1 //********************************************************************************************
2 //*
3 //* This file is part of Egoboo.
4 //*
5 //* Egoboo is free software: you can redistribute it and/or modify it
6 //* under the terms of the GNU General Public License as published by
7 //* the Free Software Foundation, either version 3 of the License, or
8 //* (at your option) any later version.
9 //*
10 //* Egoboo is distributed in the hope that it will be useful, but
11 //* WITHOUT ANY WARRANTY; without even the implied warranty of
12 //* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 //* General Public License for more details.
14 //*
15 //* You should have received a copy of the GNU General Public License
16 //* along with Egoboo. If not, see <http://www.gnu.org/licenses/>.
17 //*
18 //********************************************************************************************
19
20 /// @file menu.c
21 /// @brief Implements the main menu tree, using the code in Ui.*
22 /// @details
23
24 #include "menu.h"
25
26 #include "particle.inl"
27 #include "mad.h"
28 #include "char.inl"
29 #include "profile.inl"
30
31 #include "game.h"
32 #include "quest.h"
33
34 #include "controls_file.h"
35 #include "scancode_file.h"
36 #include "ui.h"
37 #include "log.h"
38 #include "link.h"
39 #include "game.h"
40 #include "texture.h"
41 #include "module_file.h"
42
43 // To allow changing settings
44 #include "sound.h"
45 #include "input.h"
46 #include "camera.h"
47 #include "graphic.h"
48
49 #include "egoboo_math.h"
50 #include "egoboo_vfs.h"
51 #include "egoboo_typedef.h"
52 #include "egoboo_fileutil.h"
53 #include "egoboo_setup.h"
54 #include "egoboo_strutil.h"
55
56 #include "egoboo.h"
57
58 #include "SDL_extensions.h"
59
60 //--------------------------------------------------------------------------------------------
61 //--------------------------------------------------------------------------------------------
62
63 /// The possible states of the menu state machine
64 enum e_menu_states
65 {
66 MM_Begin,
67 MM_Entering,
68 MM_Running,
69 MM_Leaving,
70 MM_Finish
71 };
72
73 #define MENU_STACK_COUNT 256
74 #define MAXWIDGET 100
75 #define MENU_MAX_GAMETIPS 100
76
77 //--------------------------------------------------------------------------------------------
78 //--------------------------------------------------------------------------------------------
79 // "Slidy" buttons used in some of the menus. They're shiny.
80 struct s_SlidyButtonState
81 {
82 char **buttons;
83 float lerp;
84 int top;
85 int left;
86 };
87 typedef struct s_SlidyButtonState mnu_SlidyButtonState_t;
88
89 //--------------------------------------------------------------------------------------------
90 //--------------------------------------------------------------------------------------------
91
92 /// the data to display a chosen player in the load player menu
93 struct s_ChoosePlayer_element
94 {
95 CAP_REF cap_ref; ///< the character profile reference from "data.txt"
96 TX_REF tx_ref; ///< the index of the icon texture
97 int skin_ref; ///< the index of the object skin from "skin.txt"
98 chop_definition_t chop; ///< the chop data from "naming.txt". put this here so we can generate a name without loading an entire profile
99 };
100 typedef struct s_ChoosePlayer_element ChoosePlayer_element_t;
101
102 ChoosePlayer_element_t * ChoosePlayer_ctor( ChoosePlayer_element_t * ptr );
103 ChoosePlayer_element_t * ChoosePlayer_dtor( ChoosePlayer_element_t * ptr );
104
105 bool_t ChoosePlayer_init( ChoosePlayer_element_t * ptr );
106 bool_t ChoosePlayer_dealloc( ChoosePlayer_element_t * ptr );
107
108 //--------------------------------------------------------------------------------------------
109
110 /// The data that menu.c uses to store the users' choice of players
111 struct s_ChoosePlayer_list
112 {
113 int count; ///< the profiles that have been loaded
114 ChoosePlayer_element_t lst[MAXIMPORTPERPLAYER + 1]; ///< the profile data
115 };
116 typedef struct s_ChoosePlayer_list ChoosePlayer_list_t;
117
118 ChoosePlayer_list_t * ChoosePlayer_list_dealloc( ChoosePlayer_list_t * );
119
120 //--------------------------------------------------------------------------------------------
121 //--------------------------------------------------------------------------------------------
122
123 /// the module data that the menu system needs
124 struct s_mnu_module
125 {
126 EGO_PROFILE_STUFF ///< the "base class" of a profile obbject
127
128 mod_file_t base; ///< the data for the "base class" of the module
129
130 // extended data
131 TX_REF tex_index; ///< the index of the module's tile image
132
133 STRING vfs_path; ///< the virtual pathname of the module
134 STRING dest_path; ///< the path that module data can be written into
135 };
136 typedef struct s_mnu_module mnu_module_t;
137
138 #define VALID_MOD_RANGE( IMOD ) ( ((IMOD) >= 0) && ((IMOD) < MAX_MODULE) )
139 #define VALID_MOD( IMOD ) ( VALID_MOD_RANGE( IMOD ) && IMOD < mnu_ModList.count && mnu_ModList.lst[IMOD].loaded )
140 #define INVALID_MOD( IMOD ) ( !VALID_MOD_RANGE( IMOD ) || IMOD >= mnu_ModList.count || !mnu_ModList.lst[IMOD].loaded )
141
142 INSTANTIATE_STACK_STATIC( mnu_module_t, mnu_ModList, MAX_MODULE );
143
144 //--------------------------------------------------------------------------------------------
145 //--------------------------------------------------------------------------------------------
146
147 /// The data that menu.c uses to store the users' choice of players
148 struct s_GameTips
149 {
150 //These are loaded only once
151 Uint8 count; //< Number of global tips loaded
152 STRING hint[MENU_MAX_GAMETIPS]; //< The global hints/tips
153
154 //These are loaded for every module
155 Uint8 local_count; //< Number of module specific tips loaded
156 STRING local_hint[MENU_MAX_GAMETIPS]; //< Module specific hints and tips
157 };
158 typedef struct s_GameTips GameTips_t;
159
160 //--------------------------------------------------------------------------------------------
161 //--------------------------------------------------------------------------------------------
162 struct s_SelectedPlayer_element
163 {
164 Uint32 input;
165 int player;
166 };
167 typedef struct s_SelectedPlayer_element SelectedPlayer_element_t;
168
169 egoboo_rv SelectedPlayer_element_init( SelectedPlayer_element_t * ptr );
170
171 //--------------------------------------------------------------------------------------------
172 struct s_SelectedPlayer_list
173 {
174 int count;
175 SelectedPlayer_element_t lst[MAX_PLAYER];
176 };
177 typedef struct s_SelectedPlayer_list SelectedPlayer_list_t;
178
179 #define SELECTED_PLAYER_LIST_INIT { 0 }
180
181 // implementation of the SelectedPlayer_list_t
182 static egoboo_rv SelectedPlayer_list_init( SelectedPlayer_list_t * sp_lst );
183 static bool_t SelectedPlayer_list_check_loadplayer( SelectedPlayer_list_t * sp_lst, int loadplayer_idx );
184 static bool_t SelectedPlayer_list_add( SelectedPlayer_list_t * sp_lst, int loadplayer_idx );
185 static bool_t SelectedPlayer_list_remove( SelectedPlayer_list_t * sp_lst, int loadplayer_idx );
186 static bool_t SelectedPlayer_list_add_input( SelectedPlayer_list_t * sp_lst, int loadplayer_idx, Uint32 input_bits );
187 static bool_t SelectedPlayer_list_remove_input( SelectedPlayer_list_t * sp_lst, int loadplayer_idx, Uint32 input_bits );
188 static int SelectedPlayer_list_index_from_loadplayer( SelectedPlayer_list_t * sp_lst, int loadplayer_idx );
189
190 //--------------------------------------------------------------------------------------------
191 // declaration of "private" variables
192 //--------------------------------------------------------------------------------------------
193
194 static int mnu_stack_index = 0;
195 static which_menu_t mnu_stack[MENU_STACK_COUNT];
196
197 static which_menu_t mnu_whichMenu = emnu_Main;
198
199 static module_filter_t mnu_moduleFilter = FILTER_OFF;
200
201 static ui_Widget_t mnu_widgetList[MAXWIDGET];
202
203 static int selectedModule = -1;
204
205 /* Copyright text variables. Change these to change how the copyright text appears */
206 static const char * copyrightText = "Welcome to Egoboo!\nhttp://egoboo.sourceforge.net\nVersion " VERSION "\n";
207 static int copyrightLeft = 0;
208 static int copyrightTop = 0;
209
210 /* Options info text variables. Change these to change how the options text appears */
211 static const char * tipText = "Put a tip in this box";
212 static int tipTextLeft = 0;
213 static int tipTextTop = 0;
214
215 /* Button position for the "easy" menus, like the main one */
216 static int buttonLeft = 0;
217 static int buttonTop = 0;
218
219 static menu_process_t _mproc;
220
221 static GameTips_t mnu_GameTip = { 0 };
222
223 static mnu_SlidyButtonState_t mnu_SlidyButtonState = { NULL };
224
225 static SelectedPlayer_list_t mnu_SelectedList = SELECTED_PLAYER_LIST_INIT;
226
227 //--------------------------------------------------------------------------------------------
228 // declaration of public variables
229 //--------------------------------------------------------------------------------------------
230
231 #define TITLE_TEXTURE_COUNT MAX_MODULE
232 #define INVALID_TITLE_TEXTURE TITLE_TEXTURE_COUNT
233
234 INSTANTIATE_STACK_STATIC( oglx_texture_t, TxTitleImage, TITLE_TEXTURE_COUNT ); // OpenGL title image surfaces
235
236 menu_process_t * MProc = &_mproc;
237 bool_t start_new_player = bfalse;
238 bool_t module_list_valid = bfalse;
239
240 /* The font used for drawing text. It's smaller than the button font */
241 Font *menuFont = NULL;
242
243 bool_t mnu_draw_background = btrue;
244
245 LoadPlayer_list_t mnu_loadplayer = LOADPLAYER_LIST_INIT;
246
247 //--------------------------------------------------------------------------------------------
248 // "private" function prototypes
249 //--------------------------------------------------------------------------------------------
250
251 // Implementation of the mnu_stack
252 static bool_t mnu_stack_push( which_menu_t menu );
253 static which_menu_t mnu_stack_pop();
254 static which_menu_t mnu_stack_peek();
255 static void mnu_stack_clear();
256
257 // Implementation of the mnu_SlidyButton array
258 static void mnu_SlidyButton_init( float lerp, const char *button_text[] );
259 static void mnu_SlidyButton_update_all( float deltaTime );
260 static void mnu_SlidyButton_draw_all();
261
262 // implementation of "private" TxTitleImage functions
263 static void TxTitleImage_clear_data();
264 static void TxTitleImage_release_one( const TX_REF index );
265 static void TxTitleImage_ctor();
266 static void TxTitleImage_release_all();
267 static void TxTitleImage_dtor();
268 static oglx_texture_t * TxTitleImage_get_ptr( const TX_REF itex );
269
270 // tipText functions
271 static void tipText_set_position( Font * font, const char * text, int spacing );
272
273 // copyrightText functions
274 static void copyrightText_set_position( Font * font, const char * text, int spacing );
275
276 // implementation of "private" ModList functions
277 static void mnu_ModList_release_images();
278 void mnu_ModList_release_all();
279
280 // "process" management
281 static int do_menu_proc_begin( menu_process_t * mproc );
282 static int do_menu_proc_running( menu_process_t * mproc );
283 static int do_menu_proc_leaving( menu_process_t * mproc );
284
285 // the hint system
286 static void mnu_GameTip_load_global_vfs();
287 static bool_t mnu_GameTip_load_local_vfs();
288
289 // "private" module utility
290 static void mnu_load_all_module_info();
291
292 // "private" asset function
293 static TX_REF mnu_get_icon_ref( const CAP_REF icap, const TX_REF default_ref );
294
295 // implementation of the autoformatting
296 static void autoformat_init_slidy_buttons();
297 static void autoformat_init_tip_text();
298 static void autoformat_init_copyright_text();
299
300 // misc other stuff
301 static void mnu_release_one_module( const MOD_REF imod );
302 static void mnu_load_all_module_images_vfs( LoadPlayer_list_t * lp_lst );
303 static egoboo_rv mnu_set_local_import_list( Import_list_t * imp_lst, SelectedPlayer_list_t * sp_lst );
304 static egoboo_rv mnu_set_selected_list( LoadPlayer_list_t * dst, LoadPlayer_list_t * src, SelectedPlayer_list_t * sp_lst );
305 static egoboo_rv mnu_copy_local_imports( Import_list_t * imp_lst );
306
307 //--------------------------------------------------------------------------------------------
308 // implementation of the menu stack
309 //--------------------------------------------------------------------------------------------
mnu_stack_push(which_menu_t menu)310 bool_t mnu_stack_push( which_menu_t menu )
311 {
312 mnu_stack_index = CLIP( mnu_stack_index, 0, MENU_STACK_COUNT ) ;
313
314 if ( mnu_stack_index >= MENU_STACK_COUNT ) return bfalse;
315
316 mnu_stack[mnu_stack_index] = menu;
317 mnu_stack_index++;
318
319 return btrue;
320 }
321
322 //--------------------------------------------------------------------------------------------
mnu_stack_pop()323 which_menu_t mnu_stack_pop()
324 {
325 if ( mnu_stack_index < 0 )
326 {
327 mnu_stack_index = 0;
328 return emnu_Main;
329 }
330 if ( mnu_stack_index > MENU_STACK_COUNT )
331 {
332 mnu_stack_index = MENU_STACK_COUNT;
333 }
334
335 if ( 0 == mnu_stack_index ) return emnu_Main;
336
337 mnu_stack_index--;
338 return mnu_stack[mnu_stack_index];
339 }
340
341 //--------------------------------------------------------------------------------------------
mnu_stack_peek()342 which_menu_t mnu_stack_peek()
343 {
344 which_menu_t return_menu = emnu_Main;
345
346 if ( mnu_stack_index > 0 )
347 {
348 return_menu = mnu_stack[mnu_stack_index-1];
349 }
350
351 return return_menu;
352 }
353
354 //--------------------------------------------------------------------------------------------
mnu_stack_clear()355 void mnu_stack_clear()
356 {
357 mnu_stack_index = 0;
358 mnu_stack[0] = emnu_Main;
359 }
360
361 //--------------------------------------------------------------------------------------------
362 // The implementation of the menu process
363 //--------------------------------------------------------------------------------------------
do_menu_proc_begin(menu_process_t * mproc)364 int do_menu_proc_begin( menu_process_t * mproc )
365 {
366 // reset the fps counter
367 menu_fps_clock = 0;
368 menu_fps_loops = 0;
369
370 stabilized_menu_fps = TARGET_FPS;
371 stabilized_menu_fps_sum = 0.1f * TARGET_FPS;
372 stabilized_menu_fps_weight = 0.1f;
373
374 // play some music
375 sound_play_song( MENU_SONG, 0, -1 );
376
377 // initialize all these structures
378 menu_system_begin(); // start the menu menu
379
380 // load all module info at menu initialization
381 // this will not change unless a new module is downloaded for a network menu?
382 mnu_load_all_module_info();
383
384 // initialize the process state
385 mproc->base.valid = btrue;
386
387 return 1;
388 }
389
390 //--------------------------------------------------------------------------------------------
do_menu_proc_running(menu_process_t * mproc)391 int do_menu_proc_running( menu_process_t * mproc )
392 {
393 int menuResult;
394
395 if ( !process_validate( PROC_PBASE( mproc ) ) ) return -1;
396
397 mproc->was_active = mproc->base.valid;
398
399 if ( mproc->base.paused ) return 0;
400
401 // play the menu music
402 mnu_draw_background = !process_running( PROC_PBASE( GProc ) );
403 menuResult = game_do_menu( mproc );
404
405 switch ( menuResult )
406 {
407 case MENU_SELECT:
408 // go ahead and start the game
409 process_pause( PROC_PBASE( mproc ) );
410 break;
411
412 case MENU_QUIT:
413 // the user selected "quit"
414 process_kill( PROC_PBASE( mproc ) );
415 break;
416 }
417
418 if ( mnu_get_menu_depth() <= GProc->menu_depth )
419 {
420 GProc->menu_depth = -1;
421 GProc->escape_latch = bfalse;
422
423 // We have exited the menu and restarted the game
424 GProc->mod_paused = bfalse;
425 process_pause( PROC_PBASE( MProc ) );
426 }
427
428 return 0;
429 }
430
431 //--------------------------------------------------------------------------------------------
do_menu_proc_leaving(menu_process_t * mproc)432 int do_menu_proc_leaving( menu_process_t * mproc )
433 {
434 if ( !process_validate( PROC_PBASE( mproc ) ) ) return -1;
435
436 // terminate the menu system
437 menu_system_end();
438
439 // finish the menu song
440 sound_finish_song( 500 );
441
442 // reset the fps counter
443 menu_fps_clock = 0;
444 menu_fps_loops = 0;
445
446 stabilized_menu_fps = TARGET_FPS;
447 stabilized_menu_fps_sum = 0.1f * TARGET_FPS;
448 stabilized_menu_fps_weight = 0.1f;
449
450 return 1;
451 }
452
453 //--------------------------------------------------------------------------------------------
do_menu_proc_run(menu_process_t * mproc,double frameDuration)454 int do_menu_proc_run( menu_process_t * mproc, double frameDuration )
455 {
456 int result = 0, proc_result = 0;
457
458 if ( !process_validate( PROC_PBASE( mproc ) ) ) return -1;
459 mproc->base.dtime = frameDuration;
460
461 if ( mproc->base.paused ) return 0;
462
463 if ( mproc->base.killme )
464 {
465 mproc->base.state = proc_leaving;
466 }
467
468 switch ( mproc->base.state )
469 {
470 case proc_begin:
471 proc_result = do_menu_proc_begin( mproc );
472
473 if ( 1 == proc_result )
474 {
475 mproc->base.state = proc_entering;
476 }
477 break;
478
479 case proc_entering:
480 // proc_result = do_menu_proc_entering( mproc );
481
482 mproc->base.state = proc_running;
483 break;
484
485 case proc_running:
486 proc_result = do_menu_proc_running( mproc );
487
488 if ( 1 == proc_result )
489 {
490 mproc->base.state = proc_leaving;
491 }
492 break;
493
494 case proc_leaving:
495 proc_result = do_menu_proc_leaving( mproc );
496
497 if ( 1 == proc_result )
498 {
499 mproc->base.state = proc_finish;
500 mproc->base.killme = bfalse;
501 }
502 break;
503
504 case proc_finish:
505 process_terminate( PROC_PBASE( mproc ) );
506 break;
507
508 default:
509 case proc_invalid:
510 break;
511 }
512
513 return result;
514 }
515
516 //--------------------------------------------------------------------------------------------
menu_process_init(menu_process_t * mproc)517 menu_process_t * menu_process_init( menu_process_t * mproc )
518 {
519 if ( NULL == mproc ) return NULL;
520
521 memset( mproc, 0, sizeof( *mproc ) );
522
523 process_init( PROC_PBASE( mproc ) );
524
525 return mproc;
526 }
527
528 //--------------------------------------------------------------------------------------------
529 // Code for global initialization/deinitialization of the menu system
530 //--------------------------------------------------------------------------------------------
menu_system_begin()531 int menu_system_begin()
532 {
533 // initializes the menu system
534 //
535 // Loads resources for the menus, and figures out where things should
536 // be positioned. If we ever allow changing resolution on the fly, this
537 // function will have to be updated/called more than once.
538
539 autoformat_init( &gfx );
540
541 menuFont = ui_loadFont( vfs_resolveReadFilename( "mp_data/Bo_Chen.ttf" ), 18 );
542 if ( NULL == menuFont )
543 {
544 log_error( "Could not load the menu font! (\"mp_data/Bo_Chen.ttf\")\n" );
545 return 0;
546 }
547
548 // Figure out where to draw the copyright text
549 copyrightText_set_position( menuFont, copyrightText, 20 );
550
551 // Figure out where to draw the options text
552 tipText_set_position( menuFont, tipText, 20 );
553
554 // construct the TxTitleImage array
555 TxTitleImage_ctor();
556
557 // Load game hints
558 mnu_GameTip_load_global_vfs();
559
560 return 1;
561 }
562
563 //--------------------------------------------------------------------------------------------
menu_system_end()564 void menu_system_end()
565 {
566 // initializes the menu system
567 //
568 // Loads resources for the menus, and figures out where things should
569 // be positioned. If we ever allow changing resolution on the fly, this
570 // function will have to be updated/called more than once.
571
572 // if this has not been done before yet, do it now
573 LoadPlayer_list_dealloc( &mnu_loadplayer );
574
575 if ( NULL != menuFont )
576 {
577 fnt_freeFont( menuFont );
578 menuFont = NULL;
579 }
580
581 // destruct the TxTitleImage array
582 TxTitleImage_dtor();
583 }
584
585 //--------------------------------------------------------------------------------------------
586 // Interface for starting and stopping menus
587 //--------------------------------------------------------------------------------------------
mnu_begin_menu(which_menu_t which)588 bool_t mnu_begin_menu( which_menu_t which )
589 {
590 if ( !mnu_stack_push( mnu_whichMenu ) ) return bfalse;
591 mnu_whichMenu = which;
592
593 return btrue;
594 }
595
596 //--------------------------------------------------------------------------------------------
mnu_end_menu()597 void mnu_end_menu()
598 {
599 mnu_whichMenu = mnu_stack_pop();
600 }
601
602 //--------------------------------------------------------------------------------------------
mnu_get_menu_depth()603 int mnu_get_menu_depth()
604 {
605 return mnu_stack_index;
606 }
607 //--------------------------------------------------------------------------------------------
608 // Implementations of the various menus
609 //--------------------------------------------------------------------------------------------
doMainMenu(float deltaTime)610 int doMainMenu( float deltaTime )
611 {
612 static int menuState = MM_Begin;
613 static oglx_texture_t background;
614 static oglx_texture_t logo;
615
616 // static float lerp;
617 static int menuChoice = 0;
618 static SDL_Rect bg_rect, logo_rect;
619
620 /* Button labels. Defined here for consistency's sake, rather than leaving them as constants */
621 static const char *sz_buttons[] =
622 {
623 "New Game",
624 "Load Game",
625 "Options",
626 "Quit",
627 ""
628 };
629
630 float fminw = 1, fminh = 1, fmin = 1;
631 int result = 0;
632
633 switch ( menuState )
634 {
635 case MM_Begin:
636
637 menuChoice = 0;
638 menuState = MM_Entering;
639
640 //Special xmas theme
641 if ( check_time( SEASON_CHRISTMAS ) )
642 {
643 // load the menu image
644 ego_texture_load_vfs( &background, "mp_data/menu/menu_xmas", INVALID_KEY );
645
646 // load the logo image
647 ego_texture_load_vfs( &logo, "mp_data/menu/snowy_logo", INVALID_KEY );
648 }
649
650 //Special Halloween theme
651 else if ( check_time( SEASON_HALLOWEEN ) )
652 {
653 // load the menu image
654 ego_texture_load_vfs( &background, "mp_data/menu/menu_halloween", INVALID_KEY );
655
656 // load the logo image
657 ego_texture_load_vfs( &logo, "mp_data/menu/creepy_logo", INVALID_KEY );
658 }
659
660 //Default egoboo theme
661 else
662 {
663 // load the menu image
664 ego_texture_load_vfs( &background, "mp_data/menu/menu_main", INVALID_KEY );
665
666 // load the logo image
667 ego_texture_load_vfs( &logo, "mp_data/menu/menu_logo", INVALID_KEY );
668 }
669
670 // calculate the centered position of the background
671 fminw = ( float ) MIN( GFX_WIDTH , background.imgW ) / ( float ) background.imgW;
672 fminh = ( float ) MIN( GFX_HEIGHT, background.imgH ) / ( float ) background.imgW;
673 fmin = MIN( fminw, fminh );
674
675 bg_rect.w = background.imgW * fmin;
676 bg_rect.h = background.imgH * fmin;
677 bg_rect.x = ( GFX_WIDTH - bg_rect.w ) * 0.5f;
678 bg_rect.y = ( GFX_HEIGHT - bg_rect.h ) * 0.5f;
679
680 // calculate the position of the logo
681 fmin = MIN( bg_rect.w * 0.5f / logo.imgW, bg_rect.h * 0.5f / logo.imgH );
682
683 logo_rect.x = bg_rect.x;
684 logo_rect.y = bg_rect.y;
685 logo_rect.w = logo.imgW * fmin;
686 logo_rect.h = logo.imgH * fmin;
687
688 mnu_SlidyButton_init( 1.0f, sz_buttons );
689 // let this fall through into MM_Entering
690
691 case MM_Entering:
692 // do buttons sliding in animation, and background fading in
693 // background
694 GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
695
696 if ( mnu_draw_background )
697 {
698 ui_drawImage( 0, &background, bg_rect.x, bg_rect.y, bg_rect.w, bg_rect.h, NULL );
699 ui_drawImage( 0, &logo, logo_rect.x, logo_rect.y, logo_rect.w, logo_rect.h, NULL );
700 }
701
702 // "Copyright" text
703 ui_drawTextBox( menuFont, copyrightText, copyrightLeft, copyrightTop, 0, 0, 20 );
704
705 mnu_SlidyButton_draw_all();
706 mnu_SlidyButton_update_all( -deltaTime );
707
708 // Let lerp wind down relative to the time elapsed
709 if ( mnu_SlidyButtonState.lerp <= 0.0f )
710 {
711 menuState = MM_Running;
712 }
713 break;
714
715 case MM_Running:
716 // Do normal run
717 // Background
718
719 GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
720
721 if ( mnu_draw_background )
722 {
723 ui_drawImage( 0, &background, bg_rect.x, bg_rect.y, bg_rect.w, bg_rect.h, NULL );
724 ui_drawImage( 0, &logo, logo_rect.x, logo_rect.y, logo_rect.w, logo_rect.h, NULL );
725 }
726
727 // "Copyright" text
728 ui_drawTextBox( menuFont, copyrightText, copyrightLeft, copyrightTop, 0, 0, 20 );
729
730 // Buttons
731 if ( BUTTON_UP == ui_doButton( 1, sz_buttons[0], NULL, buttonLeft, buttonTop, 200, 30 ) )
732 {
733 // begin single player stuff
734 menuChoice = 1;
735 }
736 if ( BUTTON_UP == ui_doButton( 2, sz_buttons[1], NULL, buttonLeft, buttonTop + 35, 200, 30 ) )
737 {
738 // begin multi player stuff
739 menuChoice = 2;
740 }
741 if ( BUTTON_UP == ui_doButton( 3, sz_buttons[2], NULL, buttonLeft, buttonTop + 35 * 2, 200, 30 ) )
742 {
743 // go to options menu
744 menuChoice = 3;
745 }
746 if ( SDLKEYDOWN( SDLK_ESCAPE ) || BUTTON_UP == ui_doButton( 4, sz_buttons[3], NULL, buttonLeft, buttonTop + 35 * 3, 200, 30 ) )
747 {
748 // quit game
749 menuChoice = 4;
750 }
751 if ( menuChoice != 0 )
752 {
753 menuState = MM_Leaving;
754 mnu_SlidyButton_init( 0.0f, sz_buttons );
755 }
756 break;
757
758 case MM_Leaving:
759 // Do buttons sliding out and background fading
760 // Do the same stuff as in MM_Entering, but backwards
761 GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
762
763 if ( mnu_draw_background )
764 {
765 ui_drawImage( 0, &background, bg_rect.x, bg_rect.y, bg_rect.w, bg_rect.h, NULL );
766 ui_drawImage( 0, &logo, logo_rect.x, logo_rect.y, logo_rect.w, logo_rect.h, NULL );
767 }
768
769 // "Copyright" text
770 ui_drawTextBox( menuFont, copyrightText, copyrightLeft, copyrightTop, 0, 0, 20 );
771
772 // Buttons
773 mnu_SlidyButton_draw_all();
774 mnu_SlidyButton_update_all( deltaTime );
775 if ( mnu_SlidyButtonState.lerp >= 1.0f )
776 {
777 menuState = MM_Finish;
778 }
779 break;
780
781 case MM_Finish:
782 // Free the background texture; don't need to hold onto it
783 oglx_texture_Release( &background );
784 menuState = MM_Begin; // Make sure this all resets next time
785
786 // reset the ui
787 ui_Reset();
788
789 // Set the next menu to load
790 result = menuChoice;
791 break;
792 };
793
794 return result;
795 }
796
797 //--------------------------------------------------------------------------------------------
doSinglePlayerMenu(float deltaTime)798 int doSinglePlayerMenu( float deltaTime )
799 {
800 static int menuState = MM_Begin;
801 static oglx_texture_t background;
802 static int menuChoice;
803
804 static const char *sz_buttons[] =
805 {
806 "New Player",
807 "Load Saved Player",
808 "Back",
809 ""
810 };
811
812 int result = 0;
813
814 switch ( menuState )
815 {
816 case MM_Begin:
817 // Load resources for this menu
818 ego_texture_load_vfs( &background, "mp_data/menu/menu_advent", TRANSCOLOR );
819 menuChoice = 0;
820
821 menuState = MM_Entering;
822
823 mnu_SlidyButton_init( 1.0f, sz_buttons );
824
825 // Let this fall through
826
827 case MM_Entering:
828 GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
829
830 // Draw the background image
831 if ( mnu_draw_background )
832 {
833 ui_drawImage( 0, &background, GFX_WIDTH - background.imgW, 0, 0, 0, NULL );
834 }
835
836 // "Copyright" text
837 ui_drawTextBox( menuFont, copyrightText, copyrightLeft, copyrightTop, 0, 0, 20 );
838
839 mnu_SlidyButton_draw_all();
840 mnu_SlidyButton_update_all( -deltaTime );
841 if ( mnu_SlidyButtonState.lerp <= 0.0f )
842 menuState = MM_Running;
843
844 break;
845
846 case MM_Running:
847
848 // Draw the background image
849 if ( mnu_draw_background )
850 {
851 ui_drawImage( 0, &background, GFX_WIDTH - background.imgW, 0, 0, 0, NULL );
852 }
853
854 // "Copyright" text
855 ui_drawTextBox( menuFont, copyrightText, copyrightLeft, copyrightTop, 0, 0, 20 );
856
857 // Buttons
858 if ( BUTTON_UP == ui_doButton( 1, sz_buttons[0], NULL, buttonLeft, buttonTop, 200, 30 ) )
859 {
860 menuChoice = 1;
861 }
862 if ( BUTTON_UP == ui_doButton( 2, sz_buttons[1], NULL, buttonLeft, buttonTop + 35, 200, 30 ) )
863 {
864 menuChoice = 2;
865 }
866 if ( SDLKEYDOWN( SDLK_ESCAPE ) || BUTTON_UP == ui_doButton( 3, sz_buttons[2], NULL, buttonLeft, buttonTop + 35 * 2, 200, 30 ) )
867 {
868 menuChoice = 3; //back
869 }
870 if ( menuChoice != 0 )
871 {
872 menuState = MM_Leaving;
873 mnu_SlidyButton_init( 0.0f, sz_buttons );
874 }
875 break;
876
877 case MM_Leaving:
878 // Do buttons sliding out and background fading
879 // Do the same stuff as in MM_Entering, but backwards
880 GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
881
882 if ( mnu_draw_background )
883 {
884 ui_drawImage( 0, &background, GFX_WIDTH - background.imgW, 0, 0, 0, NULL );
885 }
886
887 // "Copyright" text
888 ui_drawTextBox( menuFont, copyrightText, copyrightLeft, copyrightTop, 0, 0, 20 );
889
890 mnu_SlidyButton_draw_all();
891 mnu_SlidyButton_update_all( deltaTime );
892 if ( mnu_SlidyButtonState.lerp >= 1.0f )
893 {
894 menuState = MM_Finish;
895 }
896 break;
897
898 case MM_Finish:
899 // Release the background texture
900 oglx_texture_Release( &background );
901
902 // reset the ui
903 ui_Reset();
904
905 // Set the next menu to load
906 result = menuChoice;
907
908 // And make sure that if we come back to this menu, it resets
909 // properly
910 menuState = MM_Begin;
911 }
912
913 return result;
914 }
915
916 //--------------------------------------------------------------------------------------------
917 static int cmp_mod_ref_mult = 1;
918
cmp_mod_ref(const void * vref1,const void * vref2)919 int cmp_mod_ref( const void * vref1, const void * vref2 )
920 {
921 /// @details BB@> Sort MOD REF values based on the rank of the module that they point to.
922 /// Trap all stupid values.
923
924 MOD_REF * pref1 = ( MOD_REF * )vref1;
925 MOD_REF * pref2 = ( MOD_REF * )vref2;
926
927 int retval = 0;
928
929 if ( NULL == pref1 && NULL == pref2 )
930 {
931 return 0;
932 }
933 else if ( NULL == pref1 )
934 {
935 return 1;
936 }
937 else if ( NULL == pref2 )
938 {
939 return -1;
940 }
941
942 if ( *pref1 > mnu_ModList.count && *pref2 > mnu_ModList.count )
943 {
944 return 0;
945 }
946 else if ( *pref1 > mnu_ModList.count )
947 {
948 return 1;
949 }
950 else if ( *pref2 > mnu_ModList.count )
951 {
952 return -1;
953 }
954
955 // if they are beaten, float them to the end of the list
956 retval = ( int )mnu_ModList.lst[*pref1].base.beaten - ( int )mnu_ModList.lst[*pref2].base.beaten;
957
958 if ( 0 == retval )
959 {
960 // I want to uot the "newest" == "hardest" modules at the front, but this should be opposite for
961 // beginner modules
962 retval = cmp_mod_ref_mult * strncmp( mnu_ModList.lst[*pref1].base.rank, mnu_ModList.lst[*pref2].base.rank, RANKSIZE );
963 }
964
965 if ( 0 == retval )
966 {
967 retval = strncmp( mnu_ModList.lst[*pref1].base.longname, mnu_ModList.lst[*pref2].base.longname, sizeof( STRING ) );
968 }
969
970 return retval;
971 }
972
973 //--------------------------------------------------------------------------------------------
doChooseModule(float deltaTime)974 int doChooseModule( float deltaTime )
975 {
976 /// @details Choose the module
977
978 static oglx_texture_t background;
979 static int menuState = MM_Begin;
980 static Uint8 keycooldown;
981 static char* filterText = "All Modules";
982
983 static int validModules_count;
984 static MOD_REF validModules[MAX_MODULE];
985
986 static int moduleMenuOffsetX;
987 static int moduleMenuOffsetY;
988
989 static int startIndex = 0;
990 static int int_module = -1;
991 static int ext_module = -1;
992
993 // keep a local list of the currently selected players
994 static LoadPlayer_list_t loc_selectedplayer = LOADPLAYER_LIST_INIT;
995
996 int result = 0;
997 int i, x, y;
998 MOD_REF imod;
999
1000 switch ( menuState )
1001 {
1002 case MM_Begin:
1003
1004 // copy over the selected players from mnu_SelectedList to loc_selectedplayer
1005 mnu_set_selected_list( &loc_selectedplayer, &mnu_loadplayer, &mnu_SelectedList );
1006
1007 // reload the module data, if necessary
1008 if ( !module_list_valid )
1009 {
1010 mnu_load_all_module_info();
1011 }
1012
1013 // Reload all modules, something might be unlocked
1014 mnu_load_all_module_images_vfs( &loc_selectedplayer );
1015
1016 // Reset which module we are selecting
1017 startIndex = 0;
1018 ext_module = int_module = -1;
1019
1020 // reset the global module selection index
1021 selectedModule = -1;
1022
1023 // blank out the valid modules
1024 validModules_count = 0;
1025 for ( i = 0; i < MAX_MODULE; i++ )
1026 {
1027 memset( validModules + i, 0, sizeof( MOD_REF ) );
1028 }
1029
1030 // Figure out at what offset we want to draw the module menu.
1031 moduleMenuOffsetX = ( GFX_WIDTH - 640 ) / 2;
1032 moduleMenuOffsetX = MAX( 0, moduleMenuOffsetX );
1033
1034 moduleMenuOffsetY = ( GFX_HEIGHT - 480 ) / 2;
1035 moduleMenuOffsetY = MAX( 0, moduleMenuOffsetY );
1036
1037 menuState = MM_Entering;
1038
1039 // fall through...
1040
1041 case MM_Entering:
1042 menuState = MM_Running;
1043
1044 if ( !module_list_valid )
1045 {
1046 mnu_load_all_module_info();
1047 mnu_load_all_module_images_vfs( &loc_selectedplayer );
1048 }
1049
1050 // Find the modules that we want to allow loading for. If start_new_player
1051 // is true, we want ones that don't allow imports (e.g. starter modules).
1052 // Otherwise, we want modules that allow imports
1053 validModules_count = 0;
1054 for ( imod = 0; imod < mnu_ModList.count; imod++ )
1055 {
1056 // if this module is not valid given the game options and the
1057 // selected players, skip it
1058 if ( !mnu_test_module_by_index( &loc_selectedplayer, imod, 0, NULL ) ) continue;
1059
1060 if ( start_new_player && 0 == mnu_ModList.lst[imod].base.importamount )
1061 {
1062 // starter module
1063 validModules[validModules_count] = REF_TO_INT( imod );
1064 validModules_count++;
1065 }
1066 else
1067 {
1068 if ( FILTER_OFF != mnu_moduleFilter && mnu_ModList.lst[imod].base.moduletype != mnu_moduleFilter ) continue;
1069 if ( mnu_SelectedList.count > mnu_ModList.lst[imod].base.importamount ) continue;
1070 if ( mnu_SelectedList.count < mnu_ModList.lst[imod].base.minplayers ) continue;
1071 if ( mnu_SelectedList.count > mnu_ModList.lst[imod].base.maxplayers ) continue;
1072
1073 // regular module
1074 validModules[validModules_count] = REF_TO_INT( imod );
1075 validModules_count++;
1076 }
1077 }
1078
1079 // sort the modules by difficulty. easiest to hardeest for starting a new character
1080 // hardest to easiest for loading a module
1081 cmp_mod_ref_mult = start_new_player ? 1 : -1;
1082 qsort( validModules, validModules_count, sizeof( MOD_REF ), cmp_mod_ref );
1083
1084 // load background depending on current filter
1085 if ( start_new_player )
1086 {
1087 ego_texture_load_vfs( &background, "mp_data/menu/menu_advent", TRANSCOLOR );
1088 }
1089 else switch ( mnu_moduleFilter )
1090 {
1091 case FILTER_MAIN: ego_texture_load_vfs( &background, "mp_data/menu/menu_draco", TRANSCOLOR ); break;
1092 case FILTER_SIDE: ego_texture_load_vfs( &background, "mp_data/menu/menu_sidequest", TRANSCOLOR ); break;
1093 case FILTER_TOWN: ego_texture_load_vfs( &background, "mp_data/menu/menu_town", TRANSCOLOR ); break;
1094 case FILTER_FUN: ego_texture_load_vfs( &background, "mp_data/menu/menu_funquest", TRANSCOLOR ); break;
1095
1096 default:
1097 case FILTER_OFF: ego_texture_load_vfs( &background, "mp_data/menu/menu_allquest", TRANSCOLOR ); break;
1098 }
1099
1100 // set the tip text
1101 if ( 0 == validModules_count )
1102 {
1103 tipText_set_position( menuFont, "Sorry, there are no valid games!\n Please press the \"Back\" button.", 20 );
1104 }
1105 else if ( validModules_count <= 3 )
1106 {
1107 tipText_set_position( menuFont, "Press an icon to select a game.", 20 );
1108 }
1109 else
1110 {
1111 tipText_set_position( menuFont, "Press an icon to select a game.\nUse the mouse wheel or the \"<-\" and \"->\" buttons to scroll.", 20 );
1112 }
1113
1114 // fall through for now...
1115
1116 case MM_Running:
1117 {
1118 GLXvector4f beat_tint = { 0.5f, 0.25f, 0.25f, 1.0f };
1119 GLXvector4f normal_tint = { 1.0f, 1.0f, 1.0f, 1.0f };
1120
1121 if ( !module_list_valid )
1122 {
1123 mnu_load_all_module_info();
1124 mnu_load_all_module_images_vfs( &loc_selectedplayer );
1125 }
1126
1127 // Draw the background
1128 GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
1129 x = ( GFX_WIDTH / 2 ) - ( background.imgW / 2 );
1130 y = GFX_HEIGHT - background.imgH;
1131
1132 if ( mnu_draw_background )
1133 {
1134 ui_drawImage( 0, &background, x, y, 0, 0, NULL );
1135 }
1136
1137 // use the mouse wheel to scan the modules
1138 if ( cursor_wheel_event_pending() )
1139 {
1140 if ( cursor.z > 0 )
1141 {
1142 startIndex++;
1143 }
1144 else if ( cursor.z < 0 )
1145 {
1146 startIndex--;
1147 }
1148
1149 cursor_finish_wheel_event();
1150 }
1151
1152 //Allow arrow keys to scroll as well
1153 if ( SDLKEYDOWN( SDLK_RIGHT ) )
1154 {
1155 if ( 0 == keycooldown )
1156 {
1157 startIndex++;
1158 keycooldown = 5;
1159 }
1160 }
1161 else if ( SDLKEYDOWN( SDLK_LEFT ) )
1162 {
1163 if ( 0 == keycooldown )
1164 {
1165 startIndex--;
1166 keycooldown = 5;
1167 }
1168 }
1169 else keycooldown = 0;
1170 if ( keycooldown > 0 ) keycooldown--;
1171
1172 // Draw the arrows to pick modules
1173 if ( validModules_count > 3 )
1174 {
1175 if ( BUTTON_UP == ui_doButton( 1051, "<-", NULL, moduleMenuOffsetX + 20, moduleMenuOffsetY + 74, 30, 30 ) )
1176 {
1177 startIndex--;
1178 }
1179 if ( BUTTON_UP == ui_doButton( 1052, "->", NULL, moduleMenuOffsetX + 590, moduleMenuOffsetY + 74, 30, 30 ) )
1180 {
1181 startIndex++;
1182 }
1183 }
1184
1185 // restrict the range to valid values
1186 startIndex = CLIP( startIndex, 0, validModules_count - 3 );
1187
1188 // Draw buttons for the modules that can be selected
1189 x = 93;
1190 y = 20;
1191 for ( i = startIndex; i < MIN( startIndex + 3, validModules_count ); i++ )
1192 {
1193 // fix the menu images in case one or more of them are undefined
1194 MOD_REF imod = validModules[i];
1195 TX_REF tex_offset = mnu_ModList.lst[imod].tex_index;
1196 oglx_texture_t * ptex = TxTitleImage_get_ptr( tex_offset );
1197
1198 GLfloat * img_tint = normal_tint;
1199
1200 if ( mnu_ModList.lst[imod].base.beaten )
1201 {
1202 img_tint = beat_tint;
1203 }
1204
1205 if ( ui_doImageButton( i, ptex, moduleMenuOffsetX + x, moduleMenuOffsetY + y, 138, 138, img_tint ) )
1206 {
1207 int_module = i;
1208 ext_module = (( int_module < 0 ) || ( int_module > validModules_count ) ) ? -1 : validModules[int_module];
1209 }
1210
1211 //Draw a text over the image explaining what it means
1212 if ( mnu_ModList.lst[imod].base.beaten )
1213 {
1214 ui_drawTextBox( NULL, "BEATEN", moduleMenuOffsetX + x + 32, moduleMenuOffsetY + y + 64, 64, 30, 20 );
1215 }
1216
1217 x += 138 + 20; // Width of the button, and the spacing between buttons
1218 }
1219
1220 // Draw an empty button as the backdrop for the module text
1221 ui_drawButton( UI_Nothing, moduleMenuOffsetX + 21, moduleMenuOffsetY + 173, 291, 250, NULL );
1222
1223 // Draw the text description of the selected module
1224 if ( ext_module > -1 && ext_module < mnu_ModList.count )
1225 {
1226 char buffer[1024] = EMPTY_CSTR;
1227 const char * rank_string, * name_string;
1228 char * carat = buffer, * carat_end = buffer + SDL_arraysize( buffer );
1229
1230 mod_file_t * pmod = &( mnu_ModList.lst[ext_module].base );
1231
1232 GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
1233
1234 name_string = "Unnamed";
1235 if ( CSTR_END != pmod->longname[0] )
1236 {
1237 name_string = pmod->longname;
1238 }
1239 carat += snprintf( carat, carat_end - carat - 1, "%s\n", name_string );
1240
1241 rank_string = "Unranked";
1242 if ( CSTR_END != pmod->rank[0] )
1243 {
1244 rank_string = pmod->rank;
1245 }
1246 carat += snprintf( carat, carat_end - carat - 1, "Difficulty: %s\n", rank_string );
1247
1248 if ( pmod->maxplayers > 1 )
1249 {
1250 if ( pmod->minplayers == pmod->maxplayers )
1251 {
1252 carat += snprintf( carat, carat_end - carat - 1, "%d Players\n", pmod->minplayers );
1253 }
1254 else
1255 {
1256 carat += snprintf( carat, carat_end - carat - 1, "%d - %d Players\n", pmod->minplayers, pmod->maxplayers );
1257 }
1258 }
1259 else
1260 {
1261 if ( 0 != pmod->importamount )
1262 {
1263 carat += snprintf( carat, carat_end - carat - 1, "Single Player\n" );
1264 }
1265 else
1266 {
1267 carat += snprintf( carat, carat_end - carat - 1, "Starter Module\n" );
1268 }
1269 }
1270 carat += snprintf( carat, carat_end - carat - 1, " \n" );
1271
1272 for ( i = 0; i < SUMMARYLINES; i++ )
1273 {
1274 carat += snprintf( carat, carat_end - carat - 1, "%s\n", pmod->summary[i] );
1275 }
1276
1277 // Draw a text box
1278 ui_drawTextBox( menuFont, buffer, moduleMenuOffsetX + 21, moduleMenuOffsetY + 173, 291, 230, 20 );
1279 }
1280
1281 // And draw the next & back buttons
1282 if ( ext_module > -1 )
1283 {
1284 if ( SDLKEYDOWN( SDLK_RETURN ) || BUTTON_UP == ui_doButton( 53, "Select Module", NULL, moduleMenuOffsetX + 327, moduleMenuOffsetY + 173, 200, 30 ) )
1285 {
1286 // go to the next menu with this module selected
1287 menuState = MM_Leaving;
1288 }
1289 }
1290
1291 if ( SDLKEYDOWN( SDLK_ESCAPE ) || BUTTON_UP == ui_doButton( 54, "Back", NULL, moduleMenuOffsetX + 327, moduleMenuOffsetY + 208, 200, 30 ) )
1292 {
1293 // Signal doMenu to go back to the previous menu
1294 int_module = -1;
1295 ext_module = -1;
1296 menuState = MM_Leaving;
1297 }
1298
1299 //Do the module filter button
1300 if ( !start_new_player )
1301 {
1302 bool_t click_button;
1303
1304 // unly display the filter name
1305 ui_doButton( 55, filterText, NULL, moduleMenuOffsetX + 327, moduleMenuOffsetY + 390, 200, 30 );
1306
1307 // use the ">" button to change since we are already using arrows to indicate "spin control"-like widgets
1308 click_button = ( BUTTON_UP == ui_doButton( 56, ">", NULL, moduleMenuOffsetX + 532, moduleMenuOffsetY + 390, 30, 30 ) );
1309
1310 if ( click_button )
1311 {
1312 //Reload the modules with the new filter
1313 menuState = MM_Entering;
1314
1315 //Swap to the next filter
1316 mnu_moduleFilter = CLIP( mnu_moduleFilter, FILTER_NORMAL_BEGIN, FILTER_NORMAL_END );
1317
1318 mnu_moduleFilter = ( module_filter_t )( mnu_moduleFilter + 1 );
1319
1320 if ( mnu_moduleFilter > FILTER_NORMAL_END ) mnu_moduleFilter = FILTER_NORMAL_BEGIN;
1321
1322 switch ( mnu_moduleFilter )
1323 {
1324 case FILTER_MAIN: filterText = "Main Quest"; break;
1325 case FILTER_SIDE: filterText = "Sidequests"; break;
1326 case FILTER_TOWN: filterText = "Towns and Cities"; break;
1327 case FILTER_FUN: filterText = "Fun Modules"; break;
1328 case FILTER_STARTER: filterText = "Starter Modules"; break;
1329 default: case FILTER_OFF: filterText = "All Modules"; break;
1330 }
1331 }
1332 }
1333
1334 // the tool-tip text
1335 GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
1336 ui_drawTextBox( menuFont, tipText, tipTextLeft, tipTextTop, 0, 0, 20 );
1337 }
1338 break;
1339
1340 case MM_Leaving:
1341 menuState = MM_Finish;
1342 // fall through for now
1343
1344 case MM_Finish:
1345 oglx_texture_Release( &background );
1346
1347 pickedmodule_index = -1;
1348 pickedmodule_path[0] = CSTR_END;
1349 pickedmodule_name[0] = CSTR_END;
1350 pickedmodule_write_path[0] = CSTR_END;
1351
1352 menuState = MM_Begin;
1353 if ( -1 == ext_module )
1354 {
1355 result = -1;
1356 }
1357 else
1358 {
1359 // Save the name of the module that we've picked
1360 pickedmodule_index = ext_module;
1361
1362 strncpy( pickedmodule_path, mnu_ModList_get_vfs_path( pickedmodule_index ), SDL_arraysize( pickedmodule_path ) );
1363 strncpy( pickedmodule_name, mnu_ModList_get_name( pickedmodule_index ), SDL_arraysize( pickedmodule_name ) );
1364 strncpy( pickedmodule_write_path, mnu_ModList_get_dest_path( pickedmodule_index ), SDL_arraysize( pickedmodule_write_path ) );
1365
1366 if ( !game_choose_module( ext_module, -1 ) )
1367 {
1368 log_warning( "Tried to select an invalid module. index == %d\n", ext_module );
1369 result = -1;
1370 }
1371 else
1372 {
1373 pickedmodule_ready = btrue;
1374 result = ( PMod->importamount > 0 ) ? 1 : 2;
1375 }
1376 }
1377
1378 // just blank out the data since we do not own it
1379 LoadPlayer_list_init( &loc_selectedplayer );
1380
1381 // post the selected module
1382 selectedModule = ext_module;
1383
1384 // reset the ui
1385 ui_Reset();
1386
1387 break;
1388 }
1389
1390 return result;
1391 }
1392
1393 //--------------------------------------------------------------------------------------------
doChoosePlayer_load_profiles(LoadPlayer_element_t * loadplayer_ptr,ChoosePlayer_list_t * chooseplayer)1394 bool_t doChoosePlayer_load_profiles( LoadPlayer_element_t * loadplayer_ptr, ChoosePlayer_list_t * chooseplayer )
1395 {
1396 int i;
1397 STRING szFilename;
1398
1399 CAP_REF cap_ref;
1400 cap_t * cap_ptr = NULL;
1401
1402 ChoosePlayer_element_t * chooseplayer_ptr;
1403
1404 // free any allocated data
1405 ChoosePlayer_list_dealloc( chooseplayer );
1406
1407 if ( NULL == loadplayer_ptr ) return bfalse;
1408
1409 // grab the loadplayer_idx data
1410 if ( !LOADED_CAP( loadplayer_ptr->cap_ref ) )
1411 {
1412 return bfalse;
1413 }
1414 cap_ptr = CapStack.lst + loadplayer_ptr->cap_ref;
1415
1416 // go to the next element in the list
1417 chooseplayer_ptr = chooseplayer->lst + chooseplayer->count;
1418 chooseplayer->count++;
1419
1420 // blank out the data
1421 ChoosePlayer_ctor( chooseplayer_ptr );
1422
1423 // set the index of this object
1424 chooseplayer_ptr->cap_ref = loadplayer_ptr->cap_ref;
1425
1426 // copy the skin
1427 chooseplayer_ptr->skin_ref = loadplayer_ptr->skin_ref;
1428 chooseplayer_ptr->skin_ref = CLIP( chooseplayer_ptr->skin_ref, 0, MAX_SKIN - 1 );
1429
1430 // copy the texture reference over
1431 chooseplayer_ptr->tx_ref = loadplayer_ptr->tx_ref;
1432
1433 // copy the chop info
1434 memmove( &( chooseplayer_ptr->chop ), &( loadplayer_ptr->chop ), sizeof( chooseplayer_ptr->chop ) );
1435
1436 // make sure the book data is loaded
1437 if ( 0 == bookicon_count )
1438 {
1439 load_one_profile_vfs( "mp_data/globalobjects/book.obj", SPELLBOOK );
1440 }
1441
1442 // grab the inventory data
1443 for ( i = 0; i < MAXIMPORTOBJECTS; i++ )
1444 {
1445 int slot = i + 1;
1446
1447 snprintf( szFilename, SDL_arraysize( szFilename ), "%s/%d.obj", loadplayer_ptr->dir, i );
1448
1449 // load the profile
1450 cap_ref = load_one_character_profile_vfs( szFilename, slot, bfalse );
1451 if ( LOADED_CAP( cap_ref ) )
1452 {
1453 cap_ptr = CapStack.lst + cap_ref;
1454
1455 // go to the next element in the list
1456 chooseplayer_ptr = chooseplayer->lst + chooseplayer->count;
1457 chooseplayer->count++;
1458
1459 // sace the cap reference
1460 chooseplayer_ptr->cap_ref = cap_ref;
1461
1462 // get the skin info
1463 chooseplayer_ptr->skin_ref = cap_ptr->skin_override % MAX_SKIN;
1464 chooseplayer_ptr->skin_ref = CLIP( chooseplayer_ptr->skin_ref, 0, MAX_SKIN - 1 );
1465
1466 // load the icon of the skin
1467 snprintf( szFilename, SDL_arraysize( szFilename ), "%s/%d.obj/icon%d", loadplayer_ptr->dir, i, chooseplayer_ptr->skin_ref );
1468 chooseplayer_ptr->tx_ref = TxTexture_load_one_vfs( szFilename, ( TX_REF )INVALID_TX_TEXTURE, INVALID_KEY );
1469
1470 // load the chop info from "naming.txt"
1471 snprintf( szFilename, SDL_arraysize( szFilename ), "%s/%d.obj/naming.txt", loadplayer_ptr->dir, i );
1472 chop_load_vfs( &chop_mem, szFilename, &( chooseplayer_ptr->chop ) );
1473 }
1474 }
1475
1476 return btrue;
1477 }
1478
1479 //--------------------------------------------------------------------------------------------
doChoosePlayer_show_stats(LoadPlayer_element_t * loadplayer_ptr,int mode,const int x,const int y,const int width,const int height)1480 bool_t doChoosePlayer_show_stats( LoadPlayer_element_t * loadplayer_ptr, int mode, const int x, const int y, const int width, const int height )
1481 {
1482 int i, x1, y1;
1483
1484 static ChoosePlayer_list_t objects = { 0 };
1485
1486 if ( NULL == loadplayer_ptr ) mode = 1;
1487
1488 // handle the profile data
1489 switch ( mode )
1490 {
1491 case 0: // load new loadplayer data
1492
1493 if ( !doChoosePlayer_load_profiles( loadplayer_ptr, &objects ) )
1494 {
1495 loadplayer_ptr = NULL;
1496 }
1497 break;
1498
1499 case 1: // unload loadplayer data
1500
1501 // release all of the temporary profiles
1502 ChoosePlayer_list_dealloc( &objects );
1503
1504 loadplayer_ptr = NULL;
1505
1506 break;
1507 }
1508
1509 // do the actual display
1510 x1 = x + 25;
1511 y1 = y + 10;
1512 if ( NULL != loadplayer_ptr && objects.count > 0 )
1513 {
1514 CAP_REF icap = objects.lst[0].cap_ref;
1515
1516 if ( LOADED_CAP( icap ) )
1517 {
1518 STRING temp_string;
1519 cap_t * pcap = CapStack.lst + icap;
1520 Uint8 skin = MAX( pcap->skin_override, 0 );
1521
1522 ui_drawButton( UI_Nothing, x, y, width, height, NULL );
1523
1524 // fix class name capitalization
1525 pcap->classname[0] = toupper( pcap->classname[0] );
1526
1527 //Character level and class
1528 GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
1529 snprintf( temp_string, SDL_arraysize( temp_string ), "A level %d %s", pcap->level_override + 1, pcap->classname );
1530 ui_drawTextBox( menuFont, temp_string, x1, y1, 0, 0, 20 ); y1 += 20;
1531
1532 // Armor
1533 GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
1534 snprintf( temp_string, SDL_arraysize( temp_string ), "Wearing %s %s", pcap->skinname[skin], HAS_SOME_BITS( pcap->skindressy, 1 << skin ) ? "(Light)" : "(Heavy)" );
1535 ui_drawTextBox( menuFont, temp_string, x1, y1, 0, 0, 20 ); y1 += 30;
1536
1537 // Life and mana (can be less than maximum if not in easy mode)
1538 if ( cfg.difficulty >= GAME_NORMAL )
1539 {
1540 snprintf( temp_string, SDL_arraysize( temp_string ), "Life: %d/%d", MIN( FP8_TO_INT( pcap->life_spawn ), ( int )pcap->life_stat.val.from ), ( int )pcap->life_stat.val.from );
1541 ui_drawTextBox( menuFont, temp_string, x1, y1, 0, 0, 20 ); y1 += 20;
1542
1543 y1 = ui_drawBar( 0, x1, y1, FP8_TO_INT( pcap->life_spawn ), ( int )pcap->life_stat.val.from, pcap->lifecolor );
1544
1545 if ( pcap->mana_stat.val.from > 0 )
1546 {
1547 snprintf( temp_string, SDL_arraysize( temp_string ), "Mana: %d/%d", MIN( FP8_TO_INT( pcap->mana_spawn ), ( int )pcap->mana_stat.val.from ), ( int )pcap->mana_stat.val.from );
1548 ui_drawTextBox( menuFont, temp_string, x1, y1, 0, 0, 20 ); y1 += 20;
1549
1550 y1 = ui_drawBar( 0, x1, y1, FP8_TO_INT( pcap->mana_spawn ), ( int )pcap->mana_stat.val.from, pcap->manacolor );
1551 }
1552 }
1553 else
1554 {
1555 snprintf( temp_string, SDL_arraysize( temp_string ), "Life: %d", ( int )pcap->life_stat.val.from );
1556 ui_drawTextBox( menuFont, temp_string, x1, y1, 0, 0, 20 ); y1 += 20;
1557
1558 y1 = ui_drawBar( 0, x1, y1, ( int )pcap->life_stat.val.from, ( int )pcap->life_stat.val.from, pcap->lifecolor );
1559
1560 if ( pcap->mana_stat.val.from > 0 )
1561 {
1562 snprintf( temp_string, SDL_arraysize( temp_string ), "Mana: %d", ( int )pcap->mana_stat.val.from );
1563 ui_drawTextBox( menuFont, temp_string, x1, y1, 0, 0, 20 ); y1 += 20;
1564
1565 y1 = ui_drawBar( 0, x1, y1, ( int )pcap->mana_stat.val.from, ( int )pcap->mana_stat.val.from, pcap->manacolor );
1566 }
1567 }
1568 y1 += 10;
1569
1570 //SWID
1571 ui_drawTextBox( menuFont, "Stats", x1, y1, 0, 0, 20 ); y1 += 20;
1572
1573 snprintf( temp_string, SDL_arraysize( temp_string ), " Str: %s (%d)", describe_value( pcap->strength_stat.val.from, 60, NULL ), ( int )pcap->strength_stat.val.from );
1574 ui_drawTextBox( menuFont, temp_string, x1, y1, 0, 0, 20 ); y1 += 20;
1575
1576 snprintf( temp_string, SDL_arraysize( temp_string ), " Wis: %s (%d)", describe_value( pcap->wisdom_stat.val.from, 60, NULL ), ( int )pcap->wisdom_stat.val.from );
1577 ui_drawTextBox( menuFont, temp_string, x1, y1, 0, 0, 20 ); y1 += 20;
1578
1579 snprintf( temp_string, SDL_arraysize( temp_string ), " Int: %s (%d)", describe_value( pcap->intelligence_stat.val.from, 60, NULL ), ( int )pcap->intelligence_stat.val.from );
1580 ui_drawTextBox( menuFont, temp_string, x1, y1, 0, 0, 20 ); y1 += 20;
1581
1582 snprintf( temp_string, SDL_arraysize( temp_string ), " Dex: %s (%d)", describe_value( pcap->dexterity_stat.val.from, 60, NULL ), ( int )pcap->dexterity_stat.val.from );
1583 ui_drawTextBox( menuFont, temp_string, x1, y1, 0, 0, 20 ); y1 += 30;
1584
1585 //Inventory
1586 if ( objects.count > 1 )
1587 {
1588 ChoosePlayer_element_t * chooseplayer_ptr;
1589
1590 ui_drawTextBox( menuFont, "Inventory", x1, y1, 0, 0, 20 ); y1 += 20;
1591
1592 for ( i = 1; i < objects.count; i++ )
1593 {
1594 chooseplayer_ptr = objects.lst + i;
1595
1596 icap = chooseplayer_ptr->cap_ref;
1597 if ( LOADED_CAP( icap ) )
1598 {
1599 TX_REF icon_ref;
1600 cap_t * pcap = CapStack.lst + icap;
1601
1602 STRING itemname;
1603 if ( pcap->nameknown ) strncpy( itemname, chop_create( &chop_mem, &( chooseplayer_ptr->chop ) ), SDL_arraysize( itemname ) );
1604 else strncpy( itemname, pcap->classname, SDL_arraysize( itemname ) );
1605
1606 //draw the icon for this item
1607 icon_ref = mnu_get_icon_ref( icap, chooseplayer_ptr->tx_ref );
1608 ui_drawImage( 0, TxTexture_get_ptr( icon_ref ), x1, y1, 32, 32, NULL );
1609
1610 if ( icap == SLOT_LEFT + 1 )
1611 {
1612 snprintf( temp_string, SDL_arraysize( temp_string ), " Left: %s", itemname );
1613 ui_drawTextBox( menuFont, temp_string, x1 + 32, y1 + 6, 0, 0, 20 ); y1 += 32;
1614 }
1615 else if ( icap == SLOT_RIGHT + 1 )
1616 {
1617 snprintf( temp_string, SDL_arraysize( temp_string ), " Right: %s", itemname );
1618 ui_drawTextBox( menuFont, temp_string, x1 + 32, y1 + 6, 0, 0, 20 ); y1 += 32;
1619 }
1620 else
1621 {
1622 snprintf( temp_string, SDL_arraysize( temp_string ), " Item: %s", itemname );
1623 ui_drawTextBox( menuFont, temp_string, x1 + 32, y1 + 6, 0, 0, 20 ); y1 += 32;
1624 }
1625 }
1626 }
1627 }
1628 }
1629 }
1630
1631 return btrue;
1632 }
1633
1634 //--------------------------------------------------------------------------------------------
doChoosePlayer(float deltaTime)1635 int doChoosePlayer( float deltaTime )
1636 {
1637 const int x0 = 20, y0 = 20, icon_size = 42, text_width = 175, button_repeat = 47;
1638
1639 static int menuState = MM_Begin;
1640 static oglx_texture_t background;
1641 static int startIndex = 0;
1642 static int last_player = -1;
1643 static bool_t new_player = bfalse;
1644 static int numVertical, numHorizontal;
1645 static Uint32 BitsInput[4];
1646 static bool_t device_on[4];
1647 static const char * button_text[] = { "N/A", "Back", ""};
1648
1649 int result = 0;
1650 int i, j, x, y;
1651
1652 switch ( menuState )
1653 {
1654 case MM_Begin:
1655 TxTexture_free_one(( TX_REF )TX_BARS );
1656
1657 SelectedPlayer_list_init( &mnu_SelectedList );
1658
1659 TxTexture_load_one_vfs( "mp_data/nullicon", ( TX_REF )ICON_NULL, INVALID_KEY );
1660
1661 TxTexture_load_one_vfs( "mp_data/keybicon", ( TX_REF )ICON_KEYB, INVALID_KEY );
1662 BitsInput[0] = INPUT_BITS_KEYBOARD;
1663 device_on[0] = keyb.on;
1664
1665 TxTexture_load_one_vfs( "mp_data/mousicon", ( TX_REF )ICON_MOUS, INVALID_KEY );
1666 BitsInput[1] = INPUT_BITS_MOUSE;
1667 device_on[1] = mous.on;
1668
1669 TxTexture_load_one_vfs( "mp_data/joyaicon", ( TX_REF )ICON_JOYA, INVALID_KEY );
1670 BitsInput[2] = INPUT_BITS_JOYA;
1671 device_on[2] = joy[0].on;
1672
1673 TxTexture_load_one_vfs( "mp_data/joybicon", ( TX_REF )ICON_JOYB, INVALID_KEY );
1674 BitsInput[3] = INPUT_BITS_JOYB;
1675 device_on[3] = joy[1].on;
1676
1677 ego_texture_load_vfs( &background, "mp_data/menu/menu_sleepy", TRANSCOLOR );
1678
1679 TxTexture_load_one_vfs( "mp_data/bars", ( TX_REF )TX_BARS, INVALID_KEY );
1680
1681 // load information for all the players that could be imported
1682 LoadPlayer_list_import_all( &mnu_loadplayer, "mp_players", btrue );
1683
1684 // reset button 0, or it will mess up the menu.
1685 // must do it before mnu_SlidyButton_init()
1686 button_text[0] = "N/A";
1687
1688 mnu_SlidyButton_init( 1.0f, button_text );
1689
1690 numVertical = ( buttonTop - y0 ) / button_repeat - 1;
1691 numHorizontal = 1;
1692
1693 x = x0;
1694 y = y0;
1695 for ( i = 0; i < numVertical; i++ )
1696 {
1697 int m = i * 5;
1698
1699 ui_initWidget( mnu_widgetList + m, m, NULL, NULL, NULL, x, y, text_width, icon_size );
1700 ui_widgetAddMask( mnu_widgetList + m, UI_BITS_CLICKED );
1701
1702 for ( j = 0, m++; j < 4; j++, m++ )
1703 {
1704 ui_initWidget( mnu_widgetList + m, m, menuFont, NULL, TxTexture_get_ptr(( TX_REF )( ICON_KEYB + j ) ), x + text_width + j*icon_size, y, icon_size, icon_size );
1705 ui_widgetAddMask( mnu_widgetList + m, UI_BITS_CLICKED );
1706 };
1707
1708 y += button_repeat;
1709 };
1710
1711 if ( mnu_loadplayer.count < 10 )
1712 {
1713 tipText_set_position( menuFont, "Choose an input device to select your player(s)", 20 );
1714 }
1715 else
1716 {
1717 tipText_set_position( menuFont, "Choose an input device to select your player(s)\nUse the mouse wheel to scroll.", 20 );
1718 }
1719
1720 menuState = MM_Entering;
1721 // fall through
1722
1723 case MM_Entering:
1724
1725 /*GL_DEBUG(glColor4f)(1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
1726 mnu_SlidyButton_draw_all();
1727 mnu_SlidyButton_update_all( -deltaTime );
1728 // Let lerp wind down relative to the time elapsed
1729 if ( mnu_SlidyButtonState.lerp <= 0.0f )
1730 {
1731 menuState = MM_Running;
1732 }*/
1733
1734 // Simply fall through
1735 // menuState = MM_Running;
1736 // break;
1737
1738 case MM_Running:
1739 // Figure out how many players we can show without scrolling
1740
1741 if ( 0 == mnu_SelectedList.count )
1742 {
1743 button_text[0] = "";
1744 }
1745 else if ( 1 == mnu_SelectedList.count )
1746 {
1747 button_text[0] = "Select Player";
1748 }
1749 else
1750 {
1751 button_text[0] = "Select Players";
1752 }
1753
1754 // Draw the background
1755 x = ( GFX_WIDTH / 2 ) - ( background.imgW / 2 );
1756 y = GFX_HEIGHT - background.imgH;
1757
1758 if ( mnu_draw_background )
1759 {
1760 ui_drawImage( 0, &background, x, y, 0, 0, NULL );
1761 }
1762
1763 // use the mouse wheel to scan the characters
1764 if ( cursor_wheel_event_pending() )
1765 {
1766 if ( cursor.z > 0 )
1767 {
1768 if ( startIndex + numVertical < mnu_loadplayer.count )
1769 {
1770 startIndex++;
1771 }
1772 }
1773 else if ( cursor.z < 0 )
1774 {
1775 if ( startIndex > 0 )
1776 {
1777 startIndex--;
1778 }
1779 }
1780
1781 cursor_finish_wheel_event();
1782 }
1783
1784 // Draw the lplayer selection buttons
1785 x = x0;
1786 y = y0;
1787 for ( i = 0; i < numVertical; i++ )
1788 {
1789 int lplayer;
1790 int splayer;
1791 LoadPlayer_element_t * loadplayer_ptr = NULL;
1792 int m = i * 5;
1793
1794 lplayer = i + startIndex;
1795 if ( !VALID_LOADPLAYER_IDX( mnu_loadplayer, lplayer ) ) continue;
1796
1797 loadplayer_ptr = mnu_loadplayer.lst + lplayer;
1798 splayer = SelectedPlayer_list_index_from_loadplayer( &mnu_SelectedList, lplayer );
1799
1800 // do the character button
1801 mnu_widgetList[m].img = TxTexture_get_ptr( loadplayer_ptr->tx_ref );
1802 mnu_widgetList[m].text = loadplayer_ptr->name;
1803 if ( INVALID_PLAYER != splayer )
1804 {
1805 SET_BIT( mnu_widgetList[m].state, UI_BITS_CLICKED );
1806 }
1807 else
1808 {
1809 UNSET_BIT( mnu_widgetList[m].state, UI_BITS_CLICKED );
1810 }
1811
1812 if ( BUTTON_DOWN == ui_doWidget( mnu_widgetList + m ) )
1813 {
1814 if ( HAS_SOME_BITS( mnu_widgetList[m].state, UI_BITS_CLICKED ) && !SelectedPlayer_list_check_loadplayer( &mnu_SelectedList, lplayer ) )
1815 {
1816 // button has become cursor_clicked
1817 // SelectedPlayer_list_add( &mnu_SelectedList, lplayer);
1818 last_player = lplayer;
1819 new_player = btrue;
1820 }
1821 else if ( HAS_NO_BITS( mnu_widgetList[m].state, UI_BITS_CLICKED ) && SelectedPlayer_list_check_loadplayer( &mnu_SelectedList, lplayer ) )
1822 {
1823 // button has become unclicked
1824 if ( SelectedPlayer_list_remove( &mnu_SelectedList, lplayer ) )
1825 {
1826 last_player = -1;
1827 }
1828 }
1829 }
1830
1831 // do each of the input buttons
1832 for ( j = 0, m++; j < 4; j++, m++ )
1833 {
1834 /// @note check for devices being turned on and off each time
1835 /// technically we COULD recognize joysticks being inserted and removed while the
1836 /// game is running but we don't. I will set this up to handle such future behavior
1837 /// anyway :)
1838 switch ( j )
1839 {
1840 case INPUT_DEVICE_KEYBOARD: device_on[j] = keyb.on; break;
1841 case INPUT_DEVICE_MOUSE: device_on[j] = mous.on; break;
1842 case INPUT_DEVICE_JOY_A: device_on[j] = joy[0].on; break;
1843 case INPUT_DEVICE_JOY_B: device_on[j] = joy[1].on; break;
1844 default: device_on[j] = bfalse;
1845 }
1846
1847 // replace any not on device with a null icon
1848 if ( !device_on[j] )
1849 {
1850 mnu_widgetList[m].img = TxTexture_get_ptr(( TX_REF )ICON_NULL );
1851
1852 // draw the widget, even though it will not do anything
1853 // the menu would looks funny if odd columns missing
1854 ui_doWidget( mnu_widgetList + m );
1855 }
1856
1857 // make the button states reflect the chosen input devices
1858 if ( INVALID_PLAYER == splayer || HAS_NO_BITS( mnu_SelectedList.lst[ splayer ].input, BitsInput[j] ) )
1859 {
1860 UNSET_BIT( mnu_widgetList[m].state, UI_BITS_CLICKED );
1861 }
1862 else if ( HAS_SOME_BITS( mnu_SelectedList.lst[splayer].input, BitsInput[j] ) )
1863 {
1864 SET_BIT( mnu_widgetList[m].state, UI_BITS_CLICKED );
1865 }
1866
1867 if ( BUTTON_DOWN == ui_doWidget( mnu_widgetList + m ) )
1868 {
1869 if ( HAS_SOME_BITS( mnu_widgetList[m].state, UI_BITS_CLICKED ) )
1870 {
1871 // button has become cursor_clicked
1872 if ( INVALID_PLAYER == splayer )
1873 {
1874 if ( SelectedPlayer_list_add( &mnu_SelectedList, lplayer ) )
1875 {
1876 last_player = lplayer;
1877 new_player = btrue;
1878 }
1879 }
1880 if ( SelectedPlayer_list_add_input( &mnu_SelectedList, lplayer, BitsInput[j] ) )
1881 {
1882 last_player = lplayer;
1883 new_player = btrue;
1884 }
1885 }
1886 else if ( INVALID_PLAYER != splayer && HAS_NO_BITS( mnu_widgetList[m].state, UI_BITS_CLICKED ) )
1887 {
1888 // button has become unclicked
1889 if ( SelectedPlayer_list_remove_input( &mnu_SelectedList, lplayer, BitsInput[j] ) )
1890 {
1891 last_player = -1;
1892 }
1893 }
1894 }
1895 }
1896 }
1897
1898 // Buttons for going ahead
1899
1900 // Continue
1901 if ( 0 != mnu_SelectedList.count )
1902 {
1903 if ( SDLKEYDOWN( SDLK_RETURN ) || BUTTON_UP == ui_doButton( 100, button_text[0], NULL, buttonLeft, buttonTop, 200, 30 ) )
1904 {
1905 menuState = MM_Leaving;
1906 }
1907 }
1908
1909 // Back
1910 if ( SDLKEYDOWN( SDLK_ESCAPE ) || BUTTON_UP == ui_doButton( 101, button_text[1], NULL, buttonLeft, buttonTop + 35, 200, 30 ) )
1911 {
1912 SelectedPlayer_list_init( &mnu_SelectedList );
1913 menuState = MM_Leaving;
1914 }
1915
1916 // show the stats
1917 if ( VALID_LOADPLAYER_IDX( mnu_loadplayer, last_player ) )
1918 {
1919 LoadPlayer_element_t * loadplayer_ptr = mnu_loadplayer.lst + last_player;
1920 if ( new_player )
1921 {
1922 // load and display the new lplayer data
1923 new_player = bfalse;
1924 doChoosePlayer_show_stats( loadplayer_ptr, 0, GFX_WIDTH - 400, 10, 350, GFX_HEIGHT - 60 );
1925 }
1926 else
1927 {
1928 // just display the new lplayer data
1929 doChoosePlayer_show_stats( loadplayer_ptr, 2, GFX_WIDTH - 400, 10, 350, GFX_HEIGHT - 60 );
1930 }
1931 }
1932 else
1933 {
1934 doChoosePlayer_show_stats( NULL, 1, GFX_WIDTH - 100, 10, 100, GFX_HEIGHT - 60 );
1935 }
1936
1937 // tool-tip text
1938 ui_drawTextBox( menuFont, tipText, tipTextLeft, tipTextTop, 0, 0, 20 );
1939
1940 break;
1941
1942 case MM_Leaving:
1943 /*
1944 // Do buttons sliding out and background fading
1945 // Do the same stuff as in MM_Entering, but backwards
1946 GL_DEBUG(glColor4f)(1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
1947 // Buttons
1948 mnu_SlidyButton_draw_all();
1949 mnu_SlidyButton_update_all( deltaTime );
1950 if ( mnu_SlidyButtonState.lerp >= 1.0f )
1951 {
1952 menuState = MM_Finish;
1953 }
1954 */
1955
1956 // Simply fall through
1957 // menuState = MM_Finish;
1958 // break;
1959
1960 case MM_Finish:
1961
1962 // release all of the temporary profiles
1963 doChoosePlayer_show_stats( NULL, 1, 0, 0, 0, 0 );
1964
1965 oglx_texture_Release( &background );
1966 TxTexture_free_one(( TX_REF )TX_BARS );
1967
1968 menuState = MM_Begin;
1969 if ( 0 == mnu_SelectedList.count )
1970 {
1971 result = -1;
1972 }
1973 else
1974 {
1975 // set up the slots and the import stuff for the selected players
1976 if ( rv_success == mnu_set_local_import_list( &ImportList, &mnu_SelectedList ) )
1977 {
1978 game_copy_imports( &ImportList );
1979 }
1980 else
1981 {
1982 // erase the data in the import folder
1983 vfs_removeDirectoryAndContents( "import", VFS_TRUE );
1984 }
1985
1986 // if there are no selected players, there is no reason to keep this data
1987 if ( 0 == mnu_SelectedList.count )
1988 {
1989 LoadPlayer_list_dealloc( &mnu_loadplayer );
1990 }
1991
1992 result = 1;
1993 }
1994
1995 // reset the ui
1996 ui_Reset();
1997
1998 break;
1999 }
2000
2001 return result;
2002 }
2003
2004 //--------------------------------------------------------------------------------------------
doOptions(float deltaTime)2005 int doOptions( float deltaTime )
2006 {
2007 static int menuState = MM_Begin;
2008 static oglx_texture_t background;
2009 static int menuChoice = 0;
2010
2011 static const char *sz_buttons[] =
2012 {
2013 "Game Options",
2014 "Audio Options",
2015 "Input Controls",
2016 "Video Settings",
2017 "Back",
2018 ""
2019 };
2020
2021 int result = 0;
2022
2023 switch ( menuState )
2024 {
2025 case MM_Begin:
2026 // set up menu variables
2027 ego_texture_load_vfs( &background, "mp_data/menu/menu_gnome", TRANSCOLOR );
2028 menuChoice = 0;
2029 menuState = MM_Entering;
2030
2031 tipText_set_position( menuFont, "Change your audio, input and video\nsettings here.", 20 );
2032
2033 mnu_SlidyButton_init( 1.0f, sz_buttons );
2034 // let this fall through into MM_Entering
2035
2036 case MM_Entering:
2037 // do buttons sliding in animation, and background fading in
2038 // background
2039 GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
2040
2041 // Draw the background
2042 if ( mnu_draw_background )
2043 {
2044 ui_drawImage( 0, &background, ( GFX_WIDTH - background.imgW ), 0, 0, 0, NULL );
2045 }
2046
2047 mnu_SlidyButton_draw_all();
2048 mnu_SlidyButton_update_all( -deltaTime );
2049
2050 // Let lerp wind down relative to the time elapsed
2051 if ( mnu_SlidyButtonState.lerp <= 0.0f )
2052 {
2053 menuState = MM_Running;
2054 }
2055 break;
2056
2057 case MM_Running:
2058 // Do normal run
2059 // Background
2060 GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
2061
2062 if ( mnu_draw_background )
2063 {
2064 ui_drawImage( 0, &background, ( GFX_WIDTH - background.imgW ), 0, 0, 0, NULL );
2065 }
2066
2067 // "Options" text
2068 ui_drawTextBox( menuFont, tipText, tipTextLeft, tipTextTop, 0, 0, 20 );
2069
2070 // Buttons
2071 if ( BUTTON_UP == ui_doButton( 1, sz_buttons[0], NULL, buttonLeft, buttonTop, 200, 30 ) )
2072 {
2073 // game options
2074 menuChoice = 5;
2075 }
2076 if ( BUTTON_UP == ui_doButton( 2, sz_buttons[1], NULL, buttonLeft, buttonTop + 35, 200, 30 ) )
2077 {
2078 // audio options
2079 menuChoice = 1;
2080 }
2081 if ( BUTTON_UP == ui_doButton( 3, sz_buttons[2], NULL, buttonLeft, buttonTop + 35 * 2, 200, 30 ) )
2082 {
2083 // input options
2084 menuChoice = 2;
2085 }
2086 if ( BUTTON_UP == ui_doButton( 4, sz_buttons[3], NULL, buttonLeft, buttonTop + 35 * 3, 200, 30 ) )
2087 {
2088 // video options
2089 menuChoice = 3;
2090 }
2091 if ( SDLKEYDOWN( SDLK_ESCAPE ) || BUTTON_UP == ui_doButton( 5, sz_buttons[4], NULL, buttonLeft, buttonTop + 35 * 4, 200, 30 ) )
2092 {
2093 // back to main menu
2094 menuChoice = 4;
2095 }
2096 if ( menuChoice != 0 )
2097 {
2098 menuState = MM_Leaving;
2099 mnu_SlidyButton_init( 0.0f, sz_buttons );
2100 }
2101 break;
2102
2103 case MM_Leaving:
2104 // Do buttons sliding out and background fading
2105 // Do the same stuff as in MM_Entering, but backwards
2106 GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
2107
2108 if ( mnu_draw_background )
2109 {
2110 ui_drawImage( 0, &background, ( GFX_WIDTH - background.imgW ), 0, 0, 0, NULL );
2111 }
2112
2113 // Buttons
2114 mnu_SlidyButton_draw_all();
2115 mnu_SlidyButton_update_all( deltaTime );
2116 if ( mnu_SlidyButtonState.lerp >= 1.0f )
2117 {
2118 menuState = MM_Finish;
2119 }
2120 break;
2121
2122 case MM_Finish:
2123 // Free the background texture; don't need to hold onto it
2124 oglx_texture_Release( &background );
2125 menuState = MM_Begin; // Make sure this all resets next time
2126
2127 // reset the ui
2128 ui_Reset();
2129
2130 // Set the next menu to load
2131 result = menuChoice;
2132 break;
2133 }
2134
2135 return result;
2136 }
2137
2138 //--------------------------------------------------------------------------------------------
doInputOptions(float deltaTime)2139 int doInputOptions( float deltaTime )
2140 {
2141 static int menuState = MM_Begin;
2142 static int menuChoice = 0;
2143 static int waitingforinput = -1;
2144
2145 static STRING inputOptionsButtons[CONTROL_COMMAND_COUNT + 2];
2146
2147 Sint8 result = 0;
2148 static Sint32 player = 0;
2149
2150 Uint32 i;
2151 Sint32 idevice, iicon;
2152 device_controls_t * pdevice;
2153
2154 pdevice = NULL;
2155 if ( player >= 0 && player < input_device_count )
2156 {
2157 pdevice = controls + player;
2158 };
2159
2160 idevice = player;
2161 if ( NULL == pdevice )
2162 {
2163 idevice = -1;
2164 }
2165
2166 iicon = MIN( 4, idevice );
2167 if ( idevice < 0 )
2168 {
2169 iicon = -1;
2170 }
2171
2172 switch ( menuState )
2173 {
2174 case MM_Begin:
2175 // set up menu variables
2176 menuChoice = 0;
2177 menuState = MM_Entering;
2178 // let this fall through into MM_Entering
2179
2180 waitingforinput = -1;
2181
2182 for ( i = 0; i < CONTROL_COMMAND_COUNT; i++ )
2183 {
2184 inputOptionsButtons[i][0] = CSTR_END;
2185 }
2186 strncpy( inputOptionsButtons[i++], "Player 1", sizeof( STRING ) );
2187 strncpy( inputOptionsButtons[i++], "Save Settings", sizeof( STRING ) );
2188
2189 tipText_set_position( menuFont, "Change input settings here.", 20 );
2190
2191 // Load the global icons (keyboard, mouse, etc.)
2192 if ( !load_all_global_icons() ) log_warning( "Could not load all global icons!\n" );
2193
2194 case MM_Entering:
2195 // do buttons sliding in animation, and background fading in
2196 // background
2197 GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
2198
2199 // Fall trough
2200 menuState = MM_Running;
2201 break;
2202
2203 case MM_Running:
2204 // Do normal run
2205 // Background
2206 GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
2207 ui_drawTextBox( menuFont, "ATK_LEFT HAND", buttonLeft, GFX_HEIGHT - 470, 0, 0, 20 );
2208
2209 // Are we waiting for input?
2210 if ( SDLKEYDOWN( SDLK_ESCAPE ) ) waitingforinput = -1; // Someone pressed abort
2211
2212 // Grab the key/button input from the selected device
2213 if ( -1 != waitingforinput )
2214 {
2215 if ( NULL == pdevice || idevice < 0 || idevice >= input_device_count )
2216 {
2217 waitingforinput = -1;
2218 }
2219 else
2220 {
2221 if ( waitingforinput >= pdevice->count )
2222 {
2223 // invalid input range for this device
2224 waitingforinput = -1;
2225 }
2226 else
2227 {
2228 control_t * pcontrol;
2229 int tag;
2230
2231 // make sure to update the input
2232 input_read();
2233
2234 pcontrol = pdevice->control + waitingforinput;
2235 if ( idevice >= INPUT_DEVICE_JOY )
2236 {
2237 int ijoy = idevice - INPUT_DEVICE_JOY;
2238 if ( ijoy < MAXJOYSTICK )
2239 {
2240 for ( tag = 0; tag < scantag_count; tag++ )
2241 {
2242 if ( 0 != scantag[tag].value && ( Uint32 )scantag[tag].value == joy[ijoy].b )
2243 {
2244 pcontrol->tag = scantag[tag].value;
2245 pcontrol->is_key = bfalse;
2246 waitingforinput = -1;
2247 }
2248 }
2249
2250 for ( tag = 0; tag < scantag_count; tag++ )
2251 {
2252 if ( scantag[tag].value < SDLK_NUMLOCK && SDLKEYDOWN( scantag[tag].value ) )
2253 {
2254 pcontrol->tag = scantag[tag].value;
2255 pcontrol->is_key = btrue;
2256 waitingforinput = -1;
2257 }
2258 }
2259 }
2260 }
2261 else
2262 {
2263 switch ( idevice )
2264 {
2265 case INPUT_DEVICE_KEYBOARD:
2266 {
2267 for ( tag = 0; tag < scantag_count; tag++ )
2268 {
2269 if ( scantag[tag].value < SDLK_NUMLOCK && SDLKEYDOWN( scantag[tag].value ) )
2270 {
2271 pcontrol->tag = scantag[tag].value;
2272 pcontrol->is_key = btrue;
2273 waitingforinput = -1;
2274 }
2275 }
2276 }
2277 break;
2278
2279 case INPUT_DEVICE_MOUSE:
2280 {
2281 for ( tag = 0; tag < scantag_count; tag++ )
2282 {
2283 if ( 0 != scantag[tag].value && ( Uint32 )scantag[tag].value == mous.b )
2284 {
2285 pcontrol->tag = scantag[tag].value;
2286 pcontrol->is_key = bfalse;
2287 waitingforinput = -1;
2288 }
2289 }
2290
2291 for ( tag = 0; tag < scantag_count; tag++ )
2292 {
2293 if ( scantag[tag].value < SDLK_NUMLOCK && SDLKEYDOWN( scantag[tag].value ) )
2294 {
2295 pcontrol->tag = scantag[tag].value;
2296 pcontrol->is_key = btrue;
2297 waitingforinput = -1;
2298 }
2299 }
2300 }
2301 break;
2302 }
2303 }
2304
2305 }
2306 }
2307 }
2308 if ( NULL != pdevice && -1 == waitingforinput )
2309 {
2310 // update the control names
2311 for ( i = CONTROL_BEGIN; i <= CONTROL_END && i < pdevice->count; i++ )
2312 {
2313 const char * tag = scantag_get_string( pdevice->device, pdevice->control[i].tag, pdevice->control[i].is_key );
2314
2315 strncpy( inputOptionsButtons[i], tag, sizeof( STRING ) );
2316 }
2317 for ( /* nothing */; i <= CONTROL_END ; i++ )
2318 {
2319 inputOptionsButtons[i][0] = CSTR_END;
2320 }
2321 }
2322
2323 // Left hand
2324 if ( CSTR_END != inputOptionsButtons[CONTROL_LEFT_USE][0] )
2325 {
2326 ui_drawTextBox( menuFont, "Use:", buttonLeft, GFX_HEIGHT - 440, 0, 0, 20 );
2327 if ( BUTTON_UP == ui_doButton( 1, inputOptionsButtons[CONTROL_LEFT_USE], menuFont, buttonLeft + 100, GFX_HEIGHT - 440, 140, 30 ) )
2328 {
2329 waitingforinput = CONTROL_LEFT_USE;
2330 strncpy( inputOptionsButtons[CONTROL_LEFT_USE], "...", sizeof( STRING ) );
2331 }
2332 }
2333 if ( CSTR_END != inputOptionsButtons[CONTROL_LEFT_GET][0] )
2334 {
2335 ui_drawTextBox( menuFont, "Get/Drop:", buttonLeft, GFX_HEIGHT - 410, 0, 0, 20 );
2336 if ( BUTTON_UP == ui_doButton( 2, inputOptionsButtons[CONTROL_LEFT_GET], menuFont, buttonLeft + 100, GFX_HEIGHT - 410, 140, 30 ) )
2337 {
2338 waitingforinput = CONTROL_LEFT_GET;
2339 strncpy( inputOptionsButtons[CONTROL_LEFT_GET], "...", sizeof( STRING ) );
2340 }
2341 }
2342 if ( CSTR_END != inputOptionsButtons[CONTROL_LEFT_PACK][0] )
2343 {
2344 ui_drawTextBox( menuFont, "Inventory:", buttonLeft, GFX_HEIGHT - 380, 0, 0, 20 );
2345 if ( BUTTON_UP == ui_doButton( 3, inputOptionsButtons[CONTROL_LEFT_PACK], menuFont, buttonLeft + 100, GFX_HEIGHT - 380, 140, 30 ) )
2346 {
2347 waitingforinput = CONTROL_LEFT_PACK;
2348 strncpy( inputOptionsButtons[CONTROL_LEFT_PACK], "...", sizeof( STRING ) );
2349 }
2350 }
2351
2352 // Right hand
2353 ui_drawTextBox( menuFont, "ATK_RIGHT HAND", buttonLeft + 300, GFX_HEIGHT - 470, 0, 0, 20 );
2354 if ( CSTR_END != inputOptionsButtons[CONTROL_RIGHT_USE][0] )
2355 {
2356 ui_drawTextBox( menuFont, "Use:", buttonLeft + 300, GFX_HEIGHT - 440, 0, 0, 20 );
2357 if ( BUTTON_UP == ui_doButton( 4, inputOptionsButtons[CONTROL_RIGHT_USE], menuFont, buttonLeft + 400, GFX_HEIGHT - 440, 140, 30 ) )
2358 {
2359 waitingforinput = CONTROL_RIGHT_USE;
2360 strncpy( inputOptionsButtons[CONTROL_RIGHT_USE], "...", sizeof( STRING ) );
2361 }
2362 }
2363 if ( CSTR_END != inputOptionsButtons[CONTROL_RIGHT_GET][0] )
2364 {
2365 ui_drawTextBox( menuFont, "Get/Drop:", buttonLeft + 300, GFX_HEIGHT - 410, 0, 0, 20 );
2366 if ( BUTTON_UP == ui_doButton( 5, inputOptionsButtons[CONTROL_RIGHT_GET], menuFont, buttonLeft + 400, GFX_HEIGHT - 410, 140, 30 ) )
2367 {
2368 waitingforinput = CONTROL_RIGHT_GET;
2369 strncpy( inputOptionsButtons[CONTROL_RIGHT_GET], "...", sizeof( STRING ) );
2370 }
2371 }
2372 if ( CSTR_END != inputOptionsButtons[CONTROL_RIGHT_PACK][0] )
2373 {
2374 ui_drawTextBox( menuFont, "Inventory:", buttonLeft + 300, GFX_HEIGHT - 380, 0, 0, 20 );
2375 if ( BUTTON_UP == ui_doButton( 6, inputOptionsButtons[CONTROL_RIGHT_PACK], menuFont, buttonLeft + 400, GFX_HEIGHT - 380, 140, 30 ) )
2376 {
2377 waitingforinput = CONTROL_RIGHT_PACK;
2378 strncpy( inputOptionsButtons[CONTROL_RIGHT_PACK], "...", sizeof( STRING ) );
2379 }
2380 }
2381
2382 // Controls
2383 ui_drawTextBox( menuFont, "CONTROLS", buttonLeft, GFX_HEIGHT - 320, 0, 0, 20 );
2384 if ( CSTR_END != inputOptionsButtons[CONTROL_JUMP][0] )
2385 {
2386 ui_drawTextBox( menuFont, "Jump:", buttonLeft, GFX_HEIGHT - 290, 0, 0, 20 );
2387 if ( BUTTON_UP == ui_doButton( 7, inputOptionsButtons[CONTROL_JUMP], menuFont, buttonLeft + 100, GFX_HEIGHT - 290, 140, 30 ) )
2388 {
2389 waitingforinput = CONTROL_JUMP;
2390 strncpy( inputOptionsButtons[CONTROL_JUMP], "...", sizeof( STRING ) );
2391 }
2392 }
2393 if ( CSTR_END != inputOptionsButtons[CONTROL_UP][0] )
2394 {
2395 ui_drawTextBox( menuFont, "Up:", buttonLeft, GFX_HEIGHT - 260, 0, 0, 20 );
2396 if ( BUTTON_UP == ui_doButton( 8, inputOptionsButtons[CONTROL_UP], menuFont, buttonLeft + 100, GFX_HEIGHT - 260, 140, 30 ) )
2397 {
2398 waitingforinput = CONTROL_UP;
2399 strncpy( inputOptionsButtons[CONTROL_UP], "...", sizeof( STRING ) );
2400 }
2401 }
2402 if ( CSTR_END != inputOptionsButtons[CONTROL_DOWN][0] )
2403 {
2404 ui_drawTextBox( menuFont, "Down:", buttonLeft, GFX_HEIGHT - 230, 0, 0, 20 );
2405 if ( BUTTON_UP == ui_doButton( 9, inputOptionsButtons[CONTROL_DOWN], menuFont, buttonLeft + 100, GFX_HEIGHT - 230, 140, 30 ) )
2406 {
2407 waitingforinput = CONTROL_DOWN;
2408 strncpy( inputOptionsButtons[CONTROL_DOWN], "...", sizeof( STRING ) );
2409 }
2410 }
2411 if ( CSTR_END != inputOptionsButtons[CONTROL_LEFT][0] )
2412 {
2413 ui_drawTextBox( menuFont, "Left:", buttonLeft, GFX_HEIGHT - 200, 0, 0, 20 );
2414 if ( BUTTON_UP == ui_doButton( 10, inputOptionsButtons[CONTROL_LEFT], menuFont, buttonLeft + 100, GFX_HEIGHT - 200, 140, 30 ) )
2415 {
2416 waitingforinput = CONTROL_LEFT;
2417 strncpy( inputOptionsButtons[CONTROL_LEFT], "...", sizeof( STRING ) );
2418 }
2419 }
2420 if ( CSTR_END != inputOptionsButtons[CONTROL_RIGHT][0] )
2421 {
2422 ui_drawTextBox( menuFont, "Right:", buttonLeft, GFX_HEIGHT - 170, 0, 0, 20 );
2423 if ( BUTTON_UP == ui_doButton( 11, inputOptionsButtons[CONTROL_RIGHT], menuFont, buttonLeft + 100, GFX_HEIGHT - 170, 140, 30 ) )
2424 {
2425 waitingforinput = CONTROL_RIGHT;
2426 strncpy( inputOptionsButtons[CONTROL_RIGHT], "...", sizeof( STRING ) );
2427 }
2428 }
2429
2430 // Controls
2431 ui_drawTextBox( menuFont, "CAMERA CONTROL", buttonLeft + 300, GFX_HEIGHT - 320, 0, 0, 20 );
2432 if ( CSTR_END != inputOptionsButtons[CONTROL_CAMERA_IN][0] )
2433 {
2434 ui_drawTextBox( menuFont, "Zoom In:", buttonLeft + 300, GFX_HEIGHT - 290, 0, 0, 20 );
2435 if ( BUTTON_UP == ui_doButton( 12, inputOptionsButtons[CONTROL_CAMERA_IN], menuFont, buttonLeft + 450, GFX_HEIGHT - 290, 140, 30 ) )
2436 {
2437 waitingforinput = CONTROL_CAMERA_IN;
2438 strncpy( inputOptionsButtons[CONTROL_CAMERA_IN], "...", sizeof( STRING ) );
2439 }
2440 }
2441 else
2442 {
2443 // single button camera control
2444 ui_drawTextBox( menuFont, "Camera:", buttonLeft + 300, GFX_HEIGHT - 290, 0, 0, 20 );
2445 if ( BUTTON_UP == ui_doButton( 12, inputOptionsButtons[CONTROL_CAMERA], menuFont, buttonLeft + 450, GFX_HEIGHT - 290, 140, 30 ) )
2446 {
2447 waitingforinput = CONTROL_CAMERA;
2448 strncpy( inputOptionsButtons[CONTROL_CAMERA], "...", sizeof( STRING ) );
2449 }
2450 }
2451 if ( CSTR_END != inputOptionsButtons[CONTROL_CAMERA_OUT][0] )
2452 {
2453 ui_drawTextBox( menuFont, "Zoom Out:", buttonLeft + 300, GFX_HEIGHT - 260, 0, 0, 20 );
2454 if ( BUTTON_UP == ui_doButton( 13, inputOptionsButtons[CONTROL_CAMERA_OUT], menuFont, buttonLeft + 450, GFX_HEIGHT - 260, 140, 30 ) )
2455 {
2456 waitingforinput = CONTROL_CAMERA_OUT;
2457 strncpy( inputOptionsButtons[CONTROL_CAMERA_OUT], "...", sizeof( STRING ) );
2458 }
2459 }
2460 if ( CSTR_END != inputOptionsButtons[CONTROL_CAMERA_LEFT][0] )
2461 {
2462 ui_drawTextBox( menuFont, "Rotate Left:", buttonLeft + 300, GFX_HEIGHT - 230, 0, 0, 20 );
2463 if ( BUTTON_UP == ui_doButton( 14, inputOptionsButtons[CONTROL_CAMERA_LEFT], menuFont, buttonLeft + 450, GFX_HEIGHT - 230, 140, 30 ) )
2464 {
2465 waitingforinput = CONTROL_CAMERA_LEFT;
2466 strncpy( inputOptionsButtons[CONTROL_CAMERA_LEFT], "...", sizeof( STRING ) );
2467 }
2468 }
2469 if ( CSTR_END != inputOptionsButtons[CONTROL_CAMERA_RIGHT][0] )
2470 {
2471 ui_drawTextBox( menuFont, "Rotate Right:", buttonLeft + 300, GFX_HEIGHT - 200, 0, 0, 20 );
2472 if ( BUTTON_UP == ui_doButton( 15, inputOptionsButtons[CONTROL_CAMERA_RIGHT], menuFont, buttonLeft + 450, GFX_HEIGHT - 200, 140, 30 ) )
2473 {
2474 waitingforinput = CONTROL_CAMERA_RIGHT;
2475 strncpy( inputOptionsButtons[CONTROL_CAMERA_RIGHT], "...", sizeof( STRING ) );
2476 }
2477 }
2478
2479 // The select player button
2480 if ( iicon < 0 )
2481 {
2482 if ( BUTTON_UP == ui_doButton( 16, "Select Player...", NULL, buttonLeft + 300, GFX_HEIGHT - 90, 140, 50 ) )
2483 {
2484 player = 0;
2485 }
2486 }
2487 else if ( BUTTON_UP == ui_doImageButtonWithText( 16, TxTexture_get_ptr(( TX_REF )( ICON_KEYB + iicon ) ), inputOptionsButtons[CONTROL_COMMAND_COUNT+0], menuFont, buttonLeft + 300, GFX_HEIGHT - 90, 140, 50 ) )
2488 {
2489 if ( input_device_count > 0 )
2490 {
2491 player++;
2492 player %= input_device_count;
2493 }
2494
2495 snprintf( inputOptionsButtons[CONTROL_COMMAND_COUNT+0], sizeof( STRING ), "Player %i", player + 1 );
2496 }
2497
2498 // Save settings button
2499 if ( BUTTON_UP == ui_doButton( 17, inputOptionsButtons[CONTROL_COMMAND_COUNT+1], menuFont, buttonLeft, GFX_HEIGHT - 60, 200, 30 ) )
2500 {
2501 // save settings and go back
2502 player = 0;
2503 input_settings_save_vfs( "controls.txt" );
2504 menuState = MM_Leaving;
2505 }
2506
2507 // tool-tip text
2508 ui_drawTextBox( menuFont, tipText, tipTextLeft, tipTextTop, 0, 0, 20 );
2509
2510 break;
2511
2512 case MM_Leaving:
2513 // Do buttons sliding out and background fading
2514 // Do the same stuff as in MM_Entering, but backwards
2515 GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
2516
2517 // Fall trough
2518 menuState = MM_Finish;
2519 break;
2520
2521 case MM_Finish:
2522 menuState = MM_Begin; // Make sure this all resets next time
2523
2524 // reset the ui
2525 ui_Reset();
2526
2527 // Set the next menu to load
2528 result = 1;
2529 break;
2530 }
2531
2532 return result;
2533 }
2534
2535 //--------------------------------------------------------------------------------------------
doGameOptions(float deltaTime)2536 int doGameOptions( float deltaTime )
2537 {
2538 /// @details Game options menu
2539
2540 static int menuState = MM_Begin;
2541 static oglx_texture_t background;
2542 static int menuChoice = 0;
2543
2544 static STRING Cdifficulty;
2545 static STRING Cmaxmessage;
2546 static const char *sz_buttons[] =
2547 {
2548 "N/A", // Difficulty
2549 "N/A", // Max messages
2550 "N/A", // Message duration
2551 "N/A", // Autoturn camera
2552 "N/A", // Show FPS
2553 "N/A", // Feedback
2554 "Save Settings",
2555 ""
2556 };
2557
2558 char szDifficulty[4096] = EMPTY_CSTR;
2559 int result = 0;
2560
2561 switch ( menuState )
2562 {
2563 case MM_Begin:
2564 // set up menu variables
2565 ego_texture_load_vfs( &background, "mp_data/menu/menu_fairy", TRANSCOLOR );
2566
2567 menuChoice = 0;
2568 menuState = MM_Entering;
2569
2570 tipText_set_position( menuFont, "Change game settings here.", 20 );
2571
2572 mnu_SlidyButton_init( 1.0f, sz_buttons );
2573 // let this fall through into MM_Entering
2574
2575 case MM_Entering:
2576 // do buttons sliding in animation, and background fading in
2577 // background
2578 GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
2579
2580 // Draw the background
2581 if ( mnu_draw_background )
2582 {
2583 ui_drawImage( 0, &background, ( GFX_WIDTH / 2 ) + ( background.imgW / 2 ), GFX_HEIGHT - background.imgH, 0, 0, NULL );
2584 }
2585
2586 // Load the current settings
2587 switch ( cfg.difficulty )
2588 {
2589 case GAME_HARD: snprintf( Cdifficulty, SDL_arraysize( Cdifficulty ), "Punishing" ); break;
2590 case GAME_EASY: snprintf( Cdifficulty, SDL_arraysize( Cdifficulty ), "Forgiving" ); break;
2591 default: cfg.difficulty = GAME_NORMAL; /* fall through */
2592 case GAME_NORMAL: snprintf( Cdifficulty, SDL_arraysize( Cdifficulty ), "Challenging" ); break;
2593 }
2594 sz_buttons[0] = Cdifficulty;
2595
2596 maxmessage = CLIP( maxmessage, 4, MAX_MESSAGE );
2597 if ( 0 == maxmessage )
2598 {
2599 snprintf( Cmaxmessage, SDL_arraysize( Cmaxmessage ), "None" ); // Set to default
2600 }
2601 else
2602 {
2603 snprintf( Cmaxmessage, SDL_arraysize( Cmaxmessage ), "%i", maxmessage );
2604 }
2605 sz_buttons[1] = Cmaxmessage;
2606
2607 // Message duration
2608 if ( cfg.message_duration <= 100 )
2609 {
2610 sz_buttons[2] = "Short";
2611 }
2612 else if ( cfg.message_duration <= 150 )
2613 {
2614 sz_buttons[2] = "Normal";
2615 }
2616 else
2617 {
2618 sz_buttons[2] = "Long";
2619 }
2620
2621 // Autoturn camera
2622 if ( CAM_TURN_GOOD == cfg.autoturncamera ) sz_buttons[3] = "Fast";
2623 else if ( CAM_TURN_AUTO == cfg.autoturncamera ) sz_buttons[3] = "On";
2624 else
2625 {
2626 sz_buttons[3] = "Off";
2627 cfg.autoturncamera = CAM_TURN_NONE;
2628 }
2629
2630 // Show FPS
2631 sz_buttons[4] = cfg.fps_allowed ? "On" : "Off";
2632
2633 //Billboard feedback
2634 if ( !cfg.feedback ) sz_buttons[5] = "Disabled";
2635 else
2636 {
2637 if ( cfg.feedback == FEEDBACK_TEXT ) sz_buttons[5] = "Enabled";
2638 else sz_buttons[5] = "Debug";
2639 }
2640
2641 // Fall trough
2642 menuState = MM_Running;
2643 //break;
2644
2645 case MM_Running:
2646 // Do normal run
2647 // Background
2648 GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
2649
2650 if ( mnu_draw_background )
2651 {
2652 ui_drawImage( 0, &background, ( GFX_WIDTH / 2 ) - ( background.imgW / 2 ), GFX_HEIGHT - background.imgH, 0, 0, NULL );
2653 }
2654
2655 ui_drawTextBox( menuFont, "Game Difficulty:", buttonLeft, 50, 0, 0, 20 );
2656
2657 // Buttons
2658 if ( !PMod->active && BUTTON_UP == ui_doButton( 1, sz_buttons[0], menuFont, buttonLeft + 150, 50, 150, 30 ) )
2659 {
2660 // Increase difficulty
2661 cfg.difficulty++;
2662 switch ( cfg.difficulty )
2663 {
2664 case GAME_NORMAL: snprintf( Cdifficulty, SDL_arraysize( Cdifficulty ), "Challenging" ); break;
2665 case GAME_HARD: snprintf( Cdifficulty, SDL_arraysize( Cdifficulty ), "Punishing" ); break;
2666 default: case GAME_EASY:
2667 {
2668 snprintf( Cdifficulty, SDL_arraysize( Cdifficulty ), "Forgiving" );
2669 cfg.difficulty = GAME_EASY;
2670 break;
2671 }
2672 }
2673 sz_buttons[0] = Cdifficulty;
2674 }
2675
2676 // Now do difficulty description. Currently it's handled very bad, but it works.
2677 switch ( cfg.difficulty )
2678 {
2679 case GAME_EASY:
2680 strncpy( szDifficulty, "FORGIVING (Easy)\n - Players gain no bonus XP \n - 15%% XP loss upon death\n - Monsters take 25%% extra damage by players\n - Players take 25%% less damage by monsters\n - Halves the chance for Kursed items\n - Cannot unlock the final level in this mode\n - Life and Mana is refilled after quitting a module", SDL_arraysize( szDifficulty ) );
2681 break;
2682 case GAME_NORMAL:
2683 strncpy( szDifficulty, "CHALLENGING (Normal)\n - Players gain 10%% bonus XP \n - 15%% XP loss upon death \n - 15%% money loss upon death", SDL_arraysize( szDifficulty ) );
2684 break;
2685 case GAME_HARD:
2686 strncpy( szDifficulty, "PUNISHING (Hard)\n - Monsters award 20%% extra xp! \n - 15%% XP loss upon death\n - 15%% money loss upon death\n - No respawning\n - Channeling life can kill you\n - Players take 25%% more damage\n - Doubles the chance for Kursed items", SDL_arraysize( szDifficulty ) );
2687 break;
2688 }
2689 str_add_linebreaks( szDifficulty, SDL_arraysize( szDifficulty ), 30 );
2690 ui_drawTextBox( menuFont, szDifficulty, buttonLeft, 100, 0, 0, 20 );
2691
2692 // Text messages
2693 ui_drawTextBox( menuFont, "Max Messages:", buttonLeft + 350, 50, 0, 0, 20 );
2694 if ( BUTTON_UP == ui_doButton( 2, sz_buttons[1], menuFont, buttonLeft + 515, 50, 75, 30 ) )
2695 {
2696 cfg.message_count_req++;
2697 if ( cfg.message_count_req > MAX_MESSAGE ) cfg.message_count_req = 0;
2698 if ( cfg.message_count_req < 4 && cfg.message_count_req != 0 ) cfg.message_count_req = 4;
2699
2700 if ( 0 == cfg.message_count_req )
2701 {
2702 snprintf( Cmaxmessage, SDL_arraysize( Cmaxmessage ), "None" );
2703 }
2704 else
2705 {
2706 snprintf( Cmaxmessage, SDL_arraysize( Cmaxmessage ), "%i", cfg.message_count_req ); // Convert integer to a char we can use
2707 }
2708
2709 sz_buttons[1] = Cmaxmessage;
2710 }
2711
2712 // Message time
2713 ui_drawTextBox( menuFont, "Message Duration:", buttonLeft + 350, 100, 0, 0, 20 );
2714 if ( BUTTON_UP == ui_doButton( 3, sz_buttons[2], menuFont, buttonLeft + 515, 100, 100, 30 ) )
2715 {
2716 if ( cfg.message_duration <= 0 )
2717 {
2718 cfg.message_duration = 100;
2719 }
2720 else
2721 {
2722 cfg.message_duration += 50;
2723 }
2724
2725 if ( cfg.message_duration >= 250 )
2726 {
2727 cfg.message_duration = 100;
2728 }
2729
2730 if ( cfg.message_duration <= 100 )
2731 {
2732 sz_buttons[2] = "Short";
2733 }
2734 else if ( cfg.message_duration <= 150 )
2735 {
2736 sz_buttons[2] = "Normal";
2737 }
2738 else
2739 {
2740 sz_buttons[2] = "Long";
2741 }
2742 }
2743
2744 // Autoturn camera
2745 ui_drawTextBox( menuFont, "Autoturn Camera:", buttonLeft + 350, 150, 0, 0, 20 );
2746 if ( BUTTON_UP == ui_doButton( 4, sz_buttons[3], menuFont, buttonLeft + 515, 150, 100, 30 ) )
2747 {
2748 if ( CAM_TURN_GOOD == cfg.autoturncamera )
2749 {
2750 sz_buttons[3] = "Off";
2751 cfg.autoturncamera = CAM_TURN_NONE;
2752 }
2753 else if ( cfg.autoturncamera )
2754 {
2755 sz_buttons[3] = "Fast";
2756 cfg.autoturncamera = CAM_TURN_GOOD;
2757 }
2758 else
2759 {
2760 sz_buttons[3] = "On";
2761 cfg.autoturncamera = CAM_TURN_AUTO;
2762 }
2763 }
2764
2765 // Show the fps?
2766 ui_drawTextBox( menuFont, "Display FPS:", buttonLeft + 350, 200, 0, 0, 20 );
2767 if ( BUTTON_UP == ui_doButton( 5, sz_buttons[4], menuFont, buttonLeft + 515, 200, 100, 30 ) )
2768 {
2769 cfg.fps_allowed = !cfg.fps_allowed;
2770 if ( cfg.fps_allowed ) sz_buttons[4] = "On";
2771 else sz_buttons[4] = "Off";
2772 }
2773
2774 // Feedback
2775 ui_drawTextBox( menuFont, "Floating Text:", buttonLeft + 350, 250, 0, 0, 20 );
2776 if ( BUTTON_UP == ui_doButton( 6, sz_buttons[5], menuFont, buttonLeft + 515, 250, 75, 30 ) )
2777 {
2778 if ( cfg.dev_mode )
2779 {
2780 cfg.feedback = ( FEEDBACK_TYPE )( cfg.feedback + 1 );
2781 if ( cfg.feedback > FEEDBACK_NUMBER ) cfg.feedback = FEEDBACK_OFF;
2782 }
2783 else
2784 {
2785 if ( FEEDBACK_OFF == cfg.feedback )
2786 {
2787 cfg.feedback = FEEDBACK_TEXT;
2788 }
2789 else
2790 {
2791 cfg.feedback = FEEDBACK_OFF;
2792 }
2793 }
2794
2795 switch ( cfg.feedback )
2796 {
2797 case FEEDBACK_OFF: sz_buttons[5] = "Disabled"; break;
2798 case FEEDBACK_TEXT: sz_buttons[5] = "Enabled"; break;
2799 case FEEDBACK_NUMBER: sz_buttons[5] = "Debug"; break;
2800 }
2801 }
2802
2803 // Save settings
2804 if ( BUTTON_UP == ui_doButton( 7, sz_buttons[6], menuFont, buttonLeft, GFX_HEIGHT - 60, 200, 30 ) )
2805 {
2806 // synchronoze the config values with the various game subsystems
2807 setup_synch( &cfg );
2808
2809 // save the setup file
2810 setup_upload( &cfg );
2811 setup_write();
2812
2813 menuState = MM_Leaving;
2814 }
2815
2816 // tool-tip text
2817 ui_drawTextBox( menuFont, tipText, tipTextLeft, tipTextTop, 0, 0, 20 );
2818 break;
2819
2820 case MM_Leaving:
2821 // Do buttons sliding out and background fading
2822 // Do the same stuff as in MM_Entering, but backwards
2823 GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
2824
2825 if ( mnu_draw_background )
2826 {
2827 ui_drawImage( 0, &background, ( GFX_WIDTH / 2 ) + ( background.imgW / 2 ), GFX_HEIGHT - background.imgH, 0, 0, NULL );
2828 }
2829
2830 // Fall trough
2831 menuState = MM_Finish;
2832 break;
2833
2834 case MM_Finish:
2835 // Free the background texture; don't need to hold onto it
2836 oglx_texture_Release( &background );
2837 menuState = MM_Begin; // Make sure this all resets next time
2838
2839 // reset the ui
2840 ui_Reset();
2841
2842 // Set the next menu to load
2843 result = 1;
2844 break;
2845 }
2846
2847 return result;
2848 }
2849
2850 //--------------------------------------------------------------------------------------------
doAudioOptions(float deltaTime)2851 int doAudioOptions( float deltaTime )
2852 {
2853 /// @details Audio options menu
2854
2855 static int menuState = MM_Begin;
2856 static oglx_texture_t background;
2857 static int menuChoice = 0;
2858 static STRING Cmaxsoundchannel;
2859 static STRING Cbuffersize;
2860 static STRING Csoundvolume;
2861 static STRING Cmusicvolume;
2862 static const char *sz_buttons[] =
2863 {
2864 "N/A", // Enable sound
2865 "N/A", // Sound volume
2866 "N/A", // Enable music
2867 "N/A", // Music volume
2868 "N/A", // Sound channels
2869 "N/A", // Sound buffer
2870 "N/A", // Sound quality
2871 "N/A", // Play footsteps
2872 "Save Settings",
2873 ""
2874 };
2875
2876 int result = 0;
2877
2878 switch ( menuState )
2879 {
2880 case MM_Begin:
2881 // set up menu variables
2882 ego_texture_load_vfs( &background, "mp_data/menu/menu_sound", TRANSCOLOR );
2883
2884 menuChoice = 0;
2885 menuState = MM_Entering;
2886
2887 tipText_set_position( menuFont, "Change audio settings here.", 20 );
2888
2889 mnu_SlidyButton_init( 1.0f, sz_buttons );
2890 // let this fall through into MM_Entering
2891
2892 case MM_Entering:
2893 // do buttons sliding in animation, and background fading in
2894 // background
2895 GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
2896
2897 // Draw the background
2898 if ( mnu_draw_background )
2899 {
2900 ui_drawImage( 0, &background, ( GFX_WIDTH - background.imgW ), 0, 0, 0, NULL );
2901 }
2902
2903 // Load the current settings
2904 sz_buttons[0] = cfg.sound_allowed ? "On" : "Off";
2905
2906 snprintf( Csoundvolume, SDL_arraysize( Csoundvolume ), "%i", cfg.sound_volume );
2907 sz_buttons[1] = Csoundvolume;
2908
2909 sz_buttons[2] = cfg.music_allowed ? "On" : "Off";
2910
2911 snprintf( Cmusicvolume, SDL_arraysize( Cmusicvolume ), "%i", cfg.music_volume );
2912 sz_buttons[3] = Cmusicvolume;
2913
2914 snprintf( Cmaxsoundchannel, SDL_arraysize( Cmaxsoundchannel ), "%i", cfg.sound_channel_count );
2915 sz_buttons[4] = Cmaxsoundchannel;
2916
2917 snprintf( Cbuffersize, SDL_arraysize( Cbuffersize ), "%i", cfg.sound_buffer_size );
2918 sz_buttons[5] = Cbuffersize;
2919
2920 sz_buttons[6] = cfg.sound_highquality ? "Normal" : "High";
2921
2922 sz_buttons[7] = cfg.sound_footfall ? "Enabled" : "Disabled";
2923
2924 // Fall trough
2925 menuState = MM_Running;
2926 break;
2927
2928 case MM_Running:
2929 // Do normal run
2930 // Background
2931 GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
2932
2933 if ( mnu_draw_background )
2934 {
2935 ui_drawImage( 0, &background, ( GFX_WIDTH - background.imgW ), 0, 0, 0, NULL );
2936 }
2937
2938 ui_drawTextBox( menuFont, "Sound:", buttonLeft, GFX_HEIGHT - 270, 0, 0, 20 );
2939
2940 // Buttons
2941 if ( BUTTON_UP == ui_doButton( 1, sz_buttons[0], menuFont, buttonLeft + 150, GFX_HEIGHT - 270, 100, 30 ) )
2942 {
2943 cfg.sound_allowed = !cfg.sound_allowed;
2944 sz_buttons[0] = cfg.sound_allowed ? "On" : "Off";
2945 }
2946
2947 ui_drawTextBox( menuFont, "Sound Volume:", buttonLeft, GFX_HEIGHT - 235, 0, 0, 20 );
2948 if ( BUTTON_UP == ui_doButton( 2, sz_buttons[1], menuFont, buttonLeft + 150, GFX_HEIGHT - 235, 100, 30 ) )
2949 {
2950 cfg.sound_volume += 5;
2951 if ( cfg.sound_volume > 100 ) cfg.sound_volume = 0;
2952
2953 snprintf( Csoundvolume, SDL_arraysize( Csoundvolume ), "%i", cfg.sound_volume );
2954 sz_buttons[1] = Csoundvolume;
2955 }
2956
2957 ui_drawTextBox( menuFont, "Music:", buttonLeft, GFX_HEIGHT - 165, 0, 0, 20 );
2958 if ( BUTTON_UP == ui_doButton( 3, sz_buttons[2], menuFont, buttonLeft + 150, GFX_HEIGHT - 165, 100, 30 ) )
2959 {
2960 cfg.music_allowed = !cfg.music_allowed;
2961 sz_buttons[2] = cfg.music_allowed ? "On" : "Off";
2962 }
2963
2964 ui_drawTextBox( menuFont, "Music Volume:", buttonLeft, GFX_HEIGHT - 130, 0, 0, 20 );
2965 if ( BUTTON_UP == ui_doButton( 4, sz_buttons[3], menuFont, buttonLeft + 150, GFX_HEIGHT - 130, 100, 30 ) )
2966 {
2967 cfg.music_volume += 5;
2968 if ( cfg.music_volume > 100 ) cfg.music_volume = 0;
2969
2970 snprintf( Cmusicvolume, SDL_arraysize( Cmusicvolume ), "%i", cfg.music_volume );
2971 sz_buttons[3] = Cmusicvolume;
2972 }
2973
2974 ui_drawTextBox( menuFont, "Sound Channels:", buttonLeft + 300, GFX_HEIGHT - 200, 0, 0, 20 );
2975 if ( BUTTON_UP == ui_doButton( 5, sz_buttons[4], menuFont, buttonLeft + 450, GFX_HEIGHT - 200, 100, 30 ) )
2976 {
2977 if ( cfg.sound_channel_count < 8 )
2978 {
2979 cfg.sound_channel_count = 8;
2980 }
2981 else
2982 {
2983 cfg.sound_channel_count <<= 1;
2984 }
2985
2986 if ( cfg.sound_channel_count > 128 )
2987 {
2988 cfg.sound_channel_count = 8;
2989 }
2990
2991 snprintf( Cmaxsoundchannel, SDL_arraysize( Cmaxsoundchannel ), "%i", cfg.sound_channel_count );
2992 sz_buttons[4] = Cmaxsoundchannel;
2993 }
2994
2995 ui_drawTextBox( menuFont, "Buffer Size:", buttonLeft + 300, GFX_HEIGHT - 165, 0, 0, 20 );
2996 if ( BUTTON_UP == ui_doButton( 6, sz_buttons[5], menuFont, buttonLeft + 450, GFX_HEIGHT - 165, 100, 30 ) )
2997 {
2998 if ( cfg.sound_buffer_size < 512 )
2999 {
3000 cfg.sound_buffer_size = 512;
3001 }
3002 else
3003 {
3004 cfg.sound_buffer_size <<= 1;
3005 }
3006
3007 if ( cfg.sound_buffer_size > 8196 )
3008 {
3009 cfg.sound_buffer_size = 512;
3010 }
3011
3012 snprintf( Cbuffersize, SDL_arraysize( Cbuffersize ), "%i", cfg.sound_buffer_size );
3013 sz_buttons[5] = Cbuffersize;
3014 }
3015
3016 ui_drawTextBox( menuFont, "Sound Quality:", buttonLeft + 300, GFX_HEIGHT - 130, 0, 0, 20 );
3017 if ( BUTTON_UP == ui_doButton( 7, sz_buttons[6], menuFont, buttonLeft + 450, GFX_HEIGHT - 130, 100, 30 ) )
3018 {
3019 cfg.sound_highquality = !cfg.sound_highquality;
3020 sz_buttons[6] = cfg.sound_highquality ? "Normal" : "High";
3021 }
3022
3023 //Footfall sounds
3024 ui_drawTextBox( menuFont, "Footstep Sounds:", buttonLeft + 300, GFX_HEIGHT - 235, 0, 0, 20 );
3025 if ( BUTTON_UP == ui_doButton( 8, sz_buttons[7], menuFont, buttonLeft + 450, GFX_HEIGHT - 235, 100, 30 ) )
3026 {
3027 cfg.sound_footfall = !cfg.sound_footfall;
3028 sz_buttons[7] = cfg.sound_footfall ? "Enabled" : "Disabled";
3029 }
3030
3031 //Save settings
3032 if ( BUTTON_UP == ui_doButton( 9, sz_buttons[8], menuFont, buttonLeft, GFX_HEIGHT - 60, 200, 30 ) )
3033 {
3034 // synchronoze the config values with the various game subsystems
3035 setup_synch( &cfg );
3036
3037 // save the setup file
3038 setup_upload( &cfg );
3039 setup_write();
3040
3041 // Reload the sound system
3042 sound_restart();
3043
3044 // Do we restart the music?
3045 if ( cfg.music_allowed )
3046 {
3047 load_all_music_sounds_vfs();
3048 fade_in_music( musictracksloaded[songplaying] );
3049 }
3050
3051 menuState = MM_Leaving;
3052 }
3053
3054 // tool-tip text
3055 ui_drawTextBox( menuFont, tipText, tipTextLeft, tipTextTop, 0, 0, 20 );
3056
3057 break;
3058
3059 case MM_Leaving:
3060 // Do buttons sliding out and background fading
3061 // Do the same stuff as in MM_Entering, but backwards
3062 GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
3063
3064 if ( mnu_draw_background )
3065 {
3066 ui_drawImage( 0, &background, ( GFX_WIDTH - background.imgW ), 0, 0, 0, NULL );
3067 }
3068
3069 // Fall trough
3070 menuState = MM_Finish;
3071 break;
3072
3073 case MM_Finish:
3074 // Free the background texture; don't need to hold onto it
3075 oglx_texture_Release( &background );
3076 menuState = MM_Begin; // Make sure this all resets next time
3077
3078 // reset the ui
3079 ui_Reset();
3080
3081 // Set the next menu to load
3082 result = 1;
3083 break;
3084 }
3085
3086 return result;
3087 }
3088
3089 //--------------------------------------------------------------------------------------------
doVideoOptions_coerce_aspect_ratio(int width,int height,float * pratio,STRING * psz_ratio)3090 bool_t doVideoOptions_coerce_aspect_ratio( int width, int height, float * pratio, STRING * psz_ratio )
3091 {
3092 /// @details BB@> coerce the aspect ratio of the screen to some standard size
3093
3094 float req_aspect_ratio;
3095
3096 if ( 0 == height || NULL == pratio || NULL == psz_ratio ) return bfalse;
3097
3098 req_aspect_ratio = ( float )width / ( float )height;
3099
3100 if ( req_aspect_ratio > 0.0f && req_aspect_ratio < 0.5f*(( 5.0f / 4.0f ) + ( 4.0f / 3.0f ) ) )
3101 {
3102 *pratio = 5.0f / 4.0f;
3103 strncpy( *psz_ratio, "5:4", sizeof( *psz_ratio ) );
3104 }
3105 else if ( req_aspect_ratio >= 0.5f*(( 5.0f / 4.0f ) + ( 4.0f / 3.0f ) ) && req_aspect_ratio < 0.5f*(( 4.0f / 3.0f ) + ( 8.0f / 5.0f ) ) )
3106 {
3107 *pratio = 4.0f / 3.0f;
3108 strncpy( *psz_ratio, "4:3", sizeof( *psz_ratio ) );
3109 }
3110 else if ( req_aspect_ratio >= 0.5f*(( 4.0f / 3.0f ) + ( 8.0f / 5.0f ) ) && req_aspect_ratio < 0.5f*(( 8.0f / 5.0f ) + ( 5.0f / 3.0f ) ) )
3111 {
3112 *pratio = 8.0f / 5.0f;
3113 strncpy( *psz_ratio, "8:5", sizeof( *psz_ratio ) );
3114 }
3115 else if ( req_aspect_ratio >= 0.5f*(( 8.0f / 5.0f ) + ( 5.0f / 3.0f ) ) && req_aspect_ratio < 0.5f*(( 5.0f / 3.0f ) + ( 16.0f / 9.0f ) ) )
3116 {
3117 *pratio = 5.0f / 3.0f;
3118 strncpy( *psz_ratio, "5:3", sizeof( *psz_ratio ) );
3119 }
3120 else
3121 {
3122 *pratio = 16.0f / 9.0f;
3123 strncpy( *psz_ratio, "16:9", sizeof( *psz_ratio ) );
3124 }
3125
3126 return btrue;
3127
3128 }
3129
3130 //--------------------------------------------------------------------------------------------
doVideoOptions_fix_fullscreen_resolution(egoboo_config_t * pcfg,SDLX_screen_info_t * psdl_scr,STRING * psz_screen_size)3131 int doVideoOptions_fix_fullscreen_resolution( egoboo_config_t * pcfg, SDLX_screen_info_t * psdl_scr, STRING * psz_screen_size )
3132 {
3133 STRING sz_aspect_ratio = "unknown";
3134 float req_screen_area = ( float )pcfg->scrx_req * ( float )pcfg->scry_req;
3135 float min_diff = 0.0f;
3136 SDL_Rect * found_rect = NULL, ** pprect = NULL;
3137
3138 float aspect_ratio;
3139
3140 doVideoOptions_coerce_aspect_ratio( pcfg->scrx_req, pcfg->scry_req, &aspect_ratio, &sz_aspect_ratio );
3141
3142 found_rect = NULL;
3143 pprect = psdl_scr->video_mode_list;
3144 while ( NULL != *pprect )
3145 {
3146 SDL_Rect * prect = *pprect;
3147
3148 float sdl_aspect_ratio;
3149 float sdl_screen_area;
3150 float diff, diff1, diff2;
3151
3152 sdl_aspect_ratio = ( float )prect->w / ( float )prect->h;
3153 sdl_screen_area = prect->w * prect->h;
3154
3155 diff1 = LOG( sdl_aspect_ratio / aspect_ratio );
3156 diff2 = LOG( sdl_screen_area / req_screen_area );
3157
3158 diff = 2.0f * ABS( diff1 ) + ABS( diff2 );
3159
3160 if ( NULL == found_rect || diff < min_diff )
3161 {
3162 found_rect = prect;
3163 min_diff = diff;
3164
3165 if ( 0.0f == min_diff ) break;
3166 }
3167
3168 pprect++;
3169 }
3170
3171 if ( NULL != found_rect )
3172 {
3173 pcfg->scrx_req = found_rect->w;
3174 pcfg->scry_req = found_rect->h;
3175 }
3176 else
3177 {
3178 // we cannot find an approximate screen size
3179
3180 switch ( pcfg->scrx_req )
3181 {
3182 // Normal resolutions
3183 case 1024:
3184 pcfg->scry_req = 768;
3185 strncpy( sz_aspect_ratio, "4:3", sizeof( sz_aspect_ratio ) );
3186 break;
3187
3188 case 640:
3189 pcfg->scry_req = 480;
3190 strncpy( sz_aspect_ratio, "4:3", sizeof( sz_aspect_ratio ) );
3191 break;
3192
3193 case 800:
3194 pcfg->scry_req = 600;
3195 strncpy( sz_aspect_ratio, "4:3", sizeof( sz_aspect_ratio ) );
3196 break;
3197
3198 // 1280 can be both widescreen and normal
3199 case 1280:
3200 if ( pcfg->scry_req > 800 )
3201 {
3202 pcfg->scry_req = 1024;
3203 strncpy( sz_aspect_ratio, "5:4", sizeof( sz_aspect_ratio ) );
3204 }
3205 else
3206 {
3207 pcfg->scry_req = 800;
3208 strncpy( sz_aspect_ratio, "8:5", sizeof( sz_aspect_ratio ) );
3209 }
3210 break;
3211
3212 // Widescreen resolutions
3213 case 1440:
3214 pcfg->scry_req = 900;
3215 strncpy( sz_aspect_ratio, "8:5", sizeof( sz_aspect_ratio ) );
3216 break;
3217
3218 case 1680:
3219 pcfg->scry_req = 1050;
3220 strncpy( sz_aspect_ratio, "8:5", sizeof( sz_aspect_ratio ) );
3221 break;
3222
3223 case 1920:
3224 pcfg->scry_req = 1200;
3225 strncpy( sz_aspect_ratio, "8:5", sizeof( sz_aspect_ratio ) );
3226 break;
3227
3228 // unknown
3229 default:
3230 doVideoOptions_coerce_aspect_ratio( pcfg->scrx_req, pcfg->scry_req, &aspect_ratio, &sz_aspect_ratio );
3231 break;
3232 }
3233 }
3234
3235 snprintf( *psz_screen_size, sizeof( *psz_screen_size ), "%dx%d - %s", pcfg->scrx_req, pcfg->scry_req, sz_aspect_ratio );
3236
3237 return btrue;
3238 }
3239
3240 //--------------------------------------------------------------------------------------------
doVideoOptions(float deltaTime)3241 int doVideoOptions( float deltaTime )
3242 {
3243 /// @details Video options menu
3244
3245 enum
3246 {
3247 but_antialiasing = 0, // Antialaising
3248 but_unused , // Unused button
3249 but_dither , // Fast & ugly
3250 but_fullscreen , // Fullscreen
3251 but_reflections , // Reflections
3252 but_filtering , // Texture filtering
3253 but_shadow , // Shadows
3254 but_zbuffer , // Z bit
3255 but_maxlights , // Fog
3256 but_3dfx , // 3D effects
3257 but_multiwater , // Multi water layer
3258 but_widescreen , // Widescreen
3259 but_screensize , // Screen resolution
3260 but_save ,
3261 but_maxparticles , // Max particles
3262 but_end,
3263
3264 but_last
3265 };
3266
3267 static int menuState = MM_Begin;
3268 static oglx_texture_t background;
3269 static int menuChoice = 0;
3270 static STRING Cantialiasing;
3271 static STRING Cmaxlights;
3272 static STRING Cscrz;
3273 static STRING Cmaxparticles;
3274 static STRING Cmaxdyna;
3275
3276 static bool_t widescreen;
3277 static float aspect_ratio;
3278 static STRING sz_screen_size;
3279
3280 static const char *sz_buttons[but_last];
3281
3282 int cnt, result = 0;
3283
3284 switch ( menuState )
3285 {
3286 case MM_Begin:
3287
3288 // set up the button text
3289 for ( cnt = 0; cnt < but_last; cnt++ ) sz_buttons[cnt] = "N/A";
3290 sz_buttons[but_end] = "";
3291
3292 // set up menu variables
3293 ego_texture_load_vfs( &background, "mp_data/menu/menu_video", TRANSCOLOR );
3294
3295 menuChoice = 0;
3296 menuState = MM_Entering;
3297
3298 tipText_set_position( menuFont, "Change video settings here.", 20 );
3299
3300 mnu_SlidyButton_init( 1.0f, sz_buttons );
3301 // let this fall through into MM_Entering
3302
3303 case MM_Entering:
3304 // do buttons sliding in animation, and background fading in
3305 // background
3306 GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
3307
3308 // Draw the background
3309 if ( mnu_draw_background )
3310 {
3311 ui_drawImage( 0, &background, ( GFX_WIDTH - background.imgW ), 0, 0, 0, NULL );
3312 }
3313
3314 // Load all the current video settings
3315 if ( 0 == cfg.multisamples ) strncpy( Cantialiasing , "Off", SDL_arraysize( Cantialiasing ) );
3316 else snprintf( Cantialiasing, SDL_arraysize( Cantialiasing ), "X%i", cfg.multisamples );
3317 sz_buttons[but_antialiasing] = Cantialiasing;
3318
3319 // Texture filtering
3320 switch ( cfg.texturefilter_req )
3321 {
3322 case TX_UNFILTERED:
3323 sz_buttons[but_filtering] = "Unfiltered";
3324 break;
3325 case TX_LINEAR:
3326 sz_buttons[but_filtering] = "Linear";
3327 break;
3328 case TX_MIPMAP:
3329 sz_buttons[but_filtering] = "Mipmap";
3330 break;
3331 case TX_BILINEAR:
3332 sz_buttons[but_filtering] = "Bilinear";
3333 break;
3334 case TX_TRILINEAR_1:
3335 sz_buttons[but_filtering] = "Trilinear 1";
3336 break;
3337 case TX_TRILINEAR_2:
3338 sz_buttons[but_filtering] = "Trilinear 2";
3339 break;
3340 case TX_ANISOTROPIC:
3341 sz_buttons[but_filtering] = "Ansiotropic";
3342 break;
3343 default: // Set to defaults
3344 sz_buttons[but_filtering] = "Linear";
3345 cfg.texturefilter_req = TX_LINEAR;
3346 break;
3347 }
3348
3349 sz_buttons[but_dither] = cfg.use_dither ? "Yes" : "No";
3350
3351 sz_buttons[but_fullscreen] = cfg.fullscreen_req ? "True" : "False";
3352
3353 if ( cfg.reflect_allowed )
3354 {
3355 sz_buttons[but_reflections] = "Low";
3356 if ( cfg.reflect_prt )
3357 {
3358 sz_buttons[but_reflections] = "Medium";
3359 if ( 0 == cfg.reflect_fade )
3360 {
3361 sz_buttons[but_reflections] = "High";
3362 }
3363 }
3364 }
3365 else
3366 {
3367 sz_buttons[but_reflections] = "Off";
3368 }
3369
3370 if ( cfg.shadow_allowed )
3371 {
3372 sz_buttons[but_shadow] = "Normal";
3373 if ( !cfg.shadow_sprite )
3374 {
3375 sz_buttons[but_shadow] = "Best";
3376 }
3377 }
3378 else sz_buttons[but_shadow] = "Off";
3379
3380 #if defined(__unix__)
3381 //Clip linux defaults to valid values so that the game doesn't crash on startup
3382 if ( cfg.scrz_req == 32 ) cfg.scrz_req = 24;
3383 if ( cfg.scrd_req == 32 ) cfg.scrd_req = 24;
3384 #endif
3385
3386 if ( cfg.scrz_req != 32 && cfg.scrz_req != 16 && cfg.scrz_req != 24 )
3387 {
3388 cfg.scrz_req = 16; // Set to default
3389 }
3390 snprintf( Cscrz, SDL_arraysize( Cscrz ), "%i", cfg.scrz_req ); // Convert the integer to a char we can use
3391 sz_buttons[but_zbuffer] = Cscrz;
3392
3393 snprintf( Cmaxlights, SDL_arraysize( Cmaxlights ), "%i", cfg.dyna_count_req );
3394 sz_buttons[but_maxlights] = Cmaxlights;
3395
3396 if ( cfg.use_phong )
3397 {
3398 sz_buttons[but_3dfx] = "Okay";
3399 if ( cfg.overlay_allowed && cfg.background_allowed )
3400 {
3401 sz_buttons[but_3dfx] = "Good";
3402 if ( cfg.use_perspective )
3403 {
3404 sz_buttons[but_3dfx] = "Superb";
3405 }
3406 }
3407 else // Set to defaults
3408 {
3409 cfg.use_perspective = bfalse;
3410 cfg.background_allowed = bfalse;
3411 cfg.overlay_allowed = bfalse;
3412 sz_buttons[but_3dfx] = "Off";
3413 }
3414 }
3415 else // Set to defaults
3416 {
3417 cfg.use_perspective = bfalse;
3418 cfg.background_allowed = bfalse;
3419 cfg.overlay_allowed = bfalse;
3420 sz_buttons[but_3dfx] = "Off";
3421 }
3422
3423 if ( cfg.twolayerwater_allowed ) sz_buttons[but_multiwater] = "On";
3424 else sz_buttons[but_multiwater] = "Off";
3425
3426 snprintf( Cmaxparticles, SDL_arraysize( Cmaxparticles ), "%i", cfg.particle_count_req ); // Convert the integer to a char we can use
3427 sz_buttons[but_maxparticles] = Cmaxparticles;
3428
3429 if ( cfg.fullscreen_req && NULL != sdl_scr.video_mode_list )
3430 {
3431 doVideoOptions_fix_fullscreen_resolution( &cfg, &sdl_scr, &sz_screen_size );
3432 sz_buttons[but_screensize] = sz_screen_size;
3433
3434 aspect_ratio = ( float )cfg.scrx_req / ( float )cfg.scry_req;
3435 widescreen = ( aspect_ratio > ( 4.0f / 3.0f ) );
3436 }
3437 else
3438 {
3439 snprintf( sz_screen_size, sizeof( sz_screen_size ), "%dx%d", cfg.scrx_req, cfg.scry_req );
3440 sz_buttons[but_screensize] = sz_screen_size;
3441
3442 aspect_ratio = ( float )cfg.scrx_req / ( float )cfg.scry_req;
3443 widescreen = ( aspect_ratio > ( 4.0f / 3.0f ) );
3444 }
3445
3446 if ( widescreen ) sz_buttons[but_widescreen] = "X";
3447 else sz_buttons[but_widescreen] = " ";
3448
3449 menuState = MM_Running;
3450 break;
3451
3452 case MM_Running:
3453 // Do normal run
3454 // Background
3455 GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
3456
3457 if ( mnu_draw_background )
3458 {
3459 ui_drawImage( 0, &background, ( GFX_WIDTH - background.imgW ), 0, 0, 0, NULL );
3460 }
3461
3462 // Antialiasing Button
3463 ui_drawTextBox( menuFont, "Antialiasing:", buttonLeft, GFX_HEIGHT - 215, 0, 0, 20 );
3464 if ( BUTTON_UP == ui_doButton( 1, sz_buttons[but_antialiasing], menuFont, buttonLeft + 150, GFX_HEIGHT - 215, 100, 30 ) )
3465 {
3466 // make the multi-sampling even
3467
3468 if ( cfg.multisamples < 0 )
3469 {
3470 cfg.multisamples = 0;
3471 }
3472 else
3473 {
3474 cfg.multisamples += 1;
3475 }
3476
3477 // set some arbitrary limit
3478 if ( cfg.multisamples > 4 ) cfg.multisamples = 0;
3479
3480 if ( 0 == cfg.multisamples ) strncpy( Cantialiasing , "Off", SDL_arraysize( Cantialiasing ) );
3481 else snprintf( Cantialiasing, SDL_arraysize( Cantialiasing ), "X%i", cfg.multisamples );
3482
3483 sz_buttons[but_antialiasing] = Cantialiasing;
3484 }
3485
3486 // Dithering
3487 ui_drawTextBox( menuFont, "Dithering:", buttonLeft, GFX_HEIGHT - 145, 0, 0, 20 );
3488 if ( BUTTON_UP == ui_doButton( 3, sz_buttons[but_dither], menuFont, buttonLeft + 150, GFX_HEIGHT - 145, 100, 30 ) )
3489 {
3490 cfg.use_dither = !cfg.use_dither;
3491 sz_buttons[but_dither] = cfg.use_dither ? "Yes" : "No";
3492 }
3493
3494 // Fullscreen
3495 ui_drawTextBox( menuFont, "Fullscreen:", buttonLeft, GFX_HEIGHT - 110, 0, 0, 20 );
3496 if ( BUTTON_UP == ui_doButton( 4, sz_buttons[but_fullscreen], menuFont, buttonLeft + 150, GFX_HEIGHT - 110, 100, 30 ) )
3497 {
3498 cfg.fullscreen_req = !cfg.fullscreen_req;
3499
3500 sz_buttons[but_fullscreen] = cfg.fullscreen_req ? "True" : "False";
3501 }
3502
3503 // Reflection
3504 ui_drawTextBox( menuFont, "Reflections:", buttonLeft, GFX_HEIGHT - 250, 0, 0, 20 );
3505 if ( BUTTON_UP == ui_doButton( 5, sz_buttons[but_reflections], menuFont, buttonLeft + 150, GFX_HEIGHT - 250, 100, 30 ) )
3506 {
3507
3508 if ( cfg.reflect_allowed && 0 == cfg.reflect_fade && cfg.reflect_prt )
3509 {
3510 cfg.reflect_allowed = bfalse;
3511 cfg.reflect_fade = 255;
3512 cfg.reflect_prt = bfalse;
3513 sz_buttons[but_reflections] = "Off";
3514 }
3515 else
3516 {
3517 if ( cfg.reflect_allowed && !cfg.reflect_prt )
3518 {
3519 sz_buttons[but_reflections] = "Medium";
3520 cfg.reflect_fade = 255;
3521 cfg.reflect_prt = btrue;
3522 }
3523 else
3524 {
3525 if ( cfg.reflect_allowed && cfg.reflect_fade == 255 && cfg.reflect_prt )
3526 {
3527 sz_buttons[but_reflections] = "High";
3528 cfg.reflect_fade = 0;
3529 }
3530 else
3531 {
3532 cfg.reflect_allowed = btrue;
3533 cfg.reflect_fade = 255;
3534 sz_buttons[but_reflections] = "Low";
3535 cfg.reflect_prt = bfalse;
3536 }
3537 }
3538 }
3539 }
3540
3541 // Texture Filtering
3542 ui_drawTextBox( menuFont, "Texture Filtering:", buttonLeft, GFX_HEIGHT - 285, 0, 0, 20 );
3543 if ( BUTTON_UP == ui_doButton( 6, sz_buttons[but_filtering], menuFont, buttonLeft + 150, GFX_HEIGHT - 285, 130, 30 ) )
3544 {
3545 if ( cfg.texturefilter_req < TX_UNFILTERED )
3546 {
3547 cfg.texturefilter_req = TX_UNFILTERED;
3548 }
3549 else
3550 {
3551 cfg.texturefilter_req = ( TX_FILTERS )(( int )cfg.texturefilter_req + 1 );
3552 }
3553
3554 if ( cfg.texturefilter_req > TX_ANISOTROPIC )
3555 {
3556 cfg.texturefilter_req = TX_UNFILTERED;
3557 }
3558
3559 switch ( cfg.texturefilter_req )
3560 {
3561
3562 case TX_UNFILTERED:
3563 sz_buttons[but_filtering] = "Unfiltered";
3564 break;
3565
3566 case TX_LINEAR:
3567 sz_buttons[but_filtering] = "Linear";
3568 break;
3569
3570 case TX_MIPMAP:
3571 sz_buttons[but_filtering] = "Mipmap";
3572 break;
3573
3574 case TX_BILINEAR:
3575 sz_buttons[but_filtering] = "Bilinear";
3576 break;
3577
3578 case TX_TRILINEAR_1:
3579 sz_buttons[but_filtering] = "Trilinear 1";
3580 break;
3581
3582 case TX_TRILINEAR_2:
3583 sz_buttons[but_filtering] = "Trilinear 2";
3584 break;
3585
3586 case TX_ANISOTROPIC:
3587 sz_buttons[but_filtering] = "Anisotropic";
3588 break;
3589
3590 default:
3591 cfg.texturefilter_req = TX_UNFILTERED;
3592 sz_buttons[but_filtering] = "Unfiltered";
3593 break;
3594 }
3595 }
3596
3597 // Shadows
3598 ui_drawTextBox( menuFont, "Shadows:", buttonLeft, GFX_HEIGHT - 320, 0, 0, 20 );
3599 if ( BUTTON_UP == ui_doButton( 7, sz_buttons[but_shadow], menuFont, buttonLeft + 150, GFX_HEIGHT - 320, 100, 30 ) )
3600 {
3601 if ( cfg.shadow_allowed && !cfg.shadow_sprite )
3602 {
3603 cfg.shadow_allowed = bfalse;
3604 cfg.shadow_sprite = bfalse; // Just in case
3605 sz_buttons[but_shadow] = "Off";
3606 }
3607 else
3608 {
3609 if ( cfg.shadow_allowed && cfg.shadow_sprite )
3610 {
3611 sz_buttons[but_shadow] = "Best";
3612 cfg.shadow_sprite = bfalse;
3613 }
3614 else
3615 {
3616 cfg.shadow_allowed = btrue;
3617 cfg.shadow_sprite = btrue;
3618 sz_buttons[but_shadow] = "Normal";
3619 }
3620 }
3621 }
3622
3623 // Z bit
3624 ui_drawTextBox( menuFont, "Z Bit:", buttonLeft + 300, GFX_HEIGHT - 320, 0, 0, 20 );
3625 if ( BUTTON_UP == ui_doButton( 8, sz_buttons[but_zbuffer], menuFont, buttonLeft + 450, GFX_HEIGHT - 320, 100, 30 ) )
3626 {
3627 if ( cfg.scrz_req < 0 )
3628 {
3629 cfg.scrz_req = 8;
3630 }
3631 else
3632 {
3633 cfg.scrz_req += 8;
3634 }
3635
3636 #if defined(__unix__)
3637 if ( cfg.scrz_req > 24 ) cfg.scrz_req = 8; //Linux max is 24
3638 #else
3639 if ( cfg.scrz_req > 32 ) cfg.scrz_req = 8; //Others can have up to 32 bit!
3640 #endif
3641
3642 snprintf( Cscrz, SDL_arraysize( Cscrz ), "%d", cfg.scrz_req );
3643 sz_buttons[but_zbuffer] = Cscrz;
3644 }
3645
3646 // Max dynamic lights
3647 ui_drawTextBox( menuFont, "Max Lights:", buttonLeft + 300, GFX_HEIGHT - 285, 0, 0, 20 );
3648 if ( BUTTON_UP == ui_doButton( 9, sz_buttons[but_maxlights], menuFont, buttonLeft + 450, GFX_HEIGHT - 285, 100, 30 ) )
3649 {
3650 if ( cfg.dyna_count_req < 16 )
3651 {
3652 cfg.dyna_count_req = 16;
3653 }
3654 else
3655 {
3656 cfg.dyna_count_req += 8;
3657 }
3658
3659 if ( cfg.dyna_count_req > TOTAL_MAX_DYNA )
3660 {
3661 cfg.dyna_count_req = 8;
3662 }
3663
3664 snprintf( Cmaxdyna, SDL_arraysize( Cmaxdyna ), "%d", cfg.dyna_count_req );
3665 sz_buttons[but_maxlights] = Cmaxdyna;
3666 }
3667
3668 // Perspective correction, overlay, underlay and phong mapping
3669 ui_drawTextBox( menuFont, "Special Effects:", buttonLeft + 300, GFX_HEIGHT - 250, 0, 0, 20 );
3670 if ( BUTTON_UP == ui_doButton( 10, sz_buttons[but_3dfx], menuFont, buttonLeft + 450, GFX_HEIGHT - 250, 100, 30 ) )
3671 {
3672 if ( cfg.use_phong && cfg.use_perspective && cfg.overlay_allowed && cfg.background_allowed )
3673 {
3674 cfg.use_phong = bfalse;
3675 cfg.use_perspective = bfalse;
3676 cfg.overlay_allowed = bfalse;
3677 cfg.background_allowed = bfalse;
3678 sz_buttons[but_3dfx] = "Off";
3679 }
3680 else
3681 {
3682 if ( !cfg.use_phong )
3683 {
3684 sz_buttons[but_3dfx] = "Okay";
3685 cfg.use_phong = btrue;
3686 }
3687 else
3688 {
3689 if ( !cfg.use_perspective && cfg.overlay_allowed && cfg.background_allowed )
3690 {
3691 sz_buttons[but_3dfx] = "Superb";
3692 cfg.use_perspective = btrue;
3693 }
3694 else
3695 {
3696 cfg.overlay_allowed = btrue;
3697 cfg.background_allowed = btrue;
3698 sz_buttons[but_3dfx] = "Good";
3699 }
3700 }
3701 }
3702 }
3703
3704 // Water Quality
3705 ui_drawTextBox( menuFont, "Good Water:", buttonLeft + 300, GFX_HEIGHT - 215, 0, 0, 20 );
3706 if ( BUTTON_UP == ui_doButton( 11, sz_buttons[but_multiwater], menuFont, buttonLeft + 450, GFX_HEIGHT - 215, 100, 30 ) )
3707 {
3708 if ( cfg.twolayerwater_allowed )
3709 {
3710 sz_buttons[but_multiwater] = "Off";
3711 cfg.twolayerwater_allowed = bfalse;
3712 }
3713 else
3714 {
3715 sz_buttons[but_multiwater] = "On";
3716 cfg.twolayerwater_allowed = btrue;
3717 }
3718 }
3719
3720 // Max particles
3721 ui_drawTextBox( menuFont, "Max Particles:", buttonLeft + 300, GFX_HEIGHT - 180, 0, 0, 20 );
3722
3723 if ( PMod->active )
3724 {
3725 snprintf( Cmaxparticles, SDL_arraysize( Cmaxparticles ), "%i (%i currently used)", maxparticles, maxparticles - prt_count_free() );
3726 ui_drawTextBox( menuFont, Cmaxparticles, buttonLeft + 450, GFX_HEIGHT - 180, 0, 100, 30 );
3727 }
3728 else if ( BUTTON_UP == ui_doButton( 15, sz_buttons[but_maxparticles], menuFont, buttonLeft + 450, GFX_HEIGHT - 180, 100, 30 ) )
3729 {
3730 if ( cfg.particle_count_req < 256 )
3731 {
3732 cfg.particle_count_req = 256;
3733 }
3734 else
3735 {
3736 cfg.particle_count_req += 128;
3737 }
3738
3739 if ( cfg.particle_count_req > MAX_PRT ) cfg.particle_count_req = 256;
3740
3741 snprintf( Cmaxparticles, SDL_arraysize( Cmaxparticles ), "%i", cfg.particle_count_req ); // Convert integer to a char we can use
3742 sz_buttons[but_maxparticles] = Cmaxparticles;
3743 }
3744
3745 // Widescreen
3746 ui_drawTextBox( menuFont, "Widescreen:", buttonLeft + 300, GFX_HEIGHT - 70, 0, 0, 20 );
3747 if ( BUTTON_UP == ui_doButton( 12, sz_buttons[but_widescreen], menuFont, buttonLeft + 450, GFX_HEIGHT - 70, 25, 25 ) )
3748 {
3749 bool_t old_widescreen = widescreen;
3750
3751 // toggle widescreen
3752 widescreen = !widescreen;
3753
3754 if ( old_widescreen )
3755 {
3756 // switch the display from widescreen to non-widescreen
3757 sz_buttons[but_widescreen] = " ";
3758
3759 // Set to default non-widescreen resolution
3760 cfg.scrx_req = 800;
3761 cfg.scry_req = 600;
3762 sz_buttons[but_screensize] = "800x600";
3763 }
3764 else
3765 {
3766 // switch the display from non-widescreen to widescreen
3767 sz_buttons[but_widescreen] = "X";
3768
3769 // Set to "default" widescreen resolution
3770 cfg.scrx_req = 960;
3771 cfg.scry_req = 600;
3772 sz_buttons[but_screensize] = "960x600";
3773 }
3774 }
3775
3776 // Screen Resolution
3777 ui_drawTextBox( menuFont, "Resolution:", buttonLeft + 300, GFX_HEIGHT - 110, 0, 0, 20 );
3778 if ( BUTTON_UP == ui_doButton( 13, sz_buttons[but_screensize], menuFont, buttonLeft + 450, GFX_HEIGHT - 110, 125, 30 ) )
3779 {
3780 float req_area;
3781
3782 cfg.scrx_req *= 1.1f;
3783 cfg.scry_req *= 1.1f;
3784
3785 req_area = cfg.scrx_req * cfg.scry_req;
3786
3787 // use 1920x1200 as a kind of max resolution
3788 if ( req_area > 1920 * 1200 )
3789 {
3790 // reset the screen size to the minimum
3791 if ( widescreen )
3792 {
3793 // "default" widescreen
3794 cfg.scrx_req = 960;
3795 cfg.scry_req = 600;
3796 }
3797 else
3798 {
3799 // "default"
3800 cfg.scrx_req = 800;
3801 cfg.scry_req = 600;
3802 }
3803 }
3804
3805 if ( cfg.fullscreen_req && NULL != sdl_scr.video_mode_list )
3806 {
3807 // coerce the screen size to a valid fullscreen mode
3808 doVideoOptions_fix_fullscreen_resolution( &cfg, &sdl_scr, &sz_screen_size );
3809 }
3810 else
3811 {
3812 // just accept whatever we are given
3813 snprintf( sz_screen_size, sizeof( sz_screen_size ), "%dx%d", cfg.scrx_req, cfg.scry_req );
3814 }
3815
3816 sz_buttons[but_screensize] = sz_screen_size;
3817
3818 aspect_ratio = ( float )cfg.scrx_req / ( float )cfg.scry_req;
3819
3820 // 1.539 is "half way" between normal aspect ratio (4/3) and anamorphic (16/9)
3821 widescreen = ( aspect_ratio > ( 1.539f ) );
3822
3823 if ( widescreen ) sz_buttons[but_widescreen] = "X";
3824 else sz_buttons[but_widescreen] = " ";
3825 }
3826
3827 // Save settings button
3828 if ( BUTTON_UP == ui_doButton( 14, "Save Settings", NULL, buttonLeft, GFX_HEIGHT - 60, 200, 30 ) )
3829 {
3830 menuChoice = 1;
3831
3832 // synchronoze the config values with the various game subsystems
3833 setup_synch( &cfg );
3834
3835 // save the setup file
3836 setup_upload( &cfg );
3837 setup_write();
3838
3839 // Reload some of the graphics
3840 load_graphics();
3841 }
3842 if ( menuChoice != 0 )
3843 {
3844 menuState = MM_Leaving;
3845 mnu_SlidyButton_init( 0.0f, sz_buttons );
3846 }
3847
3848 // tool-tip text
3849 ui_drawTextBox( menuFont, tipText, tipTextLeft, tipTextTop, 0, 0, 20 );
3850
3851 break;
3852
3853 case MM_Leaving:
3854 // Do buttons sliding out and background fading
3855 // Do the same stuff as in MM_Entering, but backwards
3856 GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
3857
3858 if ( mnu_draw_background )
3859 {
3860 ui_drawImage( 0, &background, ( GFX_WIDTH - background.imgW ), 0, 0, 0, NULL );
3861 }
3862
3863 // Fall trough
3864 menuState = MM_Finish;
3865 break;
3866
3867 case MM_Finish:
3868 // Free the background texture; don't need to hold onto it
3869 oglx_texture_Release( &background );
3870 menuState = MM_Begin; // Make sure this all resets next time
3871
3872 // reset the ui
3873 ui_Reset();
3874
3875 // Set the next menu to load
3876 result = menuChoice;
3877 break;
3878 }
3879
3880 return result;
3881 }
3882
3883 //--------------------------------------------------------------------------------------------
doShowResults(float deltaTime)3884 int doShowResults( float deltaTime )
3885 {
3886 static Font *font;
3887 static int menuState = MM_Begin;
3888 static int count;
3889 static char* game_hint;
3890 static char buffer[1024] = EMPTY_CSTR;
3891
3892 int menuResult = 0;
3893
3894 switch ( menuState )
3895 {
3896 case MM_Begin:
3897 {
3898 Uint8 i;
3899 char * carat = buffer, * carat_end = buffer + SDL_arraysize( buffer );
3900
3901 font = ui_getFont();
3902 count = 0;
3903 menuState = MM_Entering;
3904
3905 // Prepeare the summary text
3906 for ( i = 0; i < SUMMARYLINES; i++ )
3907 {
3908 carat += snprintf( carat, carat_end - carat - 1, "%s\n", mnu_ModList.lst[( MOD_REF )selectedModule].base.summary[i] );
3909 }
3910
3911 // Randomize the next game hint, but only if not in hard mode
3912 game_hint = CSTR_END;
3913 if ( cfg.difficulty <= GAME_NORMAL )
3914 {
3915 // Should be okay to randomize the seed here, the random seed isnt standarized or
3916 // used elsewhere before the module is loaded.
3917 srand( time( NULL ) );
3918 if ( mnu_GameTip_load_local_vfs() ) game_hint = mnu_GameTip.local_hint[rand() % mnu_GameTip.local_count];
3919 else if ( mnu_GameTip.count > 0 ) game_hint = mnu_GameTip.hint[rand() % mnu_GameTip.count];
3920 }
3921 }
3922 // pass through
3923
3924 case MM_Entering:
3925 menuState = MM_Running;
3926 // pass through
3927
3928 case MM_Running:
3929 {
3930 int text_h, text_w;
3931 ui_drawButton( UI_Nothing, 30, 30, GFX_WIDTH - 60, GFX_HEIGHT - 65, NULL );
3932
3933 GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
3934
3935 // the module name
3936 ui_drawTextBox( font, mnu_ModList.lst[( MOD_REF )selectedModule].base.longname, 50, 80, 291, 230, 20 );
3937
3938 // Draw a text box
3939 ui_drawTextBox( menuFont, buffer, 50, 120, 291, 230, 20 );
3940
3941 // Loading game... please wait
3942 fnt_getTextSize( font, "Loading module...", &text_w, &text_h );
3943 ui_drawTextBox( font, "Loading module...", ( GFX_WIDTH / 2 ) - text_w / 2, GFX_HEIGHT - 200, 0, 0, 20 );
3944
3945 // Draw the game tip
3946 if ( VALID_CSTR( game_hint ) )
3947 {
3948 fnt_getTextSize( menuFont, "GAME TIP", &text_w, &text_h );
3949 ui_drawTextBox( font, "GAME TIP", ( GFX_WIDTH / 2 ) - ( text_w / 2 ), GFX_HEIGHT - 150, 0, 0, 20 );
3950
3951 fnt_getTextSize( menuFont, game_hint, &text_w, &text_h ); /// @todo ZF@> : this doesnt work as I intended, fnt_get_TextSize() does not take line breaks into account
3952 ui_drawTextBox( menuFont, game_hint, ( GFX_WIDTH / 2 ) - ( text_w / 2 ), GFX_HEIGHT - 110, 0, 0, 10 );
3953 }
3954
3955 // keep track of the iterations through this section for a timer
3956 count++;
3957 if ( count > UPDATE_SKIP )
3958 {
3959 menuState = MM_Leaving;
3960 }
3961 }
3962 break;
3963
3964 case MM_Leaving:
3965 menuState = MM_Finish;
3966 // pass through
3967
3968 case MM_Finish:
3969 menuResult = 1;
3970 menuState = MM_Begin;
3971 }
3972
3973 return menuResult;
3974 }
3975
3976 //--------------------------------------------------------------------------------------------
doNotImplemented(float deltaTime)3977 int doNotImplemented( float deltaTime )
3978 {
3979 int x, y;
3980 int w, h;
3981 char notImplementedMessage[] = "Not implemented yet! Check back soon!";
3982
3983 fnt_getTextSize( ui_getFont(), notImplementedMessage, &w, &h );
3984 w += 50; // add some space on the sides
3985
3986 x = GFX_WIDTH / 2 - w / 2;
3987 y = GFX_HEIGHT / 2 - 17;
3988 if ( BUTTON_UP == ui_doButton( 1, notImplementedMessage, NULL, x, y, w, 30 ) )
3989 {
3990 return 1;
3991 }
3992
3993 return 0;
3994 }
3995
3996 //--------------------------------------------------------------------------------------------
doGamePaused(float deltaTime)3997 int doGamePaused( float deltaTime )
3998 {
3999 static int menuState = MM_Begin;
4000 static int menuChoice = 0;
4001
4002 static const char * buttons[] =
4003 {
4004 "Quit Module",
4005 "Restart Module",
4006 "Return to Module",
4007 "Options",
4008 ""
4009 };
4010
4011 int result = 0, cnt;
4012
4013 switch ( menuState )
4014 {
4015 case MM_Begin:
4016 // set up menu variables
4017 menuChoice = 0;
4018 menuState = MM_Entering;
4019
4020 if ( PMod->exportvalid && !local_stats.allpladead ) buttons[0] = "Save and Exit";
4021 else buttons[0] = "Quit Module";
4022
4023 mnu_SlidyButton_init( 1.0f, buttons );
4024
4025 case MM_Entering:
4026 mnu_SlidyButton_draw_all();
4027 mnu_SlidyButton_update_all( -deltaTime );
4028
4029 // Let lerp wind down relative to the time elapsed
4030 if ( mnu_SlidyButtonState.lerp <= 0.0f )
4031 {
4032 menuState = MM_Running;
4033 }
4034 break;
4035
4036 case MM_Running:
4037 // Do normal run
4038 // Background
4039 GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
4040
4041 // Buttons
4042 for ( cnt = 0; cnt < 4; cnt ++ )
4043 {
4044 if ( BUTTON_UP == ui_doButton( cnt + 1, buttons[cnt], NULL, buttonLeft, buttonTop + ( cnt * 35 ), 200, 30 ) )
4045 {
4046 // audio options
4047 menuChoice = cnt + 1;
4048 }
4049 }
4050
4051 // Quick return to game
4052 if ( SDLKEYDOWN( SDLK_ESCAPE ) ) menuChoice = 3;
4053
4054 if ( menuChoice != 0 )
4055 {
4056 menuState = MM_Leaving;
4057 mnu_SlidyButton_init( 0.0f, buttons );
4058 }
4059 break;
4060
4061 case MM_Leaving:
4062 // Do buttons sliding out and background fading
4063 // Do the same stuff as in MM_Entering, but backwards
4064 GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
4065
4066 // Buttons
4067 mnu_SlidyButton_draw_all();
4068 mnu_SlidyButton_update_all( deltaTime );
4069 if ( mnu_SlidyButtonState.lerp >= 1.0f )
4070 {
4071 menuState = MM_Finish;
4072 }
4073 break;
4074
4075 case MM_Finish:
4076 // Free the background texture; don't need to hold onto it
4077 menuState = MM_Begin; // Make sure this all resets next time
4078
4079 // reset the ui
4080 ui_Reset();
4081
4082 // Set the next menu to load
4083 result = menuChoice;
4084 break;
4085 }
4086
4087 return result;
4088 }
4089
4090 //--------------------------------------------------------------------------------------------
doShowEndgame(float deltaTime)4091 int doShowEndgame( float deltaTime )
4092 {
4093 static int menuState = MM_Begin;
4094 static int menuChoice = 0;
4095 static int x, y, w, h;
4096 static Font *font;
4097
4098 static const char * buttons[] =
4099 {
4100 "BLAH",
4101 ""
4102 };
4103
4104 int cnt, retval;
4105
4106 retval = 0;
4107 switch ( menuState )
4108 {
4109 case MM_Begin:
4110 menuState = MM_Entering;
4111 font = ui_getFont();
4112
4113 mnu_SlidyButton_init( 1.0f, buttons );
4114
4115 if ( PMod->exportvalid )
4116 {
4117 buttons[0] = "Save and Exit";
4118 }
4119 else
4120 {
4121 buttons[0] = "Exit Game";
4122 }
4123
4124 x = 70;
4125 y = 70;
4126 w = GFX_WIDTH - 2 * x;
4127 h = GFX_HEIGHT - 2 * y;
4128
4129 case MM_Entering:
4130
4131 GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
4132
4133 ui_drawTextBox( NULL, endtext, x, y, w, h, 20 );
4134 mnu_SlidyButton_draw_all();
4135
4136 mnu_SlidyButton_update_all( -deltaTime );
4137
4138 // Let lerp wind down relative to the time elapsed
4139 if ( mnu_SlidyButtonState.lerp <= 0.0f )
4140 {
4141 menuState = MM_Running;
4142 }
4143 break;
4144
4145 case MM_Running:
4146 GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
4147
4148 // Buttons
4149 for ( cnt = 0; cnt < 1; cnt ++ )
4150 {
4151 if ( BUTTON_UP == ui_doButton( cnt + 1, buttons[cnt], NULL, buttonLeft, buttonTop + ( cnt * 35 ), 200, 30 ) )
4152 {
4153 // audio options
4154 menuChoice = cnt + 1;
4155 menuState = MM_Leaving;
4156 }
4157 }
4158
4159 // escape also kills this menu
4160 if ( SDLKEYDOWN( SDLK_ESCAPE ) )
4161 {
4162 menuChoice = 1;
4163 menuState = MM_Leaving;
4164 }
4165
4166 ui_drawTextBox( NULL, endtext, x, y, w, h, 20 );
4167
4168 break;
4169
4170 case MM_Leaving:
4171 // Do buttons sliding out and background fading
4172 // Do the same stuff as in MM_Entering, but backwards
4173 GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
4174
4175 ui_drawTextBox( NULL, endtext, x, y, w, h, 20 );
4176
4177 // Buttons
4178 mnu_SlidyButton_draw_all();
4179 mnu_SlidyButton_update_all( deltaTime );
4180 if ( mnu_SlidyButtonState.lerp >= 1.0f )
4181 {
4182 menuState = MM_Finish;
4183 }
4184 break;
4185
4186 case MM_Finish:
4187 {
4188 bool_t reloaded = bfalse;
4189
4190 // try to pop the last module off the module stack
4191 reloaded = link_pop_module();
4192
4193 // try to go to the world map
4194 // if( !reloaded )
4195 // {
4196 // reloaded = link_load_parent( mnu_ModList.lst[pickedmodule_index].base.parent_modname, mnu_ModList.lst[pickedmodule_index].base.parent_pos );
4197 // }
4198
4199 // fix the menu that is returned when you break out of the game
4200 if ( PMod->beat && start_new_player )
4201 {
4202 // we started with a new player and beat the module... yay!
4203 // now we want to graduate to the ChoosePlayer menu to
4204 // build our party
4205
4206 start_new_player = bfalse;
4207
4208 // if we beat a beginner module, we want to
4209 // go to ChoosePlayer instead of ChooseModule.
4210 if ( mnu_stack_peek() == emnu_ChooseModule )
4211 {
4212 mnu_stack_pop();
4213 mnu_stack_push( emnu_ChoosePlayer );
4214 }
4215 }
4216
4217 // actually quit the module
4218 if ( !reloaded )
4219 {
4220 game_finish_module();
4221 pickedmodule_index = -1;
4222 process_kill( PROC_PBASE( GProc ) );
4223 }
4224
4225 menuState = MM_Begin;
4226
4227 // Set the next menu to load
4228 retval = menuChoice;
4229 }
4230 }
4231
4232 return retval;
4233 }
4234
4235 //--------------------------------------------------------------------------------------------
4236 // place this last so that we do not have to prototype every menu function
doMenu(float deltaTime)4237 int doMenu( float deltaTime )
4238 {
4239 /// @details the global function that controls the navigation between menus
4240
4241 int retval, result = 0;
4242
4243 if ( mnu_whichMenu == emnu_Main )
4244 {
4245 mnu_stack_clear();
4246 };
4247
4248 retval = MENU_NOTHING;
4249
4250 switch ( mnu_whichMenu )
4251 {
4252 case emnu_Main:
4253 result = doMainMenu( deltaTime );
4254 if ( result != 0 )
4255 {
4256 if ( 1 == result ) { mnu_begin_menu( emnu_ChooseModule ); start_new_player = btrue; }
4257 else if ( 2 == result ) { mnu_begin_menu( emnu_ChoosePlayer ); start_new_player = bfalse; }
4258 else if ( 3 == result ) { mnu_begin_menu( emnu_Options ); }
4259 else if ( 4 == result ) retval = MENU_QUIT; // need to request a quit somehow
4260 }
4261 break;
4262
4263 case emnu_SinglePlayer:
4264 result = doSinglePlayerMenu( deltaTime );
4265
4266 if ( result != 0 )
4267 {
4268 if ( 1 == result )
4269 {
4270 mnu_begin_menu( emnu_ChooseModule );
4271 start_new_player = btrue;
4272 }
4273 else if ( 2 == result )
4274 {
4275 mnu_begin_menu( emnu_ChoosePlayer );
4276 start_new_player = bfalse;
4277 }
4278 else if ( 3 == result )
4279 {
4280 mnu_end_menu();
4281 retval = MENU_END;
4282 }
4283 else
4284 {
4285 mnu_begin_menu( emnu_NewPlayer );
4286 }
4287 }
4288 break;
4289
4290 case emnu_ChooseModule:
4291 result = doChooseModule( deltaTime );
4292
4293 if ( -1 == result ) { mnu_end_menu(); retval = MENU_END; }
4294 else if ( 1 == result ) mnu_begin_menu( emnu_ShowMenuResults ); // imports are not valid (starter module)
4295 else if ( 2 == result ) mnu_begin_menu( emnu_ShowMenuResults ); // imports are valid
4296
4297 break;
4298
4299 case emnu_ChoosePlayer:
4300 result = doChoosePlayer( deltaTime );
4301
4302 if ( -1 == result ) { mnu_end_menu(); retval = MENU_END; }
4303 else if ( 1 == result ) mnu_begin_menu( emnu_ChooseModule );
4304
4305 break;
4306
4307 case emnu_Options:
4308 result = doOptions( deltaTime );
4309 if ( result != 0 )
4310 {
4311 if ( 1 == result ) mnu_begin_menu( emnu_AudioOptions );
4312 else if ( 2 == result ) mnu_begin_menu( emnu_InputOptions );
4313 else if ( 3 == result ) mnu_begin_menu( emnu_VideoOptions );
4314 else if ( 4 == result ) { mnu_end_menu(); retval = MENU_END; }
4315 else if ( 5 == result ) mnu_begin_menu( emnu_GameOptions );
4316 }
4317 break;
4318
4319 case emnu_GameOptions:
4320 result = doGameOptions( deltaTime );
4321 if ( result != 0 )
4322 {
4323 mnu_end_menu();
4324 retval = MENU_END;
4325 }
4326 break;
4327
4328 case emnu_AudioOptions:
4329 result = doAudioOptions( deltaTime );
4330 if ( result != 0 )
4331 {
4332 mnu_end_menu();
4333 retval = MENU_END;
4334 }
4335 break;
4336
4337 case emnu_VideoOptions:
4338 result = doVideoOptions( deltaTime );
4339 if ( result != 0 )
4340 {
4341 mnu_end_menu();
4342 retval = MENU_END;
4343 }
4344 break;
4345
4346 case emnu_InputOptions:
4347 result = doInputOptions( deltaTime );
4348 if ( result != 0 )
4349 {
4350 mnu_end_menu();
4351 retval = MENU_END;
4352 }
4353 break;
4354
4355 case emnu_ShowMenuResults:
4356 result = doShowResults( deltaTime );
4357 if ( result != 0 )
4358 {
4359 mnu_end_menu();
4360 retval = MENU_SELECT;
4361 }
4362 break;
4363
4364 case emnu_GamePaused:
4365 result = doGamePaused( deltaTime );
4366 if ( result != 0 )
4367 {
4368 if ( 1 == result )
4369 {
4370 // "Quit Module"
4371
4372 bool_t reloaded = bfalse;
4373
4374 mnu_end_menu();
4375
4376 // try to pop the last module off the module stack
4377 reloaded = link_pop_module();
4378
4379 // try to go to the world map
4380 // if( !reloaded )
4381 // {
4382 // reloaded = link_load_parent( mnu_ModList.lst[pickedmodule_index].base.parent_modname, mnu_ModList.lst[pickedmodule_index].base.parent_pos );
4383 // }
4384
4385 if ( !reloaded )
4386 {
4387 game_finish_module();
4388 process_kill( PROC_PBASE( GProc ) );
4389 }
4390
4391 result = MENU_QUIT;
4392 }
4393 else if ( 2 == result )
4394 {
4395 // "Restart Module"
4396 mnu_end_menu();
4397
4398 //Simply quit the current module and begin it again
4399 game_quit_module();
4400 game_begin_module( PMod->loadname, ( Uint32 )~0 );
4401
4402 retval = MENU_END;
4403 }
4404 else if ( 3 == result )
4405 {
4406 // "Return to Module"
4407 mnu_end_menu();
4408 retval = MENU_END;
4409 }
4410 else if ( 4 == result )
4411 {
4412 // "Options"
4413 mnu_begin_menu( emnu_Options );
4414 }
4415 }
4416 break;
4417
4418 case emnu_ShowEndgame:
4419 result = doShowEndgame( deltaTime );
4420 if ( 1 == result )
4421 {
4422 mnu_end_menu();
4423 retval = MENU_END;
4424 }
4425 break;
4426
4427 case emnu_NotImplemented:
4428 default:
4429 result = doNotImplemented( deltaTime );
4430 if ( result != 0 )
4431 {
4432 mnu_end_menu();
4433 retval = MENU_END;
4434 }
4435 }
4436
4437 return retval;
4438 }
4439
4440 //--------------------------------------------------------------------------------------------
4441 // Auto formatting functions
4442 //--------------------------------------------------------------------------------------------
autoformat_init(gfx_config_t * pgfx)4443 void autoformat_init( gfx_config_t * pgfx )
4444 {
4445 autoformat_init_slidy_buttons();
4446 autoformat_init_tip_text();
4447 autoformat_init_copyright_text();
4448
4449 if ( NULL != pgfx )
4450 {
4451 ui_set_virtual_screen( pgfx->vw, pgfx->vh, GFX_WIDTH, GFX_HEIGHT );
4452 }
4453 }
4454
4455 //--------------------------------------------------------------------------------------------
autoformat_init_slidy_buttons()4456 void autoformat_init_slidy_buttons()
4457 {
4458 // Figure out where to draw the buttons
4459 buttonLeft = 40;
4460 buttonTop = GFX_HEIGHT - 20;
4461 }
4462
4463 //--------------------------------------------------------------------------------------------
autoformat_init_tip_text()4464 void autoformat_init_tip_text()
4465 {
4466 // set the text
4467 tipText = NULL;
4468
4469 // Draw the options text to the right of the buttons
4470 tipTextLeft = 280;
4471
4472 // And relative to the bottom of the screen
4473 tipTextTop = GFX_HEIGHT;
4474 }
4475
4476 //--------------------------------------------------------------------------------------------
autoformat_init_copyright_text()4477 void autoformat_init_copyright_text()
4478 {
4479 // set the text
4480 copyrightText = "Welcome to Egoboo!\nhttp://egoboo.sourceforge.net\nVersion " VERSION "\n";
4481
4482 // Draw the copyright text to the right of the buttons
4483 copyrightLeft = 280;
4484
4485 // And relative to the bottom of the screen
4486 copyrightTop = GFX_HEIGHT;
4487 }
4488
4489 //--------------------------------------------------------------------------------------------
4490 // Implementation of tipText
4491 //--------------------------------------------------------------------------------------------
tipText_set_position(Font * font,const char * text,int spacing)4492 void tipText_set_position( Font * font, const char * text, int spacing )
4493 {
4494 int w, h;
4495
4496 autoformat_init_tip_text();
4497
4498 if ( NULL == text ) return;
4499
4500 fnt_getTextBoxSize( font, text, spacing, &w, &h );
4501
4502 // set the text
4503 tipText = text;
4504
4505 // Draw the options text to the right of the buttons
4506 tipTextLeft = 280;
4507
4508 // And relative to the bottom of the screen
4509 tipTextTop = GFX_HEIGHT - h - spacing;
4510 }
4511
4512 //--------------------------------------------------------------------------------------------
4513 // Implementation of copyrightText
4514 //--------------------------------------------------------------------------------------------
copyrightText_set_position(Font * font,const char * text,int spacing)4515 void copyrightText_set_position( Font * font, const char * text, int spacing )
4516 {
4517 int w, h;
4518
4519 autoformat_init_copyright_text();
4520
4521 if ( NULL == text ) return;
4522
4523 copyrightLeft = 0;
4524 copyrightLeft = 0;
4525
4526 // Figure out where to draw the copyright text
4527 fnt_getTextBoxSize( font, text, 20, &w, &h );
4528
4529 // set the text
4530 copyrightText = text;
4531
4532 // Draw the copyright text to the right of the buttons
4533 copyrightLeft = 280;
4534
4535 // And relative to the bottom of the screen
4536 copyrightTop = GFX_HEIGHT - h - spacing;
4537 }
4538
4539 //--------------------------------------------------------------------------------------------
4540 // Asset management
4541 //--------------------------------------------------------------------------------------------
mnu_load_all_module_images_vfs(LoadPlayer_list_t * lp_lst)4542 void mnu_load_all_module_images_vfs( LoadPlayer_list_t * lp_lst )
4543 {
4544 /// @details ZZ@> This function loads the title image for each module. Modules without a
4545 /// title are marked as invalid
4546
4547 STRING loadname;
4548 MOD_REF imod;
4549 vfs_FILE* filesave;
4550
4551 // release all allocated data from the mnu_ModList and empty the list
4552 mnu_ModList_release_images();
4553
4554 // Log a directory list
4555 filesave = vfs_openWrite( "/debug/modules.txt" );
4556 if ( NULL != filesave )
4557 {
4558 vfs_printf( filesave, "This file logs all of the modules found\n" );
4559 vfs_printf( filesave, "** Denotes an invalid module\n" );
4560 vfs_printf( filesave, "## Denotes an unlockable module\n\n" );
4561 }
4562
4563 // load all the title images for modules that we are going to display
4564 for ( imod = 0; imod < mnu_ModList.count; imod++ )
4565 {
4566 if ( !mnu_ModList.lst[imod].loaded )
4567 {
4568 vfs_printf( filesave, "**. %s\n", mnu_ModList.lst[imod].vfs_path );
4569 }
4570 else if ( mnu_test_module_by_index( lp_lst, imod, 0, NULL ) )
4571 {
4572 // @note just because we can't load the title image DOES NOT mean that we ignore the module
4573 snprintf( loadname, SDL_arraysize( loadname ), "%s/gamedat/title", mnu_ModList.lst[imod].vfs_path );
4574
4575 mnu_ModList.lst[imod].tex_index = TxTitleImage_load_one_vfs( loadname );
4576
4577 vfs_printf( filesave, "%02d. %s\n", REF_TO_INT( imod ), mnu_ModList.lst[imod].vfs_path );
4578 }
4579 else
4580 {
4581 vfs_printf( filesave, "##. %s\n", mnu_ModList.lst[imod].vfs_path );
4582 }
4583 }
4584
4585 if ( NULL != filesave )
4586 {
4587 vfs_close( filesave );
4588 }
4589 }
4590
4591 //--------------------------------------------------------------------------------------------
mnu_get_icon_ref(const CAP_REF icap,const TX_REF default_ref)4592 TX_REF mnu_get_icon_ref( const CAP_REF icap, const TX_REF default_ref )
4593 {
4594 /// @details BB@> This function gets the proper icon for a an object profile.
4595 //
4596 // In the character preview section of the menu system, we do not load
4597 // entire profiles, just the character definition file ("data.txt")
4598 // and one icon. Sometimes, though the item is actually a spell effect which means
4599 // that we need to display the book icon.
4600
4601 TX_REF icon_ref = ( TX_REF )ICON_NULL;
4602 bool_t is_spell_fx, is_book, draw_book;
4603
4604 cap_t * pitem_cap;
4605
4606 if ( !LOADED_CAP( icap ) ) return icon_ref;
4607 pitem_cap = CapStack.lst + icap;
4608
4609 // what do we need to draw?
4610 is_spell_fx = ( NO_SKIN_OVERRIDE != pitem_cap->spelleffect_type );
4611 is_book = ( SPELLBOOK == icap );
4612 draw_book = ( is_book || is_spell_fx ) && ( bookicon_count > 0 );
4613
4614 if ( !draw_book )
4615 {
4616 icon_ref = default_ref;
4617 }
4618 else if ( draw_book )
4619 {
4620 int iskin = 0;
4621
4622 if ( NO_SKIN_OVERRIDE != pitem_cap->spelleffect_type )
4623 {
4624 iskin = pitem_cap->spelleffect_type;
4625 }
4626 else if ( NO_SKIN_OVERRIDE != pitem_cap->skin_override )
4627 {
4628 iskin = pitem_cap->skin_override;
4629 }
4630
4631 iskin = CLIP( iskin, 0, bookicon_count );
4632
4633 icon_ref = bookicon_ref[ iskin ];
4634 }
4635
4636 return icon_ref;
4637 }
4638
4639 //--------------------------------------------------------------------------------------------
4640 // module utilities
4641 //--------------------------------------------------------------------------------------------
mnu_get_mod_number(const char * szModName)4642 int mnu_get_mod_number( const char *szModName )
4643 {
4644 /// @details ZZ@> This function returns -1 if the module does not exist locally, the module
4645 /// index otherwise
4646
4647 MOD_REF modnum;
4648 int retval = -1;
4649
4650 for ( modnum = 0; modnum < mnu_ModList.count; modnum++ )
4651 {
4652 if ( 0 == strcmp( mnu_ModList.lst[modnum].vfs_path, szModName ) )
4653 {
4654 retval = REF_TO_INT( modnum );
4655 break;
4656 }
4657 }
4658
4659 return retval;
4660 }
4661
4662 //--------------------------------------------------------------------------------------------
mnu_test_module_by_index(LoadPlayer_list_t * lp_lst,const MOD_REF modnumber,size_t buffer_len,char * buffer)4663 bool_t mnu_test_module_by_index( LoadPlayer_list_t * lp_lst, const MOD_REF modnumber, size_t buffer_len, char * buffer )
4664 {
4665 int cnt;
4666 mnu_module_t * pmod;
4667 bool_t allowed;
4668
4669 if ( INVALID_MOD( modnumber ) ) return bfalse;
4670 pmod = mnu_ModList.lst + modnumber;
4671
4672 // First check if we are in developers mode or that the right module has been beaten before
4673 allowed = bfalse;
4674
4675 if ( cfg.dev_mode )
4676 {
4677 allowed = btrue;
4678 }
4679
4680 if ( !allowed )
4681 {
4682 if ( module_has_idsz_vfs( pmod->base.reference, pmod->base.unlockquest.id, buffer_len, buffer ) )
4683 {
4684 allowed = btrue;
4685 }
4686 }
4687
4688 if ( !allowed && pmod->base.importamount > 0 )
4689 {
4690 int player_count = 0;
4691 int player_allowed = 0;
4692
4693 // If that did not work, then check all selected players directories, but only if it isn't a starter module
4694 for ( cnt = 0; cnt < lp_lst->count; cnt++ )
4695 {
4696 int quest_level = QUEST_NONE;
4697 LoadPlayer_element_t * ptr = lp_lst->lst + cnt;
4698
4699 player_count++;
4700
4701 quest_level = quest_get_level( ptr->quest_log, SDL_arraysize( ptr->quest_log ), pmod->base.unlockquest.id );
4702
4703 // find beaten quests or quests with proper level
4704 if ( quest_level <= QUEST_BEATEN || pmod->base.unlockquest.level <= quest_level )
4705 {
4706 player_allowed++;
4707 }
4708 }
4709
4710 allowed = ( player_allowed == player_count );
4711 }
4712
4713 return allowed;
4714 }
4715
4716 //--------------------------------------------------------------------------------------------
mnu_test_module_by_name(LoadPlayer_list_t * lp_lst,const char * szModName)4717 bool_t mnu_test_module_by_name( LoadPlayer_list_t * lp_lst, const char *szModName )
4718 {
4719 /// @details ZZ@> This function tests to see if a module can be entered by
4720 /// the players
4721
4722 bool_t retval;
4723
4724 // find the module by name
4725 int modnumber = mnu_get_mod_number( szModName );
4726
4727 retval = bfalse;
4728 if ( modnumber >= 0 )
4729 {
4730 retval = mnu_test_module_by_index( lp_lst, ( MOD_REF )modnumber, 0, NULL );
4731 }
4732
4733 return retval;
4734 }
4735
4736 //--------------------------------------------------------------------------------------------
mnu_module_init(mnu_module_t * pmod)4737 void mnu_module_init( mnu_module_t * pmod )
4738 {
4739 if ( NULL == pmod ) return;
4740
4741 // clear the module
4742 memset( pmod, 0, sizeof( *pmod ) );
4743
4744 pmod->tex_index = INVALID_TITLE_TEXTURE;
4745 }
4746
4747 //--------------------------------------------------------------------------------------------
mnu_load_all_module_info()4748 void mnu_load_all_module_info()
4749 {
4750 vfs_search_context_t * ctxt;
4751
4752 const char *vfs_ModPath;
4753 STRING loadname;
4754
4755 // reset the module list
4756 mnu_ModList_release_all();
4757
4758 // Search for all .mod directories and load the module info
4759 ctxt = vfs_findFirst( "mp_modules", "mod", VFS_SEARCH_DIR );
4760 vfs_ModPath = vfs_search_context_get_current( ctxt );
4761
4762 while ( NULL != ctxt && VALID_CSTR( vfs_ModPath ) && mnu_ModList.count < MAX_MODULE )
4763 {
4764 mnu_module_t * pmod = mnu_ModList.lst + ( MOD_REF )mnu_ModList.count;
4765
4766 // clear the module
4767 mnu_module_init( pmod );
4768
4769 // save the filename
4770 snprintf( loadname, SDL_arraysize( loadname ), "%s/gamedat/menu.txt", vfs_ModPath );
4771 if ( NULL != module_load_info_vfs( loadname, &( pmod->base ) ) )
4772 {
4773 mnu_ModList.count++;
4774
4775 // mark the module data as loaded
4776 pmod->loaded = btrue;
4777
4778 // save the module path
4779 strncpy( pmod->vfs_path, vfs_ModPath, SDL_arraysize( pmod->vfs_path ) );
4780
4781 // Save the user data directory version of the module path.
4782 // @note This is kinda a cheat since we know that the virtual paths all begin with "mp_" at the moment.
4783 // If that changes, this line must be changed as well.
4784 snprintf( pmod->dest_path, SDL_arraysize( pmod->dest_path ), "/%s", vfs_ModPath + 3 );
4785
4786 // same problem as above
4787 strncpy( pmod->name, vfs_ModPath + 11, SDL_arraysize( pmod->name ) );
4788 };
4789
4790 ctxt = vfs_findNext( &ctxt );
4791 vfs_ModPath = vfs_search_context_get_current( ctxt );
4792 }
4793 vfs_findClose( &ctxt );
4794
4795 module_list_valid = btrue;
4796 }
4797
4798 //--------------------------------------------------------------------------------------------
mnu_release_one_module(const MOD_REF imod)4799 void mnu_release_one_module( const MOD_REF imod )
4800 {
4801 mnu_module_t * pmod;
4802
4803 if ( !VALID_MOD( imod ) ) return;
4804 pmod = mnu_ModList.lst + imod;
4805
4806 TxTitleImage_release_one( pmod->tex_index );
4807 pmod->tex_index = INVALID_TITLE_TEXTURE;
4808 }
4809
4810 //--------------------------------------------------------------------------------------------
4811 // Implementation of the ModList struct
4812 //--------------------------------------------------------------------------------------------
mnu_ModList_get_base(int imod)4813 mod_file_t * mnu_ModList_get_base( int imod )
4814 {
4815 if ( imod < 0 || imod >= MAX_MODULE ) return NULL;
4816
4817 return &( mnu_ModList.lst[( MOD_REF )imod].base );
4818 }
4819
4820 //--------------------------------------------------------------------------------------------
mnu_ModList_get_vfs_path(int imod)4821 const char * mnu_ModList_get_vfs_path( int imod )
4822 {
4823 if ( imod < 0 || imod >= MAX_MODULE ) return NULL;
4824
4825 return mnu_ModList.lst[( MOD_REF )imod].vfs_path;
4826 }
4827
4828 //--------------------------------------------------------------------------------------------
mnu_ModList_get_dest_path(int imod)4829 const char * mnu_ModList_get_dest_path( int imod )
4830 {
4831 if ( imod < 0 || imod >= MAX_MODULE ) return NULL;
4832
4833 return mnu_ModList.lst[( MOD_REF )imod].dest_path;
4834 }
4835
4836 //--------------------------------------------------------------------------------------------
mnu_ModList_get_name(int imod)4837 const char * mnu_ModList_get_name( int imod )
4838 {
4839 if ( imod < 0 || imod >= MAX_MODULE ) return NULL;
4840
4841 return mnu_ModList.lst[( MOD_REF )imod].name;
4842 }
4843
4844 //--------------------------------------------------------------------------------------------
mnu_ModList_release_all()4845 void mnu_ModList_release_all()
4846 {
4847 MOD_REF cnt;
4848
4849 for ( cnt = 0; cnt < MAX_MODULE; cnt++ )
4850 {
4851 // release any allocated data
4852 if ( cnt < mnu_ModList.count )
4853 {
4854 mnu_release_one_module( cnt );
4855 }
4856
4857 memset( mnu_ModList.lst + cnt, 0, sizeof( mnu_module_t ) );
4858 }
4859
4860 mnu_ModList.count = 0;
4861 }
4862
4863 //--------------------------------------------------------------------------------------------
mnu_ModList_release_images()4864 void mnu_ModList_release_images()
4865 {
4866 MOD_REF cnt;
4867 int tnc;
4868
4869 tnc = -1;
4870 for ( cnt = 0; cnt < mnu_ModList.count; cnt++ )
4871 {
4872 if ( !mnu_ModList.lst[cnt].loaded ) continue;
4873 tnc = REF_TO_INT( cnt );
4874
4875 TxTitleImage_release_one( mnu_ModList.lst[cnt].tex_index );
4876 mnu_ModList.lst[cnt].tex_index = INVALID_TITLE_TEXTURE;
4877 }
4878 TxTitleImage.count = 0;
4879
4880 // make sure that mnu_ModList.count is the right size, in case some modules were unloaded?
4881 mnu_ModList.count = tnc + 1;
4882 }
4883
4884 //--------------------------------------------------------------------------------------------
4885 // Functions for implementing the TxTitleImage array of textures
4886 //--------------------------------------------------------------------------------------------
TxTitleImage_clear_data()4887 void TxTitleImage_clear_data()
4888 {
4889 TxTitleImage.count = 0;
4890 }
4891
4892 //--------------------------------------------------------------------------------------------
TxTitleImage_ctor()4893 void TxTitleImage_ctor()
4894 {
4895 /// @details ZZ@> This function clears out all of the textures
4896
4897 TX_REF cnt;
4898
4899 for ( cnt = 0; cnt < MAX_MODULE; cnt++ )
4900 {
4901 oglx_texture_ctor( TxTitleImage.lst + cnt );
4902 }
4903
4904 TxTitleImage_clear_data();
4905 }
4906
4907 //--------------------------------------------------------------------------------------------
TxTitleImage_release_one(const TX_REF index)4908 void TxTitleImage_release_one( const TX_REF index )
4909 {
4910 if ( index < 0 || index >= MAX_MODULE ) return;
4911
4912 oglx_texture_Release( TxTitleImage.lst + index );
4913 }
4914
4915 //--------------------------------------------------------------------------------------------
TxTitleImage_release_all()4916 void TxTitleImage_release_all()
4917 {
4918 /// @details ZZ@> This function releases all of the textures
4919
4920 TX_REF cnt;
4921
4922 for ( cnt = 0; cnt < MAX_MODULE; cnt++ )
4923 {
4924 TxTitleImage_release_one( cnt );
4925 }
4926
4927 TxTitleImage_clear_data();
4928 }
4929
4930 //--------------------------------------------------------------------------------------------
TxTitleImage_dtor()4931 void TxTitleImage_dtor()
4932 {
4933 /// @details ZZ@> This function clears out all of the textures
4934
4935 TX_REF cnt;
4936
4937 for ( cnt = 0; cnt < MAX_MODULE; cnt++ )
4938 {
4939 oglx_texture_dtor( TxTitleImage.lst + cnt );
4940 }
4941
4942 TxTitleImage_clear_data();
4943 }
4944
4945 //--------------------------------------------------------------------------------------------
TxTitleImage_load_one_vfs(const char * szLoadName)4946 TX_REF TxTitleImage_load_one_vfs( const char *szLoadName )
4947 {
4948 /// @details ZZ@> This function loads a title in the specified image slot, forcing it into
4949 /// system memory. Returns btrue if it worked
4950
4951 TX_REF itex;
4952
4953 if ( INVALID_CSTR( szLoadName ) ) return ( TX_REF )INVALID_TITLE_TEXTURE;
4954
4955 if ( TxTitleImage.count >= TITLE_TEXTURE_COUNT ) return ( TX_REF )INVALID_TITLE_TEXTURE;
4956
4957 itex = ( TX_REF )TxTitleImage.count;
4958 if ( INVALID_GL_ID != ego_texture_load_vfs( TxTitleImage.lst + itex, szLoadName, INVALID_KEY ) )
4959 {
4960 TxTitleImage.count++;
4961 }
4962 else
4963 {
4964 itex = ( TX_REF )INVALID_TITLE_TEXTURE;
4965 }
4966
4967 return itex;
4968 }
4969
4970 //--------------------------------------------------------------------------------------------
TxTitleImage_get_ptr(const TX_REF itex)4971 oglx_texture_t * TxTitleImage_get_ptr( const TX_REF itex )
4972 {
4973 if ( itex >= TxTitleImage.count || itex >= MAX_MODULE ) return NULL;
4974
4975 return TxTitleImage.lst + itex;
4976 }
4977
4978 //--------------------------------------------------------------------------------------------
TxTitleImage_reload_all()4979 void TxTitleImage_reload_all()
4980 {
4981 /// @details ZZ@> This function re-loads all the current textures back into
4982 /// OpenGL texture memory using the cached SDL surfaces
4983
4984 TX_REF cnt;
4985
4986 for ( cnt = 0; cnt < TX_TEXTURE_COUNT; cnt++ )
4987 {
4988 oglx_texture_t * ptex = TxTitleImage.lst + cnt;
4989
4990 if ( ptex->valid )
4991 {
4992 oglx_texture_Convert( ptex, ptex->surface, INVALID_KEY );
4993 }
4994 }
4995 }
4996
4997 //--------------------------------------------------------------------------------------------
4998 // Implementation of the mnu_GameTip system
4999 //--------------------------------------------------------------------------------------------
mnu_GameTip_load_global_vfs()5000 void mnu_GameTip_load_global_vfs()
5001 {
5002 /// ZF@> This function loads all of the game hints and tips
5003 STRING buffer;
5004 vfs_FILE *fileread;
5005 Uint8 cnt;
5006
5007 // reset the count
5008 mnu_GameTip.count = 0;
5009
5010 // Open the file with all the tips
5011 fileread = vfs_openRead( "mp_data/gametips.txt" );
5012 if ( NULL == fileread )
5013 {
5014 log_warning( "Could not load the game tips and hints. (\"mp_data/gametips.txt\")\n" );
5015 return;
5016 }
5017
5018 // Load the data
5019 for ( cnt = 0; cnt < MENU_MAX_GAMETIPS && !vfs_eof( fileread ); cnt++ )
5020 {
5021 if ( goto_colon( NULL, fileread, btrue ) )
5022 {
5023 //Read the line
5024 fget_string( fileread, buffer, SDL_arraysize( buffer ) );
5025 strcpy( mnu_GameTip.hint[cnt], buffer );
5026
5027 //Make it look nice
5028 str_decode( mnu_GameTip.hint[cnt], SDL_arraysize( mnu_GameTip.hint[cnt] ), mnu_GameTip.hint[cnt] );
5029 //str_add_linebreaks( mnu_GameTip.hint[cnt], SDL_arraysize( mnu_GameTip.hint[cnt] ), 50 );
5030
5031 //Keep track of how many we have total
5032 mnu_GameTip.count++;
5033 }
5034 }
5035
5036 vfs_close( fileread );
5037 }
5038
5039 //--------------------------------------------------------------------------------------------
mnu_GameTip_load_local_vfs()5040 bool_t mnu_GameTip_load_local_vfs()
5041 {
5042 /// ZF@> This function loads all module specific hints and tips. If this fails, the game will
5043 // default to the global hints and tips instead
5044
5045 STRING buffer;
5046 vfs_FILE *fileread;
5047 Uint8 cnt;
5048
5049 // reset the count
5050 mnu_GameTip.local_count = 0;
5051
5052 // Open all the tips
5053 snprintf( buffer, SDL_arraysize( buffer ), "mp_modules/%s/gamedat/gametips.txt", pickedmodule_name );
5054 fileread = vfs_openRead( buffer );
5055 if ( NULL == fileread ) return bfalse;
5056
5057 // Load the data
5058 for ( cnt = 0; cnt < MENU_MAX_GAMETIPS && !vfs_eof( fileread ); cnt++ )
5059 {
5060 if ( goto_colon( NULL, fileread, btrue ) )
5061 {
5062 //Read the line
5063 fget_string( fileread, buffer, SDL_arraysize( buffer ) );
5064 strcpy( mnu_GameTip.local_hint[cnt], buffer );
5065
5066 //Make it look nice
5067 str_decode( mnu_GameTip.local_hint[cnt], SDL_arraysize( mnu_GameTip.local_hint[cnt] ), mnu_GameTip.local_hint[cnt] );
5068 //str_add_linebreaks( mnu_GameTip.local_hint[cnt], SDL_arraysize( mnu_GameTip.local_hint[cnt] ), 50 );
5069
5070 //Keep track of how many we have total
5071 mnu_GameTip.local_count++;
5072 }
5073 }
5074
5075 vfs_close( fileread );
5076
5077 return mnu_GameTip.local_count > 0;
5078 }
5079
5080 //--------------------------------------------------------------------------------------------
5081 // Implementation of the mnu_SlidyButton array
5082 //--------------------------------------------------------------------------------------------
mnu_SlidyButton_init(float lerp,const char * button_text[])5083 void mnu_SlidyButton_init( float lerp, const char *button_text[] )
5084 {
5085 int i;
5086
5087 autoformat_init_slidy_buttons();
5088
5089 // Figure out where to draw the buttons
5090 for ( i = 0; button_text[i][0] != 0; i++ )
5091 {
5092 buttonTop -= 35;
5093 }
5094
5095 mnu_SlidyButtonState.lerp = lerp;
5096 mnu_SlidyButtonState.buttons = ( char** )button_text;
5097 }
5098
5099 //--------------------------------------------------------------------------------------------
mnu_SlidyButton_update_all(float deltaTime)5100 void mnu_SlidyButton_update_all( float deltaTime )
5101 {
5102 mnu_SlidyButtonState.lerp += ( deltaTime * 1.5f );
5103 }
5104
5105 //--------------------------------------------------------------------------------------------
mnu_SlidyButton_draw_all()5106 void mnu_SlidyButton_draw_all()
5107 {
5108 int i;
5109
5110 for ( i = 0; mnu_SlidyButtonState.buttons[i][0] != 0; i++ )
5111 {
5112 int x = buttonLeft - ( 360 - i * 35 ) * mnu_SlidyButtonState.lerp;
5113 int y = buttonTop + ( i * 35 );
5114
5115 ui_doButton( UI_Nothing, mnu_SlidyButtonState.buttons[i], NULL, x, y, 200, 30 );
5116 }
5117 }
5118
5119 //--------------------------------------------------------------------------------------------
5120 //--------------------------------------------------------------------------------------------
ChoosePlayer_ctor(ChoosePlayer_element_t * ptr)5121 ChoosePlayer_element_t * ChoosePlayer_ctor( ChoosePlayer_element_t * ptr )
5122 {
5123 if ( NULL == ptr ) return ptr;
5124
5125 ChoosePlayer_init( ptr );
5126
5127 return ptr;
5128 }
5129
5130 //--------------------------------------------------------------------------------------------
ChoosePlayer_dtor(ChoosePlayer_element_t * ptr)5131 ChoosePlayer_element_t * ChoosePlayer_dtor( ChoosePlayer_element_t * ptr )
5132 {
5133 if ( NULL == ptr ) return ptr;
5134
5135 ChoosePlayer_dealloc( ptr );
5136
5137 ChoosePlayer_init( ptr );
5138
5139 return ptr;
5140 }
5141
5142 //--------------------------------------------------------------------------------------------
ChoosePlayer_init(ChoosePlayer_element_t * ptr)5143 bool_t ChoosePlayer_init( ChoosePlayer_element_t * ptr )
5144 {
5145 if ( NULL == ptr ) return bfalse;
5146
5147 memset( ptr, 0, sizeof( *ptr ) );
5148
5149 ptr->cap_ref = MAX_CAP;
5150 ptr->tx_ref = INVALID_TX_TEXTURE;
5151 ptr->skin_ref = NO_SKIN_OVERRIDE;
5152
5153 chop_definition_init( &( ptr->chop ) );
5154
5155 return btrue;
5156 }
5157
5158 //--------------------------------------------------------------------------------------------
ChoosePlayer_dealloc(ChoosePlayer_element_t * ptr)5159 bool_t ChoosePlayer_dealloc( ChoosePlayer_element_t * ptr )
5160 {
5161 // release all allocated resources
5162
5163 if ( MAX_CAP != ptr->cap_ref )
5164 {
5165 release_one_cap( ptr->cap_ref );
5166 }
5167 ptr->cap_ref = MAX_CAP;
5168
5169 if ( INVALID_TX_TEXTURE != ptr->tx_ref )
5170 {
5171 TxTexture_free_one( ptr->tx_ref );
5172 }
5173 ptr->tx_ref = INVALID_TX_TEXTURE;
5174
5175 return btrue;
5176 }
5177
5178 //--------------------------------------------------------------------------------------------
5179 //--------------------------------------------------------------------------------------------
ChoosePlayer_list_dealloc(ChoosePlayer_list_t * chooseplayer)5180 ChoosePlayer_list_t * ChoosePlayer_list_dealloc( ChoosePlayer_list_t * chooseplayer )
5181 {
5182 int i;
5183 ChoosePlayer_element_t * chooseplayer_ptr;
5184
5185 if ( NULL == chooseplayer ) return chooseplayer;
5186
5187 // release any data that we have accumulated
5188 for ( i = 0; i < chooseplayer->count; i++ )
5189 {
5190 chooseplayer_ptr = chooseplayer->lst + i;
5191
5192 // don't release the first index, since we don't own that one
5193 if ( 0 == i )
5194 {
5195 ChoosePlayer_init( chooseplayer_ptr );
5196 }
5197 else
5198 {
5199 ChoosePlayer_dtor( chooseplayer_ptr );
5200 }
5201 }
5202 chooseplayer->count = 0;
5203
5204 return chooseplayer;
5205 }
5206
5207 //--------------------------------------------------------------------------------------------
5208 // Implementation of the mnu_loadplayer array
5209 //--------------------------------------------------------------------------------------------
LoadPlayer_list_init(LoadPlayer_list_t * lst)5210 egoboo_rv LoadPlayer_list_init( LoadPlayer_list_t * lst )
5211 {
5212 if ( NULL == lst ) return rv_error;
5213
5214 // restart from nothing
5215 LoadPlayer_list_dealloc( lst );
5216
5217 chop_data_init( &chop_mem );
5218
5219 return rv_success;
5220 }
5221
5222 //--------------------------------------------------------------------------------------------
LoadPlayer_list_import_one(LoadPlayer_list_t * lst,const char * foundfile)5223 egoboo_rv LoadPlayer_list_import_one( LoadPlayer_list_t * lst, const char * foundfile )
5224 {
5225 STRING filename;
5226 int slot;
5227
5228 CAP_REF icap = MAX_CAP;
5229 cap_t * pcap = NULL;
5230
5231 LoadPlayer_element_t * ptr = NULL;
5232 int idx = MAX_LOADPLAYER;
5233
5234 // valid mnu_loadplayer list?
5235 if ( NULL == lst ) return rv_error;
5236
5237 // is it a valid filename?
5238 if ( !VALID_CSTR( foundfile ) ) return rv_error;
5239
5240 // does the directory exist?
5241 if ( lst->count >= MAX_LOADPLAYER ) return rv_fail;
5242
5243 // does the directory exist?
5244 if ( !vfs_exists( foundfile ) ) return rv_fail;
5245
5246 // offset the slots so that ChoosePlayer will have space to load the inventory objects
5247 slot = ( MAXIMPORTOBJECTS + 2 ) + lst->count;
5248
5249 // try to load the character profile
5250 icap = load_one_character_profile_vfs( foundfile, slot, bfalse );
5251 if ( !LOADED_CAP( icap ) ) return rv_fail;
5252 pcap = CapStack.lst + icap;
5253
5254 // get the next index
5255 idx = LoadPlayer_list_get_free( lst );
5256 if ( idx < 0 ) return rv_fail;
5257
5258 // grab a valid mnu_loadplayer pointer
5259 ptr = lst->lst + idx;
5260
5261 // set the player directory
5262 snprintf( ptr->dir, SDL_arraysize( ptr->dir ), "%s", str_convert_slash_net(( char* )foundfile, strlen( foundfile ) ) );
5263
5264 // set the loaded character profile for this object
5265 ptr->cap_ref = icap;
5266
5267 // read in the skin from "skin.txt"
5268 // We are no longer supporting skin.txt. Use the [SKIN] expansion, instead
5269 //snprintf( filename, SDL_arraysize( filename ), "%s/skin.txt", foundfile );
5270 //ptr->skin_ref = read_skin_vfs( filename );
5271
5272 // get the skin from the [SKIN] expansion in the character profile
5273 ptr->skin_ref = pcap->skin_override % MAX_SKIN;
5274 ptr->skin_ref = CLIP( ptr->skin_ref, 0, MAX_SKIN - 1 );
5275
5276 // don't load in the md2 at this time
5277 //snprintf( filename, SDL_arraysize(filename), "%s" SLASH_STR "tris.md2", foundfile );
5278 //md2_load_one( vfs_resolveReadFilename(filename), &(MadStack.lst[idx].md2_data) );
5279
5280 // load in just the one icon
5281 snprintf( filename, SDL_arraysize( filename ), "%s/icon%d", foundfile, ptr->skin_ref );
5282 ptr->tx_ref = TxTexture_load_one_vfs( filename, ( TX_REF )INVALID_TX_TEXTURE, INVALID_KEY );
5283
5284 // load the quest info from "quest.txt" so we can determine the valid modules
5285 snprintf( ptr->dir, SDL_arraysize( ptr->dir ), "%s", str_convert_slash_net(( char* )foundfile, strlen( foundfile ) ) );
5286 quest_log_download_vfs( ptr->quest_log, SDL_arraysize( ptr->quest_log ), ptr->dir );
5287
5288 // load the chop data from "naming.txt" to generate the character name
5289 snprintf( filename, SDL_arraysize( filename ), "%s/naming.txt", foundfile );
5290 chop_load_vfs( &chop_mem, filename, &( ptr->chop ) );
5291
5292 // generate the name from the chop
5293 snprintf( ptr->name, SDL_arraysize( ptr->name ), "%s", chop_create( &chop_mem, &( ptr->chop ) ) );
5294
5295 return rv_success;
5296 }
5297
5298 //--------------------------------------------------------------------------------------------
LoadPlayer_list_get_free(LoadPlayer_list_t * lst)5299 int LoadPlayer_list_get_free( LoadPlayer_list_t * lst )
5300 {
5301 int idx = -1;
5302
5303 if ( NULL == lst ) return -1;
5304
5305 // are there any loadplayers left?
5306 if ( lst->count >= MAX_LOADPLAYER ) return -1;
5307
5308 // grab the next one
5309 idx = lst->count;
5310 lst->count++;
5311
5312 return idx;
5313 }
5314
5315 //--------------------------------------------------------------------------------------------
LoadPlayer_list_get_ptr(LoadPlayer_list_t * lst,int idx)5316 LoadPlayer_element_t * LoadPlayer_list_get_ptr( LoadPlayer_list_t * lst, int idx )
5317 {
5318
5319 if ( !VALID_LOADPLAYER_IDX( mnu_loadplayer, idx ) ) return NULL;
5320
5321 return lst->lst + idx;
5322 }
5323
5324 //--------------------------------------------------------------------------------------------
LoadPlayer_list_dealloc(LoadPlayer_list_t * lst)5325 egoboo_rv LoadPlayer_list_dealloc( LoadPlayer_list_t * lst )
5326 {
5327 int i;
5328
5329 if ( NULL == lst ) return rv_error;
5330
5331 if ( 0 == lst->count ) return rv_success;
5332
5333 lst->count = MIN( lst->count, MAX_LOADPLAYER );
5334 for ( i = 0; i < lst->count; i++ )
5335 {
5336 LoadPlayer_element_dtor( lst->lst + i );
5337 }
5338 lst->count = 0;
5339
5340 return rv_success;
5341 }
5342
5343 //--------------------------------------------------------------------------------------------
LoadPlayer_list_import_all(LoadPlayer_list_t * lst,const char * dirname,bool_t initialize)5344 egoboo_rv LoadPlayer_list_import_all( LoadPlayer_list_t * lst, const char *dirname, bool_t initialize )
5345 {
5346 /// @details ZZ@> This function figures out which players may be imported, and loads basic
5347 /// data for each
5348
5349 vfs_search_context_t * ctxt;
5350 const char *foundfile;
5351
5352 if ( NULL == lst ) return rv_error;
5353
5354 if ( initialize )
5355 {
5356 LoadPlayer_list_init( lst );
5357 };
5358
5359 // Search for all objects
5360 ctxt = vfs_findFirst( dirname, "obj", VFS_SEARCH_DIR );
5361 foundfile = vfs_search_context_get_current( ctxt );
5362
5363 while ( NULL != ctxt && VALID_CSTR( foundfile ) && lst->count < MAX_LOADPLAYER )
5364 {
5365 LoadPlayer_list_import_one( lst, foundfile );
5366
5367 ctxt = vfs_findNext( &ctxt );
5368 foundfile = vfs_search_context_get_current( ctxt );
5369 }
5370 vfs_findClose( &ctxt );
5371
5372 return rv_success;
5373 }
5374
5375 //--------------------------------------------------------------------------------------------
LoadPlayer_list_from_players(LoadPlayer_list_t * lst)5376 egoboo_rv LoadPlayer_list_from_players( LoadPlayer_list_t * lst )
5377 {
5378 int ipla;
5379 chr_t * pchr;
5380 pro_t * ppro;
5381 player_t * ppla;
5382
5383 int lp_idx;
5384 LoadPlayer_element_t * lp_ptr;
5385
5386 if ( NULL == lst || 0 != lst->count ) return rv_error;
5387
5388 for ( ipla = 0; ipla < MAX_PLAYER; ipla++ )
5389 {
5390 ppla = PlaStack.lst + ipla;
5391 if ( !ppla->valid ) continue;
5392
5393 if ( !INGAME_CHR( ppla->index ) ) continue;
5394 pchr = ChrList.lst + ppla->index;
5395
5396 if ( !LOADED_PRO( pchr->profile_ref ) )continue;
5397 ppro = ProList.lst + pchr->profile_ref;
5398
5399 // grab a free LoadPlayer_element_t
5400 lp_idx = LoadPlayer_list_get_free( lst );
5401 if ( lp_idx < 0 ) break;
5402
5403 lp_ptr = lst->lst + lp_idx;
5404
5405 // fill up the data from the player's info
5406 strncpy( lp_ptr->name, pchr->Name, SDL_arraysize( lp_ptr->name ) );
5407 strncpy( lp_ptr->dir, pchr->obj_base._name, SDL_arraysize( lp_ptr->name ) );
5408
5409 lp_ptr->cap_ref = pro_get_icap( pchr->profile_ref );
5410 lp_ptr->skin_ref = pchr->skin;
5411 lp_ptr->tx_ref = pchr->inst.texture;
5412
5413 memmove( lp_ptr->quest_log, ppla->quest_log, sizeof( lp_ptr->quest_log ) );
5414 memmove( &( lp_ptr->chop ), &( ppro->chop ), sizeof( lp_ptr->chop ) );
5415 }
5416
5417 return ( lst->count > 0 ) ? rv_success : rv_fail;
5418 }
5419
5420 //--------------------------------------------------------------------------------------------
5421 //--------------------------------------------------------------------------------------------
LoadPlayer_element_ctor(LoadPlayer_element_t * ptr)5422 LoadPlayer_element_t * LoadPlayer_element_ctor( LoadPlayer_element_t * ptr )
5423 {
5424 if ( NULL == ptr ) return ptr;
5425
5426 LoadPlayer_element_init( ptr );
5427
5428 return ptr;
5429 }
5430
5431 //--------------------------------------------------------------------------------------------
LoadPlayer_element_dtor(LoadPlayer_element_t * ptr)5432 LoadPlayer_element_t * LoadPlayer_element_dtor( LoadPlayer_element_t * ptr )
5433 {
5434 if ( NULL == ptr ) return ptr;
5435
5436 LoadPlayer_element_dealloc( ptr );
5437 LoadPlayer_element_init( ptr );
5438
5439 return ptr;
5440 }
5441
5442 //--------------------------------------------------------------------------------------------
LoadPlayer_element_dealloc(LoadPlayer_element_t * ptr)5443 bool_t LoadPlayer_element_dealloc( LoadPlayer_element_t * ptr )
5444 {
5445 if ( NULL == ptr ) return bfalse;
5446
5447 // release the cap
5448 if ( MAX_CAP != ptr->cap_ref )
5449 {
5450 release_one_cap( ptr->cap_ref );
5451 }
5452 ptr->cap_ref = MAX_CAP;
5453
5454 // release the texture
5455 if ( INVALID_TX_TEXTURE != ptr->tx_ref )
5456 {
5457 TxTexture_free_one( ptr->tx_ref );
5458 }
5459 ptr->tx_ref = INVALID_TX_TEXTURE;
5460
5461 return btrue;
5462 }
5463
5464 //--------------------------------------------------------------------------------------------
LoadPlayer_element_init(LoadPlayer_element_t * ptr)5465 bool_t LoadPlayer_element_init( LoadPlayer_element_t * ptr )
5466 {
5467 if ( NULL == ptr ) return bfalse;
5468
5469 memset( ptr, 0, sizeof( *ptr ) );
5470
5471 // set the non-zero, non-null values
5472 ptr->cap_ref = MAX_CAP;
5473 ptr->tx_ref = INVALID_TX_TEXTURE;
5474
5475 idsz_map_init( ptr->quest_log, MAX_IDSZ_MAP_SIZE );
5476 chop_definition_init( &( ptr->chop ) );
5477
5478 return btrue;
5479 }
5480
5481 //--------------------------------------------------------------------------------------------
5482 //--------------------------------------------------------------------------------------------
mnu_set_selected_list(LoadPlayer_list_t * dst,LoadPlayer_list_t * src,SelectedPlayer_list_t * sp_lst)5483 egoboo_rv mnu_set_selected_list( LoadPlayer_list_t * dst, LoadPlayer_list_t * src, SelectedPlayer_list_t * sp_lst )
5484 {
5485 int src_idx = -1;
5486 LoadPlayer_element_t * src_ptr = NULL;
5487 LoadPlayer_element_t * dst_ptr = NULL;
5488
5489 int selectedplayer_idx;
5490 SelectedPlayer_element_t * selectedplayer_ptr = NULL;
5491
5492 if ( NULL == src || NULL == dst || NULL == sp_lst ) return rv_error;
5493
5494 // blank out any existing data
5495 LoadPlayer_list_init( dst );
5496
5497 if ( 0 == src->count || 0 == sp_lst->count ) return rv_success;
5498
5499 // loop through the selected players and store all the valid data in the list of imported players
5500 for ( selectedplayer_idx = 0; selectedplayer_idx < sp_lst->count; selectedplayer_idx++ )
5501 {
5502 // grab a pointer to the selectedplayer data
5503 selectedplayer_ptr = sp_lst->lst + selectedplayer_idx;
5504
5505 // does the loadplayer exist?
5506 src_idx = selectedplayer_ptr->player;
5507 if ( !VALID_LOADPLAYER_IDX( *src, src_idx ) ) continue;
5508
5509 // grab the loadplayer info
5510 src_ptr = src->lst + src_idx;
5511
5512 // get a new import data pointer
5513 dst_ptr = dst->lst + dst->count;
5514 dst->count++;
5515
5516 // copy the data over
5517 memcpy( dst_ptr, src_ptr, sizeof( *dst_ptr ) );
5518 }
5519
5520 return ( dst->count > 0 ) ? rv_success : rv_fail;
5521 }
5522
5523 //--------------------------------------------------------------------------------------------
mnu_set_local_import_list(Import_list_t * imp_lst,SelectedPlayer_list_t * sp_lst)5524 egoboo_rv mnu_set_local_import_list( Import_list_t * imp_lst, SelectedPlayer_list_t * sp_lst )
5525 {
5526 int import_idx;
5527 Import_element_t * import_ptr = NULL;
5528
5529 int loadplayer_idx = -1;
5530 LoadPlayer_element_t * loadplayer_ptr = NULL;
5531
5532 int selectedplayer_idx;
5533 SelectedPlayer_element_t * selectedplayer_ptr = NULL;
5534
5535 if ( NULL == imp_lst || NULL == sp_lst ) return rv_error;
5536
5537 // blank out any existing data
5538 Import_list_init( imp_lst );
5539
5540 // loop through the selected players and store all the valid data in the list of imported players
5541 for ( selectedplayer_idx = 0; selectedplayer_idx < sp_lst->count; selectedplayer_idx++ )
5542 {
5543 // grab a pointer to the selectedplayer data
5544 selectedplayer_ptr = sp_lst->lst + selectedplayer_idx;
5545
5546 // does the loadplayer exist?
5547 loadplayer_idx = selectedplayer_ptr->player;
5548 if ( !VALID_LOADPLAYER_IDX( mnu_loadplayer, loadplayer_idx ) ) continue;
5549
5550 // grab the loadplayer info
5551 loadplayer_ptr = mnu_loadplayer.lst + loadplayer_idx;
5552
5553 // get a new import data pointer
5554 import_idx = imp_lst->count;
5555 import_ptr = imp_lst->lst + imp_lst->count;
5556 imp_lst->count++;
5557
5558 // set the import info
5559 import_ptr->bits = selectedplayer_ptr->input;
5560 import_ptr->slot = selectedplayer_idx * MAXIMPORTPERPLAYER;
5561 import_ptr->player = selectedplayer_idx;
5562
5563 strncpy( import_ptr->srcDir, loadplayer_ptr->dir, SDL_arraysize( import_ptr->srcDir ) );
5564 import_ptr->dstDir[0] = CSTR_END;
5565 }
5566
5567 return ( imp_lst->count > 0 ) ? rv_success : rv_fail;
5568 }
5569
5570 //--------------------------------------------------------------------------------------------
SelectedPlayer_element_init(SelectedPlayer_element_t * ptr)5571 egoboo_rv SelectedPlayer_element_init( SelectedPlayer_element_t * ptr )
5572 {
5573 if ( NULL == ptr ) return rv_error;
5574
5575 memset( ptr, 0, sizeof( *ptr ) );
5576
5577 // the non-zero, non-null values
5578 ptr->player = MAX_PLAYER;
5579
5580 return rv_success;
5581 }
5582
5583 //--------------------------------------------------------------------------------------------
5584 // implementation of SelectedPlayer_list_t
5585 //--------------------------------------------------------------------------------------------
SelectedPlayer_list_init(SelectedPlayer_list_t * sp_lst)5586 egoboo_rv SelectedPlayer_list_init( SelectedPlayer_list_t * sp_lst )
5587 {
5588 int cnt;
5589
5590 if ( NULL == sp_lst ) return rv_error;
5591
5592 for ( cnt = 0; cnt < MAX_PLAYER; cnt++ )
5593 {
5594 SelectedPlayer_element_init( sp_lst->lst + cnt );
5595 }
5596 sp_lst->count = 0;
5597
5598 return rv_success;
5599 }
5600
5601 //--------------------------------------------------------------------------------------------
SelectedPlayer_list_check_loadplayer(SelectedPlayer_list_t * sp_lst,int loadplayer_idx)5602 bool_t SelectedPlayer_list_check_loadplayer( SelectedPlayer_list_t * sp_lst, int loadplayer_idx )
5603 {
5604 int i;
5605
5606 if ( !VALID_LOADPLAYER_IDX( mnu_loadplayer, loadplayer_idx ) ) return bfalse;
5607
5608 for ( i = 0; i < MAX_PLAYER && i < sp_lst->count; i++ )
5609 {
5610 if ( sp_lst->lst[i].player == loadplayer_idx ) return btrue;
5611 }
5612
5613 return bfalse;
5614 }
5615
5616 //--------------------------------------------------------------------------------------------
SelectedPlayer_list_index_from_loadplayer(SelectedPlayer_list_t * sp_lst,int loadplayer_idx)5617 int SelectedPlayer_list_index_from_loadplayer( SelectedPlayer_list_t * sp_lst, int loadplayer_idx )
5618 {
5619 int cnt, selected_index;
5620
5621 if ( !VALID_LOADPLAYER_IDX( mnu_loadplayer, loadplayer_idx ) ) return INVALID_PLAYER;
5622
5623 selected_index = INVALID_PLAYER;
5624 for ( cnt = 0; cnt < MAX_PLAYER && cnt < sp_lst->count; cnt++ )
5625 {
5626 if ( sp_lst->lst[ cnt ].player == loadplayer_idx )
5627 {
5628 selected_index = cnt;
5629 break;
5630 }
5631 }
5632
5633 return selected_index;
5634 }
5635
5636 //--------------------------------------------------------------------------------------------
SelectedPlayer_list_add(SelectedPlayer_list_t * sp_lst,int loadplayer_idx)5637 bool_t SelectedPlayer_list_add( SelectedPlayer_list_t * sp_lst, int loadplayer_idx )
5638 {
5639 if ( !VALID_LOADPLAYER_IDX( mnu_loadplayer, loadplayer_idx ) || sp_lst->count >= MAX_PLAYER ) return bfalse;
5640 if ( SelectedPlayer_list_check_loadplayer( sp_lst, loadplayer_idx ) ) return bfalse;
5641
5642 sp_lst->lst[sp_lst->count].player = loadplayer_idx;
5643 sp_lst->lst[sp_lst->count].input = INPUT_BITS_NONE;
5644 sp_lst->count++;
5645
5646 return btrue;
5647 }
5648
5649 //--------------------------------------------------------------------------------------------
SelectedPlayer_list_remove(SelectedPlayer_list_t * sp_lst,int loadplayer_idx)5650 bool_t SelectedPlayer_list_remove( SelectedPlayer_list_t * sp_lst, int loadplayer_idx )
5651 {
5652 int i;
5653 bool_t found = bfalse;
5654
5655 if ( !VALID_LOADPLAYER_IDX( mnu_loadplayer, loadplayer_idx ) || sp_lst->count <= 0 ) return bfalse;
5656
5657 if ( 1 == sp_lst->count )
5658 {
5659 if ( sp_lst->lst[0].player == loadplayer_idx )
5660 {
5661 sp_lst->count = 0;
5662 }
5663 }
5664 else
5665 {
5666 for ( i = 0; i < MAX_PLAYER && i < sp_lst->count; i++ )
5667 {
5668 if ( sp_lst->lst[i].player == loadplayer_idx )
5669 {
5670 found = btrue;
5671 break;
5672 }
5673 }
5674
5675 if ( found )
5676 {
5677 i++;
5678 for ( /* nothing */; i < MAX_PLAYER && i < sp_lst->count; i++ )
5679 {
5680 sp_lst->lst[i-1].player = sp_lst->lst[i].player;
5681 sp_lst->lst[i-1].input = sp_lst->lst[i].input;
5682 }
5683
5684 sp_lst->count--;
5685 }
5686 };
5687
5688 return found;
5689 }
5690
5691 //--------------------------------------------------------------------------------------------
SelectedPlayer_list_add_input(SelectedPlayer_list_t * sp_lst,int loadplayer_idx,BIT_FIELD input_bits)5692 bool_t SelectedPlayer_list_add_input( SelectedPlayer_list_t * sp_lst, int loadplayer_idx, BIT_FIELD input_bits )
5693 {
5694 int i;
5695 bool_t done, retval = bfalse;
5696
5697 int selected_index = -1;
5698
5699 for ( i = 0; i < sp_lst->count; i++ )
5700 {
5701 if ( sp_lst->lst[i].player == loadplayer_idx )
5702 {
5703 selected_index = i;
5704 break;
5705 }
5706 }
5707
5708 if ( -1 == selected_index )
5709 {
5710 SelectedPlayer_list_add( sp_lst, loadplayer_idx );
5711 }
5712
5713 if ( selected_index >= 0 && selected_index < sp_lst->count )
5714 {
5715 for ( i = 0; i < sp_lst->count; i++ )
5716 {
5717 if ( i == selected_index )
5718 {
5719 // add in the selected bits for the selected loadplayer_idx
5720 SET_BIT( sp_lst->lst[i].input, input_bits );
5721 retval = btrue;
5722 }
5723 else
5724 {
5725 // remove the selectd bits from all other players
5726 UNSET_BIT( sp_lst->lst[i].input, input_bits );
5727 }
5728 }
5729 }
5730
5731 // Do the tricky part of removing all players with invalid inputs from the list
5732 // It is tricky because removing a loadplayer_idx changes the value of the loop control
5733 // value sp_lst->count within the loop.
5734 done = bfalse;
5735 while ( !done )
5736 {
5737 // assume the best
5738 done = btrue;
5739
5740 for ( i = 0; i < sp_lst->count; i++ )
5741 {
5742 if ( INPUT_BITS_NONE == sp_lst->lst[i].input )
5743 {
5744 // we found one
5745 done = bfalse;
5746 SelectedPlayer_list_remove( sp_lst, sp_lst->lst[i].player );
5747 }
5748 }
5749 }
5750
5751 return retval;
5752 }
5753
5754 //--------------------------------------------------------------------------------------------
SelectedPlayer_list_remove_input(SelectedPlayer_list_t * sp_lst,int loadplayer_idx,Uint32 input_bits)5755 bool_t SelectedPlayer_list_remove_input( SelectedPlayer_list_t * sp_lst, int loadplayer_idx, Uint32 input_bits )
5756 {
5757 int i;
5758 bool_t retval = bfalse;
5759
5760 for ( i = 0; i < MAX_PLAYER && i < sp_lst->count; i++ )
5761 {
5762 if ( sp_lst->lst[i].player == loadplayer_idx )
5763 {
5764 UNSET_BIT( sp_lst->lst[i].input, input_bits );
5765
5766 // This part is not so tricky as in SelectedPlayer_list_add_input.
5767 // Even though we are modding the loop control variable, it is never
5768 // tested in the loop because we are using the break command to
5769 // break out of the loop immediately
5770
5771 if ( INPUT_BITS_NONE == sp_lst->lst[i].input )
5772 {
5773 SelectedPlayer_list_remove( sp_lst, loadplayer_idx );
5774 }
5775
5776 retval = btrue;
5777
5778 break;
5779 }
5780 }
5781
5782 return retval;
5783 }
5784