2 * $Logfile: /Freespace2/code/MenuUI/MainHallMenu.cpp $
7 * Header file for main-hall menu code
10 * Revision 1.1 2002/05/03 03:28:09 root
14 * 62 10/28/99 2:04a Jefff
17 * 61 9/15/99 6:28p Dave
18 * No load mission button in RELEASE_REAL
20 * 60 9/13/99 4:52p Dave
23 * 59 9/13/99 11:30a Dave
24 * Added checkboxes and functionality for disabling PXO banners as well as
25 * disabling d3d zbuffer biasing.
27 * 58 9/07/99 6:55p Jefff
28 * added jump-to-campaign-mission cheat
30 * 57 9/07/99 4:01p Dave
31 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
32 * does everything properly (setting up address when binding). Remove
33 * black rectangle background from UI_INPUTBOX.
35 * 56 9/06/99 6:38p Dave
36 * Improved CD detection code.
38 * 55 9/06/99 1:30a Dave
39 * Intermediate checkin. Started on enforcing CD-in-drive to play the
42 * 54 9/03/99 1:31a Dave
43 * CD checking by act. Added support to play 2 cutscenes in a row
44 * seamlessly. Fixed super low level cfile bug related to files in the
45 * root directory of a CD. Added cheat code to set campaign mission # in
48 * 53 9/01/99 11:02p Dave
49 * Made head guy look right when not animating.
51 * 52 8/27/99 12:04a Dave
52 * Campaign loop screen.
54 * 51 8/26/99 9:45a Dave
55 * First pass at easter eggs and cheats.
57 * 50 8/25/99 11:57a Jefff
58 * freespace -> freespace 2 in tooltip strings
60 * 49 8/25/99 10:50a Dave
61 * Added music to the mainhall.tbl
63 * 48 8/24/99 8:55p Dave
64 * Make sure nondimming pixels work properly in tech menu.
66 * 47 8/18/99 11:44a Jefff
69 * 46 8/10/99 4:45p Jefff
72 * 45 8/06/99 1:01p Andsager
73 * disable quick start (g) for demo
75 * 44 8/05/99 10:34a Jefff
76 * more mouseover sound fixes
78 * 43 8/04/99 9:12p Andsager
79 * Add campaign room popup allowing restart of campaign in demo.
81 * 42 8/04/99 5:36p Dave
82 * Make glide and D3D switch out properly.
84 * 41 8/04/99 4:35p Jefff
85 * fixed tech room & options sounds playing only once
87 * 40 8/03/99 5:41p Jefff
88 * made "f1 for help" draw after animations, and stop if help overlay
91 * 39 8/03/99 4:42p Jefff
94 * 38 8/03/99 3:48p Jefff
96 * 37 8/02/99 9:13p Dave
99 * 36 8/02/99 2:26p Jefff
100 * "press f1.." text reworked
102 * 35 8/02/99 12:19p Andsager
103 * disable "L" load screen
105 * 34 8/02/99 11:12a Jefff
106 * adjusted tooltip shader stuff for more a more pleasing effect.
108 * 33 7/30/99 6:05p Jefff
109 * added shader behind tooltip text
111 * 32 7/30/99 4:20p Andsager
112 * Added user click sounds to main hall
114 * 31 7/29/99 10:47p Dave
115 * Standardized D3D fogging using vertex fog. Shook out Savage 4 bugs.
117 * 30 7/27/99 6:53p Dave
118 * Hi-res main hall support.
120 * 29 7/16/99 1:49p Dave
121 * 8 bit aabitmaps. yay.
123 * 28 7/15/99 9:20a Andsager
124 * FS2_DEMO initial checkin
126 * 27 7/13/99 1:15p Dave
127 * 32 bit support. Whee!
129 * 26 6/25/99 2:51p Jasons
130 * Changed wording of network error message.
132 * 25 6/21/99 1:30p Alanl
133 * changed main menu music tag
135 * 24 6/19/99 3:56p Dave
136 * Moved main hall definitions into a table file. Whee!
138 * 23 6/11/99 11:13a Dave
139 * last minute changes before press tour build.
141 * 22 5/09/99 8:57p Dave
142 * Final E3 build preparations.
144 * 21 4/25/99 3:02p Dave
145 * Build defines for the E3 build.
147 * 20 4/12/99 10:07p Dave
148 * Made network startup more forgiving. Added checkmarks to dogfight
149 * screen for players who hit commit.
151 * 19 3/28/99 5:58p Dave
152 * Added early demo code. Make objects move. Nice and framerate
153 * independant, but not much else. Don't use yet unless you're me :)
155 * 18 3/25/99 5:47p Dave
158 * 17 3/19/99 9:51a Dave
159 * Checkin to repair massive source safe crash. Also added support for
160 * pof-style nebulae, and some new weapons code.
162 * 16 2/25/99 4:19p Dave
163 * Added multiplayer_beta defines. Added cd_check define. Fixed a few
164 * release build warnings. Added more data to the squad war request and
167 * 15 2/03/99 11:44a Dave
168 * Fixed d3d transparent textures.
170 * 14 1/30/99 5:08p Dave
171 * More new hi-res stuff.Support for nice D3D textures.
173 * 13 1/27/99 9:56a Dave
174 * Temporary checkin of beam weapons for Dan to make cool sounds.
176 * 12 12/31/98 11:23a Dave
177 * Put mini-indicators for status of ships.tbl and weapons.tbl in the
178 * lower left corner of the main hall.
180 * 11 12/18/98 1:13a Dave
181 * Rough 1024x768 support for Direct3D. Proper detection and usage through
184 * 10 11/30/98 1:07p Dave
185 * 16 bit conversion, first run.
187 * 9 11/20/98 4:08p Dave
188 * Fixed flak effect in multiplayer.
190 * 8 11/20/98 11:16a Dave
191 * Fixed up IPX support a bit. Making sure that switching modes and
192 * loading/saving pilot files maintains proper state.
194 * 7 11/19/98 4:57p Dave
195 * Ignore PXO option if IPX is selected.
197 * 6 11/19/98 4:19p Dave
198 * Put IPX sockets back in psnet. Consolidated all multiplayer config
201 * 5 11/05/98 5:55p Dave
202 * Big pass at reducing #includes
204 * 4 11/05/98 4:18p Dave
205 * First run nebula support. Beefed up localization a bit. Removed all
206 * conditional compiles for foreign versions. Modified mission file
209 * 3 10/13/98 9:28a Dave
210 * Started neatening up freespace.h. Many variables renamed and
211 * reorganized. Added AlphaColors.[h,cpp]
213 * 2 10/07/98 10:53a Dave
216 * 1 10/07/98 10:49a Dave
218 * 103 10/02/98 3:22p Allender
219 * fix up the -connect option and fix the -port option
221 * 102 8/20/98 5:31p Dave
222 * Put in handy multiplayer logfile system. Now need to put in useful
223 * applications of it all over the code.
225 * 101 8/07/98 10:40a Allender
226 * new command line flags for starting netgames. Only starting currently
227 * works, and PXO isn't implemented yet
229 * 100 7/13/98 10:46a Lawrance
230 * Index another localized string
232 * 99 7/10/98 1:13a Allender
233 * lots of small multiplayer update changes. Code in launcher to specify
234 * connection speed. A couple of small fixes regarding empty mission
235 * files. Time out players after 10 second when they don't connect on
236 * their reliable socket.
238 * 98 6/09/98 10:31a Hoffoss
239 * Created index numbers for all xstr() references. Any new xstr() stuff
240 * added from here on out should be added to the end if the list. The
241 * current list count can be found in FreeSpace.cpp (search for
244 * 97 6/05/98 9:50a Lawrance
247 * 96 6/01/98 11:43a John
248 * JAS & MK: Classified all strings for localization.
250 * 95 5/22/98 9:02p Allender
251 * remove G key from main hall
253 * 94 5/22/98 10:54a Allender
254 * new dialog information for networking to tell user if connection type
255 * doesn't match the setup specified type
257 * 93 5/15/98 5:15p Dave
258 * Fix a standalone resetting bug.Tweaked PXO interface. Display captaincy
259 * status for team vs. team. Put in asserts to check for invalid team vs.
262 * 92 5/13/98 12:23a Lawrance
263 * Don't init main hall if already inited... not needed now, but may be
264 * useful if we don't always want to call main_hall_close() when switching
267 * 91 5/12/98 2:46a Dave
268 * Rudimentary communication between Parallax Online and freespace. Can
269 * get and store channel lists.
271 * 90 5/08/98 5:33p Lawrance
272 * check for CD when trying to enter ready room in single player
279 #include "mainhallmenu.h"
283 #include "gamesequence.h"
284 #include "animplay.h"
288 #include "snazzyui.h"
290 #include "audiostr.h"
292 #include "eventmusic.h"
294 #include "contexthelp.h"
298 #include "multiutil.h"
302 #include "playermenu.h"
303 #include "freespace.h"
304 #include "multi_voice.h"
306 #include "alphacolors.h"
308 #include "fishtank.h"
310 // #include "movie.h"
312 // ----------------------------------------------------------------------------
313 // MAIN HALL DATA DEFINES
315 #define MAX_RANDOM_INTERCOM_SOUNDS 10
316 #define NUM_RANDOM_INTERCOM_SOUNDS_0 3
317 #define NUM_RANDOM_INTERCOM_SOUNDS_1 3
319 #define MAX_MISC_ANIMATIONS 10
320 #define NUM_MISC_ANIMATIONS_0 2
321 #define NUM_MISC_ANIMATIONS_1 4
323 #define MAX_DOOR_ANIMATIONS 10
324 #define NUM_DOOR_ANIMATIONS_0 6
325 #define NUM_DOOR_ANIMATIONS_1 6
327 #define MAX_DOOR_SOUNDS 10
328 #define NUM_DOOR_SOUNDS_0 6
329 #define NUM_DOOR_SOUNDS_1 6
331 #define MISC_ANIM_MODE_LOOP 0 // loop the animation
332 #define MISC_ANIM_MODE_HOLD 1 // play to the end and hold the animation
333 #define MISC_ANIM_MODE_TIMED 2 // uses timestamps to determine when a finished anim should be checked again
335 #define NUM_REGIONS 7 // (6 + 1 for multiplayer equivalent of campaign room)
336 typedef struct main_hall_defines {
338 char bitmap[MAX_FILENAME_LEN+1];
339 char mask[MAX_FILENAME_LEN+1];
342 char music[MAX_FILENAME_LEN+1];
344 // intercom defines -------------------
346 // # of intercom sounds
347 int num_random_intercom_sounds;
349 // random (min/max) delays between playing intercom sounds
350 int intercom_delay[MAX_RANDOM_INTERCOM_SOUNDS][2];
352 // intercom sounds themselves
353 int intercom_sounds[MAX_RANDOM_INTERCOM_SOUNDS];
355 // intercom sound pan values
356 float intercom_sound_pan[MAX_RANDOM_INTERCOM_SOUNDS];
359 // misc animations --------------------
361 // # of misc animations
362 int num_misc_animations;
364 // filenames of the misc animations
365 char misc_anim_name[MAX_MISC_ANIMATIONS][MAX_FILENAME_LEN+1];
367 // Time until we will next play a given misc animation, min delay, and max delay
368 int misc_anim_delay[MAX_MISC_ANIMATIONS][3];
370 // coords of where to play the misc anim
371 int misc_anim_coords[MAX_MISC_ANIMATIONS][2];
373 // misc anim play modes (see MISC_ANIM_MODE_* above)
374 int misc_anim_modes[MAX_MISC_ANIMATIONS];
376 // panning values for each of the misc anims
377 float misc_anim_sound_pan[MAX_MISC_ANIMATIONS];
379 // [N][0] == # of sounds, [N][1-9] sound index
380 int misc_anim_special_sounds[MAX_MISC_ANIMATIONS][10];
382 // [N][0] == # of triggers, [N][1-9] >= frame num
383 int misc_anim_special_trigger[MAX_MISC_ANIMATIONS][10];
385 // [N][0] == # of handles, [N][1-9] == sound handle num
386 int misc_anim_sound_handles[MAX_MISC_ANIMATIONS][10];
388 // [N][0] == # of handles, [N][1-9] == sound "should" be playing
389 int misc_anim_sound_flag[MAX_MISC_ANIMATIONS][10];
392 // door animations --------------------
394 // # of door animations
395 int num_door_animations;
397 // filenames of the door animations
398 char door_anim_name[MAX_DOOR_ANIMATIONS][MAX_FILENAME_LEN+1];
400 // first pair : coords of where to play a given door anim
401 // second pair : center of a given door anim in windowed mode
402 int door_anim_coords[MAX_DOOR_ANIMATIONS][4];
405 // door sounds ------------------------
410 // sounds for each region (open/close)
411 int door_sounds[MAX_DOOR_SOUNDS][2];
413 // pan values for the door sounds
414 float door_sound_pan[MAX_DOOR_SOUNDS];
417 // region descriptions ----------------
419 // text (tooltip) description
420 char *region_descript[NUM_REGIONS];
422 // y coord of where to draw tooltip text
428 // use main hall 0 by default
429 main_hall_defines Main_hall_defines[GR_NUM_RESOLUTIONS][NUM_MAIN_HALLS];
430 main_hall_defines *Main_hall = &Main_hall_defines[0][0];
432 int Vasudan_funny = 0;
433 int Vasudan_funny_plate = -1;
435 char Main_hall_campaign_cheat[512] = "";
437 // ----------------------------------------------------------------------------
438 // MISC interface data
440 // is the main hall inited (for reentrancy)
441 int Main_hall_inited = 0;
443 // handle to the playing music
444 int Main_hall_music_handle = -1;
446 // background bitmap handle
447 int Main_hall_bitmap;
449 // background bitmap mask handle
452 // variable used for automatic netgame starting/joining
453 int Main_hall_netgame_started = 0;
455 // bitmap struct for th background mask bitmap
456 bitmap *Main_hall_mask_bitmap;
458 // actual data for the background mask bitmap
459 ubyte *Main_hall_mask_data;
461 int Main_hall_mask_w, Main_hall_mask_h;
464 // ----------------------------------------------------------------------------
465 // MOUSE clicking stuff
467 // indicates whether a right click occured
468 int Main_hall_right_click;
470 // use this to cycle through the selectable regions instead of the mouse's current region
471 int Main_hall_last_clicked_region;
473 // use this to determine how long the cursor has to linger on a region before it starts playing
474 #define MAIN_HALL_REGION_LINGER 175 // in ms
475 int Main_hall_region_linger_stamp = -1;
477 // handle any right clicks which may have occured
478 void main_hall_handle_right_clicks();
481 // ----------------------------------------------------------------------------
482 // RANDOM intercom sounds
485 // next random intercom sound to play
486 int Main_hall_next_intercom_sound = 0;
488 // delay for the next intercom sound
489 int Main_hall_next_intercom_sound_stamp = -1;
491 // handle to any playing instance of a random intercom sound
492 int Main_hall_intercom_sound_handle = -1;
494 // handle any details related to random intercom sounds
495 void main_hall_handle_random_intercom_sounds();
498 // ----------------------------------------------------------------------------
502 // the misc animations themselves
503 anim *Main_hall_misc_anim[MAX_MISC_ANIMATIONS];
505 // the instance of a given misc animation
506 anim_instance *Main_hall_misc_anim_instance[MAX_MISC_ANIMATIONS];
508 // handle starting, stopping and randomizing misc animations
509 void main_hall_handle_misc_anims();
511 // cull any finished misc animation instances
512 void main_hall_cull_misc_anim_instances();
514 // render all playing misc animations
515 void main_hall_render_misc_anims(float frametime);
518 // ----------------------------------------------------------------------------
519 // DOOR animations (not all of these are doors anymore, but they're doorlike _regions_)
521 #define DOOR_TEXT_X 100
522 #define DOOR_TEXT_Y 450
524 // the door animations themselves
525 anim *Main_hall_door_anim[MAX_DOOR_ANIMATIONS];
527 // the instance of a given door animation
528 anim_instance *Main_hall_door_anim_instance[MAX_DOOR_ANIMATIONS];
530 // render all playing door animations
531 void main_hall_render_door_anims(float frametime);
534 // ----------------------------------------------------------------------------
537 #define NUM_MAIN_HALL_REGIONS 10
538 #define NUM_MAIN_HALL_MOUSE_REGIONS 6
540 // region mask #'s (identifiers)
541 #define EXIT_REGION 0
542 #define BARRACKS_REGION 1
543 #define READY_ROOM_REGION 2
544 #define TECH_ROOM_REGION 3
545 #define OPTIONS_REGION 4
546 #define CAMPAIGN_ROOM_REGION 5
547 #define MULTIPLAYER_REGION 10
548 #define LOAD_MISSION_REGION 11
549 #define QUICK_START_REGION 12
550 #define SKILL_LEVEL_REGION 13
552 // all the menu regions in the main hall
553 MENU_REGION Main_hall_region[NUM_MAIN_HALL_REGIONS];
555 // # of regions (options) on this screen. parsed from a table
556 int Main_hall_num_options;
558 // region over which the mouse is currently residing, or -1 if over no region
559 // NOTE : you should nevery change this directly. Always use main_hall_handle_mouse_location(int)
560 // to do this. Otherwise, the door opening and closing animations will get screwed up
561 int Main_hall_mouse_region;
563 // set this to skip a frame
564 int Main_hall_frame_skip;
566 // do any necessary processing based upon the mouse location
567 void main_hall_handle_mouse_location(int cur_region);
569 // if the mouse has moved off of the currently active region, handle the anim accordingly
570 void main_hall_mouse_release_region(int region);
572 // if the mouse has moved on this region, handle it accordingly
573 void main_hall_mouse_grab_region(int region);
576 // ----------------------------------------------------------------------------
577 // SOUND data / handlers
580 // toaster oven room sound idex
581 #define TOASTER_REGION 3
583 // everyone's favorite desk guardian
584 #define ALLENDER_REGION 4
586 // handles to the sound instances of the doors opening/closing
587 int Main_hall_door_sound_handles[MAX_DOOR_SOUNDS] = {
591 // sound handle for looping ambient sound
592 int Main_hall_ambient_loop = -1;
594 // cull any door sounds that have finished playing
595 void main_hall_cull_door_sounds();
597 // handle starting, stopping and reversing "door" animations
598 void main_hall_handle_region_anims();
601 // ----------------------------------------------------------------------------
602 // warning/notification messages
604 #define MAIN_HALL_NOTIFY_TIME 3500
606 // timestamp for the notification messages
607 int Main_hall_notify_stamp = -1;
609 // text to display as the current notification message
610 char Main_hall_notify_text[300]="";
612 // set the current notification string and the associated timestamp
613 void main_hall_set_notify_string(char *str);
615 // handle any drawing, culling, etc of notification messages
616 void main_hall_notify_do();
619 // ----------------------------------------------------------------------------
623 // upper _RIGHT_ corner for the version text
624 #define MAIN_HALL_VERSION_X 630
625 #define MAIN_HALL_VERSION_Y 467
627 // main hall help overlay ID
628 int Main_hall_overlay_id;
630 // blit the freespace version #
631 void main_hall_blit_version();
633 // blit any necessary tooltips
634 void main_hall_maybe_blit_tooltips();
636 // shader for behind tooltips
637 shader Main_hall_tooltip_shader;
639 // num pixels shader is above/below tooltip text
640 static int Main_hall_tooltip_padding[GR_NUM_RESOLUTIONS] = {
644 static int Main_hall_f1_text_frame = 0;
645 static int F1_text_done = 0;
647 // read in main hall table
648 void main_hall_read_table();
650 // "press f1" for help stuff
651 #define MAIN_HALL_HELP_TIME 5000
652 int Main_hall_help_stamp = -1;
653 void main_hall_process_help_stuff();
656 // ----------------------------------------------------------------------------
657 // VOICE RECORDING STUFF
660 // are we currently recording voice?
664 // called when multiplayer clicks on the ready room door. May pop up dialog depending on network
665 // connection status and errors
666 void main_hall_do_multi_ready()
670 error = psnet_get_network_status();
672 case NETWORK_ERROR_NO_TYPE:
673 popup( PF_NO_NETWORKING, 1, POPUP_OK, XSTR( "You have not defined your type of Internet connection. Please run the Launcher, hit the setup button, and go to the Network tab and choose your connection type.", 360));
675 case NETWORK_ERROR_NO_WINSOCK:
676 popup( PF_NO_NETWORKING, 1, POPUP_OK, XSTR( "Winsock is not installed. You must have TCP/IP and Winsock installed to play multiplayer FreeSpace.", 361));
678 case NETWORK_ERROR_NO_PROTOCOL:
679 if(Multi_options_g.protocol == NET_TCP){
680 popup( PF_NO_NETWORKING, 1, POPUP_OK, XSTR( "TCP/IP protocol not found. This protocol is required for multiplayer FreeSpace.", 362));
682 Assert(Multi_options_g.protocol == NET_IPX);
683 popup( PF_NO_NETWORKING, 1, POPUP_OK, XSTR( "IPX protocol not found. This protocol is required for multiplayer FreeSpace.", 362));
686 case NETWORK_ERROR_CONNECT_TO_ISP:
687 popup( PF_NO_NETWORKING, 1, POPUP_OK, XSTR( "You have selected Dial Up Networking as your type of connection to the Internet. You are not currently connected. You must connect to your ISP before continuing on past this point.", 363));
689 case NETWORK_ERROR_LAN_AND_RAS:
690 popup( PF_NO_NETWORKING, 1, POPUP_OK, XSTR( "You have indicated that you use a LAN for networking. You also appear to be dialed into your ISP. Please disconnect from your service provider, or choose Dial Up Networking.", 364));
693 case NETWORK_ERROR_NONE:
698 // if our selected protocol is not active
699 if((Multi_options_g.protocol == NET_TCP) && !Tcp_active){
700 popup( PF_NO_NETWORKING, 1, POPUP_OK, XSTR( "You have selected TCP/IP for multiplayer Freespace, but the TCP/IP protocol was not detected on your machine.", 362));
703 if((Multi_options_g.protocol == NET_IPX) && !Ipx_active){
704 popup( PF_NO_NETWORKING, 1, POPUP_OK, XSTR( "You have selected IPX for multiplayer Freespace, but the IPX protocol was not detected on your machine.", 1402));
708 if ( error != NETWORK_ERROR_NONE ){
712 // 7/9/98 -- MWA. Deal with the connection speed issue. make a call to the multiplayer code to
713 // determine is a valid connection setting exists
714 if ( Multi_connection_speed == CONNECTION_SPEED_NONE ) {
715 popup( PF_NO_NETWORKING, 1, POPUP_OK, XSTR( "You must define your connection speed. Please run the Launcher, hit the setup button, and go to the Network tab and choose your connection speed.", 986) );
719 // go to parallax online
720 #ifdef MULTIPLAYER_BETA_BUILD // do we want this for FS2_DEMO
721 Multi_options_g.pxo = 1;
722 Multi_options_g.protocol = NET_TCP;
723 gameseq_post_event( GS_EVENT_PXO );
726 // go to the regular join game screen
727 gameseq_post_event( GS_EVENT_MULTI_JOIN_GAME );
731 psnet_use_protocol(Multi_options_g.protocol);
734 // blit some small color indicators to show whether ships.tbl and weapons.tbl are valid
735 // green == valid, red == invalid.
736 // ships.tbl will be on the left, weapons.tbl on the right
737 int Mh_ship_table_status[GR_NUM_RESOLUTIONS][2] = {
741 int Mh_weapon_table_status[GR_NUM_RESOLUTIONS][2] = {
745 void main_hall_blit_table_status()
747 // blit ship table status
748 gr_set_color_fast(Game_ships_tbl_valid ? &Color_bright_green : &Color_bright_red);
749 gr_line(Mh_ship_table_status[gr_screen.res][0], Mh_ship_table_status[gr_screen.res][1], Mh_ship_table_status[gr_screen.res][0], Mh_ship_table_status[gr_screen.res][1]);
751 // blit weapon table status
752 gr_set_color_fast(Game_weapons_tbl_valid ? &Color_bright_green : &Color_bright_red);
753 gr_line(Mh_weapon_table_status[gr_screen.res][0], Mh_weapon_table_status[gr_screen.res][1], Mh_weapon_table_status[gr_screen.res][0], Mh_ship_table_status[gr_screen.res][1]);
756 // bash the player to a specific mission in a campaign
757 void main_hall_campaign_cheat()
759 char *ret = popup_input(0, XSTR("Enter mission name.\n\n* This will destroy all legitimate progress in this campaign. *", -1));
763 // strcpy(Main_hall_campaign_cheat, ret);
764 mission_campaign_jump_to_mission(ret);
768 // -------------------------------------------------------------------------------------------------------------------
769 // FUNCTION DEFINITIONS BEGIN
772 // initialize the main hall proper
773 void main_hall_init(int main_hall_num)
775 if ( Main_hall_inited ) {
780 char temp[100], whee[100];
782 // read in the main hall table
783 main_hall_read_table();
785 // create the snazzy interface and load up the info from the table
787 read_menu_tbl(NOX("MAIN HALL"), temp, whee, Main_hall_region, &Main_hall_num_options, 0);
789 // assign the proper main hall data
790 Assert((main_hall_num >= 0) && (main_hall_num < NUM_MAIN_HALLS));
791 Main_hall = &Main_hall_defines[gr_screen.res][main_hall_num];
794 Main_hall->region_descript[0] = XSTR( "Exit FreeSpace 2", 353);
795 Main_hall->region_descript[1] = XSTR( "Barracks - Manage your FreeSpace 2 pilots", 354);
796 Main_hall->region_descript[2] = XSTR( "Ready room - Start or continue a campaign", 355);
797 Main_hall->region_descript[3] = XSTR( "Tech room - View specifications of FreeSpace 2 ships and weaponry", 356);
798 Main_hall->region_descript[4] = XSTR( "Options - Change your FreeSpace 2 options", 357);
799 Main_hall->region_descript[5] = XSTR( "Campaign Room - View all available campaigns", 358);
800 Main_hall->region_descript[6] = XSTR( "Multiplayer - Start or join a multiplayer game", 359);
802 // init tooltip shader
803 float gray_intensity = 0.02f; // nearly black
804 float c = (gr_screen.mode == GR_DIRECT3D) ? 0.11f : 0.07f; // adjust for renderer differences
805 gr_create_shader(&Main_hall_tooltip_shader, gray_intensity, gray_intensity, gray_intensity, c);
807 // load the background bitmap
808 Main_hall_bitmap = bm_load(Main_hall->bitmap);
809 if(Main_hall_bitmap < 0){
810 nprintf(("General","WARNING! Couldn't load main hall background bitmap %s\n", Main_hall->bitmap));
813 // remove any multiplayer flags from the game mode
814 Game_mode &= ~(GM_MULTIPLAYER);
816 // set the interface palette
817 #ifndef HARDWARE_ONLY
818 palette_use_bm_palette(Main_hall_bitmap);
821 Main_hall_mask_w = -1;
822 Main_hall_mask_h = -1;
825 Main_hall_mask = bm_load(Main_hall->mask);
826 if (Main_hall_mask < 0) {
827 Error(LOCATION,"Could not load in %s!", Main_hall->mask);
829 // get a pointer to bitmap by using bm_lock(), so we can feed it to he snazzy menu system
830 Main_hall_mask_bitmap = bm_lock(Main_hall_mask, 8, BMP_AABITMAP);
831 Main_hall_mask_data = (ubyte*)Main_hall_mask_bitmap->data;
832 bm_get_info(Main_hall_mask, &Main_hall_mask_w, &Main_hall_mask_h);
835 // load up the misc animations, and nullify all the delay timestamps for the misc animations
836 for(idx=0;idx<Main_hall->num_misc_animations;idx++) {
837 Main_hall_misc_anim[idx] = NULL;
838 Main_hall_misc_anim[idx] = anim_load(Main_hall->misc_anim_name[idx]);
839 if(Main_hall_misc_anim[idx] == NULL) {
840 nprintf(("General","WARNING!, Could not load misc %s anim in main hall\n",Main_hall->misc_anim_name));
843 // null out the animation instances
844 Main_hall_misc_anim_instance[idx] = NULL;
846 // null out the delay timestamps
847 Main_hall->misc_anim_delay[idx][0] = -1;
850 // load up the door animations
851 for(idx=0;idx<Main_hall->num_door_animations;idx++) {
852 Main_hall_door_anim[idx] = NULL;
853 Main_hall_door_anim[idx] = anim_load(Main_hall->door_anim_name[idx]);
854 if(Main_hall_door_anim[idx] == NULL){
855 nprintf(("General","WARNING!, Could not load door anim %s in main hall\n",Main_hall->door_anim_name[idx]));
858 // null out the animation instances
859 Main_hall_door_anim_instance[idx] = NULL;
862 // load in help overlay bitmap
863 if(Main_hall == &Main_hall_defines[gr_screen.res][0]) {
864 Main_hall_overlay_id = MH_OVERLAY;
866 Assert(Main_hall == &Main_hall_defines[gr_screen.res][1]);
867 Main_hall_overlay_id = MH2_OVERLAY;
869 help_overlay_load(Main_hall_overlay_id);
870 help_overlay_set_state(Main_hall_overlay_id,0);
872 // check to see if the "very first pilot" flag is set, and load the overlay if so
874 if (Main_hall_f1_text_frame == 0) {
875 Main_hall_help_stamp = timestamp(MAIN_HALL_HELP_TIME);
882 if(Player_select_very_first_pilot) {
883 Main_hall_help_stamp = timestamp(MAIN_HALL_HELP_TIME);
885 // don't display the "press f1" message more than once
886 Player_select_very_first_pilot = 0;
888 Main_hall_help_stamp = -1;
891 Main_hall_region_linger_stamp = -1;
893 strcpy(Main_hall_campaign_cheat, "");
895 // zero out the door sounds
896 for(idx=0;idx<Main_hall->num_door_sounds;idx++){
897 Main_hall_door_sound_handles[idx] = -1;
900 // zero out the misc anim sounds
901 for(idx=0;idx<Main_hall->num_misc_animations;idx++){
902 for(s_idx = 1;s_idx < 10;s_idx++){
903 Main_hall->misc_anim_sound_handles[idx][s_idx] = -1;
904 Main_hall->misc_anim_sound_flag[idx][s_idx] = 0;
908 // skip the first frame
909 Main_hall_frame_skip = 1;
911 // initialize the music
912 main_hall_start_music();
914 // initialize the main hall notify text
915 Main_hall_notify_stamp = 1;
917 // initialize the random intercom sound stuff
918 Main_hall_next_intercom_sound = 0;
919 Main_hall_next_intercom_sound_stamp = -1;
920 Main_hall_intercom_sound_handle = -1;
922 // set the placement of the mouse cursor (start at the ready room)
923 Main_hall_mouse_region = -1;
924 Main_hall_last_clicked_region = READY_ROOM_REGION;
925 mouse_set_pos(Main_hall->door_anim_coords[READY_ROOM_REGION][2],Main_hall->door_anim_coords[READY_ROOM_REGION][3]);
927 Main_hall_inited = 1;
929 // determine if we have a right click
930 Main_hall_right_click = mouse_down(MOUSE_RIGHT_BUTTON);
932 // set the game_mode based on the type of player
933 Assert( Player != NULL );
934 if ( Player->flags & PLAYER_FLAGS_IS_MULTI ){
935 Game_mode = GM_MULTIPLAYER;
937 Game_mode = GM_NORMAL;
940 if ( (Cmdline_start_netgame || (Cmdline_connect_addr != NULL)) && !Main_hall_netgame_started ) {
941 Main_hall_netgame_started = 1;
942 main_hall_do_multi_ready();
946 void main_hall_exit_game()
948 #if defined(NDEBUG) || defined(INTERPLAYQA)
952 main_hall_stop_music();
953 main_hall_stop_ambient();
954 choice = popup( PF_NO_NETWORKING | PF_BODY_BIG, 2, POPUP_NO, POPUP_YES, XSTR( "Exit Game?", 365));
956 gameseq_post_event(GS_EVENT_QUIT_GAME);
958 main_hall_start_music();
959 main_hall_start_ambient();
962 gameseq_post_event(GS_EVENT_QUIT_GAME);
967 // do a frame for the main hall
968 void main_hall_do(float frametime)
970 int code, key, snazzy_action;
972 // need to ensure ambient is playing, since it may be stopped by a playing movie
973 main_hall_start_ambient();
975 // handle any animation details
976 main_hall_handle_misc_anims();
977 main_hall_handle_region_anims();
979 // handle any random intercom sound details
980 main_hall_handle_random_intercom_sounds();
982 // handle any mouse clicks
983 main_hall_handle_right_clicks();
985 // handle any sound details
986 main_hall_cull_door_sounds();
988 // process any keypresses/mouse events
990 code = snazzy_menu_do(Main_hall_mask_data, Main_hall_mask_w, Main_hall_mask_h, Main_hall_num_options, Main_hall_region, &snazzy_action, 1, &key);
993 extern void game_process_cheats(int k);
994 game_process_cheats(key);
998 snazzy_action = SNAZZY_CLICKED;
1004 // movie_play("endprt2b.mve", 0);
1008 // movie_play_two("endprt2a.mve", "endprt2b.mve", 0);
1011 main_hall_campaign_cheat();
1013 case KEY_DEBUGGED + KEY_D:
1014 demo_start_playback("test.fsd");
1021 // do any processing based upon what happened to the snazzy menu
1022 switch (snazzy_action) {
1024 main_hall_handle_mouse_location(code);
1027 case SNAZZY_CLICKED:
1029 // clicked on the exit region
1031 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1032 main_hall_exit_game();
1035 // clicked on the readyroom region
1036 case READY_ROOM_REGION:
1037 #ifdef MULTIPLAYER_BETA_BUILD
1038 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1039 Player->flags |= PLAYER_FLAGS_IS_MULTI;
1040 main_hall_do_multi_ready();
1041 #elif defined(E3_BUILD) || defined(PRESS_TOUR_BUILD)
1042 gameseq_post_event(GS_EVENT_NEW_CAMPAIGN);
1044 if (Player->flags & PLAYER_FLAGS_IS_MULTI){
1045 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1046 main_hall_do_multi_ready();
1048 if(strlen(Main_hall_campaign_cheat)){
1049 gameseq_post_event(GS_EVENT_CAMPAIGN_CHEAT);
1051 gameseq_post_event(GS_EVENT_NEW_CAMPAIGN);
1053 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1058 // clicked on the tech room region
1059 case TECH_ROOM_REGION:
1060 #if defined(FS2_DEMO)
1061 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1062 game_feature_not_in_demo_popup();
1064 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1065 gameseq_post_event( GS_EVENT_TECH_MENU );
1069 // clicked on the options region
1070 case OPTIONS_REGION:
1071 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1072 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
1075 // clicked on the campaign toom region
1076 case CAMPAIGN_ROOM_REGION:
1077 #if !defined(MULTIPLAYER_BETA_BUILD) && !defined(E3_BUILD) && !defined(PRESS_TOUR_BUILD)
1080 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1082 //game_feature_not_in_demo_popup();
1083 int reset_campaign = popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 2, "Exit", "Restart Campaign", "Campaign Room only available in full version. However, you may restart the campaign.");
1084 if (reset_campaign == 1) {
1085 mission_campaign_savefile_delete(Campaign.filename);
1086 mission_campaign_load(Campaign.filename);
1087 mission_campaign_next_mission();
1092 if(Player->flags & PLAYER_FLAGS_IS_MULTI){
1093 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1094 main_hall_set_notify_string(XSTR( "Campaign Room not valid for multiplayer pilots", 366));
1096 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1097 gameseq_post_event(GS_EVENT_CAMPAIGN_ROOM);
1104 // clicked on the multiplayer region
1105 case MULTIPLAYER_REGION:
1106 #if defined(DEMO) || defined(OEM_BUILD) // not for FS2_DEMO
1107 game_feature_not_in_demo_popup();
1109 if (Player->flags & PLAYER_FLAGS_IS_MULTI){
1110 // NOTE : this isn't a great thing to be calling this anymore. But we'll leave it for now
1111 gameseq_post_event( GS_EVENT_MULTI_JOIN_GAME );
1113 main_hall_set_notify_string(XSTR( "Not a valid multiplayer pilot!!", 367));
1118 // load mission key was pressed
1119 case LOAD_MISSION_REGION:
1122 #if !(defined(MULTIPLAYER_BETA_BUILD) || defined(FS2_DEMO))
1123 //#if !defined(NDEBUG) || defined(INTERPLAYQA)
1124 if (Player->flags & PLAYER_FLAGS_IS_MULTI){
1125 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1126 main_hall_set_notify_string(XSTR( "Load Mission not valid for multiplayer pilots", 368));
1128 #ifdef GAME_CD_CHECK
1129 // if ( !game_do_cd_check() ) {
1133 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1134 gameseq_post_event( GS_EVENT_LOAD_MISSION_MENU );
1141 // quick start a game region
1142 case QUICK_START_REGION:
1143 #if !defined(NDEBUG) && !defined(FS2_DEMO)
1144 if (Player->flags & PLAYER_FLAGS_IS_MULTI){
1145 main_hall_set_notify_string(XSTR( "Quick Start not valid for multiplayer pilots", 369));
1148 if (Num_recent_missions > 0) {
1149 strncpy( Game_current_mission_filename, Recent_missions[0], MAX_FILENAME_LEN );
1151 mission_load_up_campaign();
1152 strncpy( Game_current_mission_filename, Campaign.missions[0].name, MAX_FILENAME_LEN );
1155 Campaign.current_mission = -1;
1156 gameseq_post_event(GS_EVENT_START_GAME_QUICK);
1161 // clicked on the barracks region
1162 case BARRACKS_REGION:
1163 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1164 gameseq_post_event( GS_EVENT_BARRACKS_MENU );
1167 // increate the skill level
1168 case SKILL_LEVEL_REGION:
1171 game_increase_skill_level();
1172 sprintf(temp, XSTR( "Skill level set to %s.", 370), Skill_level_names(Game_skill_level));
1173 main_hall_set_notify_string(temp);
1176 // escape was pressed
1178 // if there is a help overlay active, then don't quit the game - just kill the overlay
1179 if(!help_overlay_active(Main_hall_overlay_id)){
1180 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1181 main_hall_exit_game();
1185 help_overlay_set_state(Main_hall_overlay_id,0);
1190 // if the escape key wasn't pressed handle any mouse position related events
1191 if (code != ESC_PRESSED){
1192 main_hall_handle_mouse_location(code);
1197 main_hall_handle_mouse_location(-1);
1201 if ( mouse_down(MOUSE_LEFT_BUTTON) ) {
1202 help_overlay_set_state(Main_hall_overlay_id, 0);
1205 // draw the background bitmap
1207 GR_MAYBE_CLEAR_RES(Main_hall_bitmap);
1208 if(Main_hall_bitmap >= 0){
1209 gr_set_bitmap(Main_hall_bitmap);
1213 // draw any pending notification messages
1214 main_hall_notify_do();
1216 // render misc animations
1217 main_hall_render_misc_anims(frametime);
1219 // render door animtions
1220 main_hall_render_door_anims(frametime);
1222 // blit any appropriate tooltips
1223 main_hall_maybe_blit_tooltips();
1228 // process any help "hit f1" timestamps and display any messages if necessary
1229 if (!F1_text_done) {
1230 main_hall_process_help_stuff();
1233 // blit help overlay if active
1234 help_overlay_maybe_blit(Main_hall_overlay_id);
1236 // blit the freespace version #
1237 main_hall_blit_version();
1239 // blit ship and weapon table status
1240 main_hall_blit_table_status();
1242 // if we're in nice D3D texture format
1244 gr_set_color_fast(&Color_white);
1247 if(gr_screen.mode == GR_DIRECT3D){
1248 if(Bm_pixel_format == BM_PIXEL_FORMAT_ARGB_D3D){
1249 gr_string(320, gr_screen.max_h - 10, "D3D ARGB");
1251 extern int D3d_rendition_uvs;
1252 extern int D3D_32bit;
1253 extern int D3D_fog_mode;
1254 extern int D3D_zbias;
1255 if(D3d_rendition_uvs){
1256 gr_string(320, gr_screen.max_h - 20, "D3D rendition");
1259 gr_string(320, gr_screen.max_h - 30, "D3D 32bit");
1261 gr_printf(320, gr_screen.max_h - 40, "Fog : %d", D3D_fog_mode);
1262 gr_printf(320, gr_screen.max_h - 50, "Zbias : %d", D3D_zbias);
1263 // extern void d3d_test();
1265 } else if(gr_screen.mode == GR_GLIDE){
1266 extern int Glide_voodoo3;
1268 gr_string(320, gr_screen.max_h - 20, "VOODOO 3");
1275 // maybe run the player tips popup
1276 // #if defined(FS2_DEMO) && defined(NDEBUG)
1277 player_tips_popup();
1280 // if we were supposed to skip a frame, then stop doing it after 1 frame
1281 if(Main_hall_frame_skip){
1282 Main_hall_frame_skip = 0;
1286 // close the main hall proper
1287 void main_hall_close()
1291 if(!Main_hall_inited){
1295 // unload the main hall bitmap
1296 if(Main_hall_bitmap != -1){
1297 bm_unload(Main_hall_bitmap);
1300 // unload any bitmaps
1301 if(Main_hall_mask >= 0){
1302 // make sure we unlock the mask bitmap so it can be unloaded
1303 bm_unlock(Main_hall_mask);
1304 if(!bm_unload(Main_hall_mask)){
1305 nprintf(("General","WARNING! Couldn't unload main hall mask bitmap!\n"));
1309 // free up any (possibly) playing misc animation handles
1310 for(idx=0;idx<Main_hall->num_misc_animations;idx++){
1311 if(Main_hall_misc_anim_instance[idx]!=NULL){
1312 anim_stop_playing(Main_hall_misc_anim_instance[idx]);
1313 Main_hall_misc_anim_instance[idx] = NULL;
1317 // free up any (possibly) playing door animation handles
1318 for(idx=0;idx<Main_hall->num_door_animations;idx++){
1319 if(Main_hall_door_anim_instance[idx]!=NULL){
1320 anim_stop_playing(Main_hall_door_anim_instance[idx]);
1321 Main_hall_door_anim_instance[idx] = NULL;
1326 // free up any misc animations/instances
1327 for(idx=0;idx<Main_hall->num_misc_animations;idx++){
1328 if((Main_hall_misc_anim_instance[idx]!=NULL) && (anim_playing(Main_hall_misc_anim_instance[idx]))){
1329 Main_hall_misc_anim_instance[idx] = NULL;
1331 if(Main_hall_misc_anim[idx]!=NULL){
1332 if(anim_free(Main_hall_misc_anim[idx]) == -1){
1333 nprintf(("General","WARNING!, Could not free up misc anim %s in main hall\n",Main_hall->misc_anim_name[idx]));
1338 // free up any door animations/instances
1339 for(idx=0;idx<Main_hall->num_door_animations;idx++){
1340 if((Main_hall_door_anim_instance[idx]!=NULL) && (anim_playing(Main_hall_door_anim_instance[idx]))){
1341 Main_hall_door_anim_instance[idx] = NULL;
1343 if(Main_hall_door_anim[idx]!=NULL){
1344 if(anim_free(Main_hall_door_anim[idx]) == -1){
1345 nprintf(("General","WARNING!, Could not free up door anim %s in main hall\n",Main_hall->door_anim_name[idx]));
1350 // stop any playing door sounds
1351 for(idx=0;idx<Main_hall->num_door_sounds-2;idx++){ // don't cut off the glow sounds (requested by Dan)
1352 if((Main_hall_door_sound_handles[idx] != -1) && snd_is_playing(Main_hall_door_sound_handles[idx])){
1353 snd_stop(Main_hall_door_sound_handles[idx]);
1354 Main_hall_door_sound_handles[idx] = -1;
1358 // stop any playing misc animation sounds
1359 for(idx=0;idx<Main_hall->num_misc_animations;idx++){
1360 for(s_idx=1;s_idx<10;s_idx++){
1361 if(snd_is_playing(Main_hall->misc_anim_sound_handles[idx][s_idx])){
1362 snd_stop(Main_hall->misc_anim_sound_handles[idx][s_idx]);
1363 Main_hall->misc_anim_sound_handles[idx][s_idx] = -1;
1368 // unload the overlay bitmap
1369 help_overlay_unload(Main_hall_overlay_id);
1371 // close any snazzy menu details
1372 snazzy_menu_close();
1375 palette_restore_palette();
1380 // not inited anymore
1381 Main_hall_inited = 0;
1384 // start the main hall music playing
1385 void main_hall_start_music()
1387 // start a looping ambient sound
1388 main_hall_start_ambient();
1390 // if we have selected no music, then don't do this
1391 if ( Cmdline_freespace_no_music ) {
1395 int main_hall_spooled_music_index = event_music_get_spooled_music_index(Main_hall->music);
1397 if ((Main_hall_music_handle == -1) && (main_hall_spooled_music_index != -1)) {
1398 char *music_wavfile_name = Spooled_music[main_hall_spooled_music_index].filename;
1399 if (music_wavfile_name != NULL) {
1400 Main_hall_music_handle = audiostream_open( music_wavfile_name, ASF_EVENTMUSIC );
1401 if ( Main_hall_music_handle != -1 )
1402 audiostream_play(Main_hall_music_handle, Master_event_music_volume);
1405 nprintf(("Warning", "No music file exists to play music at the main menu!\n"));
1410 // stop the main hall music
1411 void main_hall_stop_music()
1413 if ( Main_hall_music_handle != -1 ) {
1414 audiostream_close_file(Main_hall_music_handle);
1415 Main_hall_music_handle = -1;
1419 // do any necessary instantiation of misc animations
1420 void main_hall_handle_misc_anims()
1424 if(Main_hall_frame_skip)
1427 for(idx=0;idx<Main_hall->num_misc_animations;idx++){
1428 // if the anim isn't playing
1429 if(Main_hall_misc_anim_instance[idx] == NULL){
1430 // if the timestamp is -1, then reset it to some random value (based on MIN and MAX) and continue
1431 if(Main_hall->misc_anim_delay[idx][0] == -1){
1432 Main_hall->misc_anim_delay[idx][0] = timestamp(Main_hall->misc_anim_delay[idx][1] +
1433 (int)(((float)rand()/(float)RAND_MAX) * (float)(Main_hall->misc_anim_delay[idx][2] - Main_hall->misc_anim_delay[idx][1])));
1435 // if the timestamp is not -1 and has popped, play the anim and make the timestap -1
1436 } else if (timestamp_elapsed(Main_hall->misc_anim_delay[idx][0]) && Main_hall_misc_anim[idx]) {
1437 anim_play_struct aps;
1439 anim_play_init(&aps, Main_hall_misc_anim[idx], Main_hall->misc_anim_coords[idx][0], Main_hall->misc_anim_coords[idx][1]);
1440 aps.screen_id = GS_STATE_MAIN_MENU;
1441 aps.framerate_independent = 1;
1443 Main_hall_misc_anim_instance[idx] = anim_play(&aps);
1445 // kill the timestamp
1446 Main_hall->misc_anim_delay[idx][0] = -1;
1448 // reset the "should be playing" flags
1449 for(s_idx=1;s_idx<10;s_idx++){
1450 Main_hall->misc_anim_sound_flag[idx][s_idx] = 0;
1454 // if the anim is playing
1456 // check to see if any special trigger points have been reached by the animation
1457 // since the frame triggers must be in ascending order, we will count down so that we don't trigger too many sounds
1458 for(s_idx=Main_hall->misc_anim_special_sounds[idx][0]; s_idx > 0; s_idx--){
1459 // if we've passed the trigger point, then play the sound and break out of the loop
1460 if((Main_hall_misc_anim_instance[idx]->frame_num >= Main_hall->misc_anim_special_trigger[idx][s_idx]) && !Main_hall->misc_anim_sound_flag[idx][s_idx]){
1461 Main_hall->misc_anim_sound_flag[idx][s_idx] = 1;
1463 // if the sound is already playing, then kill it. This is a pretty safe thing to do since we can assume that
1464 // by the time we get to this point again, the sound will have been long finished
1465 if(snd_is_playing(Main_hall->misc_anim_sound_handles[idx][s_idx])){
1466 snd_stop(Main_hall->misc_anim_sound_handles[idx][s_idx]);
1467 Main_hall->misc_anim_sound_handles[idx][s_idx] = -1;
1470 Main_hall->misc_anim_sound_handles[idx][s_idx] = snd_play(&Snds_iface[Main_hall->misc_anim_special_sounds[idx][s_idx]],Main_hall->misc_anim_sound_pan[idx]);
1475 // if the animation mode is MISC_ANIM_MODE_HOLD, pause it at the last frame
1476 if((Main_hall->misc_anim_modes[idx] == MISC_ANIM_MODE_HOLD) && (Main_hall_misc_anim_instance[idx]->frame_num == Main_hall_misc_anim_instance[idx]->stop_at)){
1477 anim_pause(Main_hall_misc_anim_instance[idx]);
1478 Main_hall_misc_anim_instance[idx]->stop_now = FALSE;
1481 // if the animation mode is MISC_ANIM_MODE_LOOP, check to see if it should be looped
1482 if((Main_hall->misc_anim_modes[idx] == MISC_ANIM_MODE_LOOP) && (Main_hall_misc_anim_instance[idx]->frame_num == Main_hall_misc_anim_instance[idx]->stop_at)){
1483 anim_release_render_instance(Main_hall_misc_anim_instance[idx]);
1485 // start it playing again
1486 anim_play_struct aps;
1488 anim_play_init(&aps, Main_hall_misc_anim[idx], Main_hall->misc_anim_coords[idx][0], Main_hall->misc_anim_coords[idx][1]);
1489 aps.screen_id = GS_STATE_MAIN_MENU;
1490 aps.framerate_independent = 1;
1492 Main_hall_misc_anim_instance[idx] = anim_play(&aps);
1494 // kill the timestamp
1495 Main_hall->misc_anim_delay[idx][0] = -1;
1497 // reset the "should be playing" flags
1498 for(s_idx=1;s_idx<10;s_idx++){
1499 Main_hall->misc_anim_sound_flag[idx][s_idx] = 0;
1503 // cull any misc animations which are marked as done (!is_playing)
1504 if(!anim_playing(Main_hall_misc_anim_instance[idx])){
1505 Main_hall_misc_anim_instance[idx] = NULL;
1511 // render all playing misc animations
1512 void main_hall_render_misc_anims(float frametime)
1516 // HACKETY HACK HACK - always render misc anim 3 first, if it is playing
1517 if(Main_hall_misc_anim_instance[2] != NULL){
1518 anim_render_one(GS_STATE_MAIN_MENU,Main_hall_misc_anim_instance[2],frametime);
1521 // render all other animations
1522 for(idx=0;idx<MAX_MISC_ANIMATIONS;idx++){
1523 // skip anim 3, which was previously rendered, if at all
1529 if(Main_hall_misc_anim_instance[idx] != NULL){
1530 anim_render_one(GS_STATE_MAIN_MENU,Main_hall_misc_anim_instance[idx],frametime);
1535 // render all playing door animations
1536 void main_hall_render_door_anims(float frametime)
1540 // render all door animations
1541 for(idx=0;idx<MAX_DOOR_ANIMATIONS;idx++){
1543 if(Main_hall_door_anim_instance[idx] != NULL){
1544 anim_render_one(GS_STATE_MAIN_MENU,Main_hall_door_anim_instance[idx],frametime);
1549 // handle starting, stopping and reversing "door" animations
1550 void main_hall_handle_region_anims()
1554 if(Main_hall_frame_skip)
1557 // make sure we make any finished door animations NULL
1558 for(idx=0;idx<Main_hall->num_door_animations;idx++){
1559 if((Main_hall_door_anim_instance[idx] != NULL) && !anim_playing(Main_hall_door_anim_instance[idx])){
1560 Main_hall_door_anim_instance[idx] = NULL;
1564 // go through each region animation
1565 for(idx=0;idx<Main_hall->num_door_animations;idx++){
1566 // if the instance is not null and the animation is playing
1567 if((Main_hall_door_anim_instance[idx] != NULL) && anim_playing(Main_hall_door_anim_instance[idx])){
1568 // check to see if we should hold a given door "open"
1569 if((Main_hall_mouse_region == idx) && (Main_hall_door_anim_instance[idx]->frame_num == Main_hall_door_anim_instance[idx]->stop_at)){
1570 anim_pause(Main_hall_door_anim_instance[idx]);
1571 Main_hall_door_anim_instance[idx]->stop_now = FALSE;
1573 // check to see if we should close a door being held open
1574 if((Main_hall_mouse_region != idx) && (Main_hall_door_anim_instance[idx]->paused)){
1575 anim_unpause(Main_hall_door_anim_instance[idx]);
1581 // do any necessary processing based upon the mouse location
1582 void main_hall_handle_mouse_location(int cur_region)
1584 if(Main_hall_frame_skip)
1587 if(cur_region > NUM_MAIN_HALL_MOUSE_REGIONS) {
1588 // MWA -- inserted return since Int3() was tripped when hitting L from main
1593 // if the mouse is now over a resgion
1594 if (cur_region != -1) {
1595 // if we're still over the same region we were last frame, check stuff
1596 if (cur_region == Main_hall_mouse_region) {
1597 // if we have a linger timestamp set and it has expired, then get moving
1598 if ((Main_hall_region_linger_stamp != -1) && timestamp_elapsed(Main_hall_region_linger_stamp)) {
1599 main_hall_mouse_grab_region(cur_region);
1601 // release the region linger stamp
1602 Main_hall_region_linger_stamp = -1;
1605 // if we're currently on another region, release it
1606 if ((Main_hall_mouse_region != -1) && (cur_region != Main_hall_mouse_region)) {
1607 main_hall_mouse_release_region(Main_hall_mouse_region);
1610 // set the linger time
1611 if (Main_hall_region_linger_stamp == -1) {
1612 Main_hall_mouse_region = cur_region;
1613 Main_hall_region_linger_stamp = timestamp(MAIN_HALL_REGION_LINGER);
1617 // if it was over a region but isn't anymore, release that region
1619 if (Main_hall_mouse_region != -1) {
1620 main_hall_mouse_release_region(Main_hall_mouse_region);
1621 Main_hall_mouse_region = -1;
1623 // release the region linger timestamp
1624 Main_hall_region_linger_stamp = -1;
1629 // if the mouse has moved off of the currently active region, handle the anim accordingly
1630 void main_hall_mouse_release_region(int region)
1632 if(Main_hall_frame_skip){
1636 // if the animation is currently playing in the forward direction, change direction and be done, otherwise don't do a thing
1637 if ( (Main_hall_door_anim_instance[region] != NULL) && anim_playing(Main_hall_door_anim_instance[region]) && (Main_hall_door_anim_instance[region]->direction == ANIM_DIRECT_FORWARD)){
1638 anim_reverse_direction(Main_hall_door_anim_instance[region]);
1641 // check for door sounds, ignoring the OPTIONS_REGION (which isn't a door)
1642 if ((Main_hall_door_anim_instance[region] != NULL)) {
1643 // don't stop the toaster oven or microwave regions from playing all the way through
1644 if (Main_hall_door_sound_handles[region] != -1) {
1645 snd_stop(Main_hall_door_sound_handles[region]);
1647 Main_hall_door_sound_handles[region] = snd_play(&Snds_iface[Main_hall->door_sounds[region][1]], Main_hall->door_sound_pan[region]);
1649 // make sure to set the sound to play from the right spot
1650 snd_set_pos(Main_hall_door_sound_handles[region], &Snds_iface[SND_MAIN_HALL_DOOR_CLOSE],
1651 (float)(Main_hall_door_anim_instance[region]->start_at - Main_hall_door_anim_instance[region]->frame_num) / (float)Main_hall_door_anim_instance[region]->parent->total_frames, 1);
1655 // if the mouse has moved on this region, handle it accordingly
1656 void main_hall_mouse_grab_region(int region)
1658 if (Main_hall_frame_skip) {
1662 // if the animation is not playing, start it playing
1663 if ( !Main_hall_door_anim_instance[region] ) {
1664 if ( Main_hall_door_anim[region] ) {
1665 anim_play_struct aps;
1667 anim_play_init(&aps, Main_hall_door_anim[region], Main_hall->door_anim_coords[region][0], Main_hall->door_anim_coords[region][1]);
1668 aps.screen_id = GS_STATE_MAIN_MENU;
1669 aps.framerate_independent = 1;
1671 Main_hall_door_anim_instance[region] = anim_play(&aps);
1674 // otherwise if its playing in the reverse direction, change it to the forward direction
1675 else if (Main_hall_door_anim_instance[region]->direction == ANIM_DIRECT_REVERSE) {
1676 anim_reverse_direction(Main_hall_door_anim_instance[region]);
1679 // check for opening/starting sounds
1680 // kill the currently playing sounds if necessary
1681 if(Main_hall_door_sound_handles[region] != -1){
1682 snd_stop(Main_hall_door_sound_handles[region]);
1684 Main_hall_door_sound_handles[region] = snd_play(&Snds_iface[Main_hall->door_sounds[region][0]],Main_hall->door_sound_pan[region]);
1686 // start the sound playing at the right spot relative to the completion of the animation
1687 if(Main_hall_door_anim_instance[region]->frame_num != -1){
1688 snd_set_pos(Main_hall_door_sound_handles[region],&Snds_iface[SND_MAIN_HALL_DOOR_OPEN],
1689 (float)Main_hall_door_anim_instance[region]->frame_num / (float)Main_hall_door_anim_instance[region]->parent->total_frames,1);
1693 // handle any right clicks which may have occured
1694 void main_hall_handle_right_clicks()
1698 if(Main_hall_frame_skip)
1701 // check to see if the button has been clicked
1702 if(!Main_hall_right_click){
1703 if(mouse_down(MOUSE_RIGHT_BUTTON)){
1704 // cycle through the available regions
1705 if(Main_hall_last_clicked_region == NUM_MAIN_HALL_MOUSE_REGIONS - 1){
1708 new_region = Main_hall_last_clicked_region + 1;
1710 // set the position of the mouse cursor and the newly clicked region
1711 mouse_set_pos(Main_hall->door_anim_coords[new_region][2],Main_hall->door_anim_coords[new_region][3]);
1713 main_hall_handle_mouse_location(new_region);
1714 Main_hall_last_clicked_region = new_region;
1716 // set the mouse as being clicked
1717 Main_hall_right_click = 1;
1720 // set the mouse as being unclicked
1721 else if(Main_hall_right_click && !(mouse_down(MOUSE_RIGHT_BUTTON))){
1722 Main_hall_right_click = 0;
1726 // cull any door sounds that have finished playing
1727 void main_hall_cull_door_sounds()
1730 // basically just set the handle of any finished sound to be -1, so that we know its free any where else in the code we may need it
1731 for(idx=0;idx<Main_hall->num_door_sounds;idx++){
1732 if((Main_hall_door_sound_handles[idx] != -1) && !snd_is_playing(Main_hall_door_sound_handles[idx])){
1733 Main_hall_door_sound_handles[idx] = -1;
1738 void main_hall_handle_random_intercom_sounds()
1740 // if we have no timestamp for the next random sound, then set on
1741 if((Main_hall_next_intercom_sound_stamp == -1) && (Main_hall_intercom_sound_handle == -1)){
1742 Main_hall_next_intercom_sound_stamp = timestamp((int)(((float)rand()/(float)RAND_MAX) *
1743 (float)(Main_hall->intercom_delay[Main_hall_next_intercom_sound][1]
1744 - Main_hall->intercom_delay[Main_hall_intercom_sound_handle][0])) );
1747 // if the there is no sound playing
1748 if(Main_hall_intercom_sound_handle == -1){
1749 // if the timestamp has popped, play a sound
1750 if((Main_hall_next_intercom_sound_stamp != -1) && (timestamp_elapsed(Main_hall_next_intercom_sound_stamp))){
1752 Main_hall_intercom_sound_handle = snd_play(&Snds_iface[Main_hall->intercom_sounds[Main_hall_next_intercom_sound]]);
1754 // unset the timestamp
1755 Main_hall_next_intercom_sound_stamp = -1;
1758 // if the sound is playing
1760 // if the sound has finished, set the timestamp and continue
1761 if(!snd_is_playing(Main_hall_intercom_sound_handle)){
1762 // increment the next sound
1763 if(Main_hall_next_intercom_sound >= (Main_hall->num_random_intercom_sounds-1)){
1764 Main_hall_next_intercom_sound = 0;
1766 Main_hall_next_intercom_sound++;
1769 // set the timestamp
1770 Main_hall_next_intercom_sound_stamp = timestamp((int)(((float)rand()/(float)RAND_MAX) *
1771 (float)(Main_hall->intercom_delay[Main_hall_next_intercom_sound][1]
1772 - Main_hall->intercom_delay[Main_hall_next_intercom_sound][0])) );
1774 // release the sound handle
1775 Main_hall_intercom_sound_handle = -1;
1780 // set the notification string with its decay timeout
1781 void main_hall_set_notify_string(char *str)
1783 strcpy(Main_hall_notify_text,str);
1784 Main_hall_notify_stamp = timestamp(MAIN_HALL_NOTIFY_TIME);
1787 void main_hall_notify_do()
1789 // check to see if we should try and do something
1790 if(Main_hall_notify_stamp != -1){
1791 // if the text time has expired
1792 if(timestamp_elapsed(Main_hall_notify_stamp)){
1793 strcpy(Main_hall_notify_text,"");
1794 Main_hall_notify_stamp = -1;
1797 gr_set_color_fast(&Color_bright);
1799 gr_get_string_size(&w,&h,Main_hall_notify_text);
1800 gr_printf((gr_screen.max_w - w)/2, gr_screen.max_h - 40, Main_hall_notify_text);
1805 // start a looping ambient sound for main hall
1806 void main_hall_start_ambient()
1808 int play_ambient_loop = 0;
1810 if ( Main_hall_ambient_loop == -1 ) {
1811 play_ambient_loop = 1;
1813 if ( !snd_is_playing(Main_hall_ambient_loop) ) {
1814 play_ambient_loop = 1;
1818 if ( play_ambient_loop ) {
1819 Main_hall_ambient_loop = snd_play_looping(&Snds_iface[SND_MAIN_HALL_AMBIENT]);
1823 // stop a looping ambient sound for the main hall
1824 void main_hall_stop_ambient()
1826 if ( Main_hall_ambient_loop != -1 ) {
1827 snd_stop(Main_hall_ambient_loop);
1828 Main_hall_ambient_loop = -1;
1832 // Reset the volume of the looping ambient sound. This is called from the options
1833 // screen when the looping ambient sound might be playing.
1834 void main_hall_reset_ambient_vol()
1836 if ( Main_hall_ambient_loop >= 0 ) {
1837 snd_set_volume(Main_hall_ambient_loop, Snds_iface[SND_MAIN_HALL_AMBIENT].default_volume);
1841 // blit the freespace version #
1842 void main_hall_blit_version()
1844 char version_string[100];
1847 // format the version string
1848 get_version_string(version_string);
1850 // get the length of the string
1851 gr_get_string_size(&w,NULL,version_string);
1853 // print the string out in the lower right corner
1854 gr_set_color_fast(&Color_white);
1855 gr_string(gr_screen.max_w - 55, gr_screen.max_h - 12, version_string);
1858 // blit any necessary tooltips
1859 void main_hall_maybe_blit_tooltips()
1864 // if we're over no region - don't blit anything
1865 if(Main_hall_mouse_region < 0) {
1869 // get the index of the proper text to be using
1870 if(Main_hall_mouse_region == READY_ROOM_REGION) {
1871 // if this is a multiplayer pilot, the ready room region becomes the multiplayer region
1872 if(Player->flags & PLAYER_FLAGS_IS_MULTI){
1873 text_index = NUM_REGIONS - 1;
1875 text_index = READY_ROOM_REGION;
1878 text_index = Main_hall_mouse_region;
1881 // set the color and blit the string
1882 if(!help_overlay_active(Main_hall_overlay_id)) {
1883 int shader_y = (Main_hall->region_yval) - Main_hall_tooltip_padding[gr_screen.res]; // subtract more to pull higher
1884 // get the width of the string
1885 gr_get_string_size(&w, NULL, Main_hall->region_descript[text_index]);
1887 gr_set_shader(&Main_hall_tooltip_shader);
1888 gr_shade(0, shader_y, gr_screen.clip_width, (gr_screen.clip_height - shader_y));
1890 gr_set_color_fast(&Color_bright_white);
1891 gr_string((gr_screen.max_w - w)/2, Main_hall->region_yval, Main_hall->region_descript[text_index]);
1896 void main_hall_process_help_stuff()
1901 // if the timestamp has popped, don't do anything
1902 if(Main_hall_help_stamp == -1) {
1906 // if the timestamp has popped, advance frame
1907 if(timestamp_elapsed(Main_hall_help_stamp)) {
1908 Main_hall_f1_text_frame++;
1911 // otherwise print out the message
1912 strcpy(str, XSTR( "Press F1 for help", 371));
1913 gr_get_string_size(&w, &h, str);
1915 int y_anim_offset = Main_hall_f1_text_frame;
1917 // if anim is off the screen finally, stop altogether
1918 if ( (y_anim_offset >= (2*Main_hall_tooltip_padding[gr_screen.res]) + h) || (help_overlay_active(Main_hall_overlay_id)) ) {
1919 Main_hall_f1_text_frame = -1;
1920 Main_hall_help_stamp = -1;
1925 // set the color and print out text and shader
1926 gr_set_color_fast(&Color_bright_white);
1927 gr_shade(0, 0, gr_screen.max_w, (2*Main_hall_tooltip_padding[gr_screen.res]) + h - y_anim_offset);
1928 gr_string((gr_screen.max_w - w)/2, Main_hall_tooltip_padding[gr_screen.res] - y_anim_offset, str);
1931 // what main hall we're on (should be 0 or 1)
1934 // only 1 of 2 main halls
1935 if(Main_hall == &Main_hall_defines[gr_screen.res][0]){
1942 // read in main hall table
1943 void main_hall_read_table()
1945 main_hall_defines *m, temp;
1946 int count, idx, s_idx, m_idx;
1949 read_file_text("mainhall.tbl");
1954 while(!optional_string("#end")){
1956 // read in 2 resolutions
1957 for(m_idx=0; m_idx<GR_NUM_RESOLUTIONS; m_idx++){
1958 // maybe use a temp main hall stuct
1959 if(count >= NUM_MAIN_HALLS){
1962 m = &Main_hall_defines[m_idx][count];
1966 required_string("$Main Hall");
1969 required_string("+Bitmap:");
1970 stuff_string(m->bitmap, F_NAME, NULL, MAX_FILENAME_LEN);
1971 required_string("+Mask:");
1972 stuff_string(m->mask, F_NAME, NULL, MAX_FILENAME_LEN);
1973 required_string("+Music:");
1974 stuff_string(m->music, F_NAME, NULL, MAX_FILENAME_LEN);
1977 required_string("+Num Intercom Sounds:");
1978 stuff_int(&m->num_random_intercom_sounds);
1979 for(idx=0; idx<m->num_random_intercom_sounds; idx++){
1981 required_string("+Intercom delay:");
1982 stuff_int(&m->intercom_delay[idx][0]);
1983 stuff_int(&m->intercom_delay[idx][1]);
1985 for(idx=0; idx<m->num_random_intercom_sounds; idx++){
1986 // intercom sound id
1987 required_string("+Intercom sound:");
1988 stuff_int(&m->intercom_sounds[idx]);
1990 for(idx=0; idx<m->num_random_intercom_sounds; idx++){
1992 required_string("+Intercom pan:");
1993 stuff_float(&m->intercom_sound_pan[idx]);
1997 required_string("+Num Misc Animations:");
1998 stuff_int(&m->num_misc_animations);
1999 for(idx=0; idx<m->num_misc_animations; idx++){
2001 required_string("+Misc anim:");
2002 stuff_string(m->misc_anim_name[idx], F_NAME, NULL);
2004 for(idx=0; idx<m->num_misc_animations; idx++){
2006 required_string("+Misc anim delay:");
2007 stuff_int(&m->misc_anim_delay[idx][0]);
2008 stuff_int(&m->misc_anim_delay[idx][1]);
2009 stuff_int(&m->misc_anim_delay[idx][2]);
2011 for(idx=0; idx<m->num_misc_animations; idx++){
2013 required_string("+Misc anim coords:");
2014 stuff_int(&m->misc_anim_coords[idx][0]);
2015 stuff_int(&m->misc_anim_coords[idx][1]);
2017 for(idx=0; idx<m->num_misc_animations; idx++){
2019 required_string("+Misc anim mode:");
2020 stuff_int(&m->misc_anim_modes[idx]);
2022 for(idx=0; idx<m->num_misc_animations; idx++){
2024 required_string("+Misc anim pan:");
2025 stuff_float(&m->misc_anim_sound_pan[idx]);
2027 for(idx=0; idx<m->num_misc_animations; idx++){
2029 required_string("+Misc anim sounds:");
2030 stuff_int(&m->misc_anim_special_sounds[idx][0]);
2031 for(s_idx=0; s_idx<m->misc_anim_special_sounds[idx][0]; s_idx++){
2032 stuff_int(&m->misc_anim_special_sounds[idx][s_idx + 1]);
2035 for(idx=0; idx<m->num_misc_animations; idx++){
2036 // anim sound triggers
2037 required_string("+Misc anim trigger:");
2038 stuff_int(&m->misc_anim_special_trigger[idx][0]);
2039 for(s_idx=0; s_idx<m->misc_anim_special_trigger[idx][0]; s_idx++){
2040 stuff_int(&m->misc_anim_special_trigger[idx][s_idx + 1]);
2043 for(idx=0; idx<m->num_misc_animations; idx++){
2044 // anim sound handles
2045 required_string("+Misc anim handles:");
2046 stuff_int(&m->misc_anim_sound_handles[idx][0]);
2048 for(idx=0; idx<m->num_misc_animations; idx++){
2050 required_string("+Misc anim flags:");
2051 stuff_int(&m->misc_anim_sound_flag[idx][0]);
2055 required_string("+Num Door Animations:");
2056 stuff_int(&m->num_door_animations);
2057 for(idx=0; idx<m->num_door_animations; idx++){
2059 required_string("+Door anim:");
2060 stuff_string(m->door_anim_name[idx], F_NAME, NULL);
2062 for(idx=0; idx<m->num_door_animations; idx++){
2064 required_string("+Door coords:");
2065 stuff_int(&m->door_anim_coords[idx][0]);
2066 stuff_int(&m->door_anim_coords[idx][1]);
2067 stuff_int(&m->door_anim_coords[idx][2]);
2068 stuff_int(&m->door_anim_coords[idx][3]);
2070 for(idx=0; idx<m->num_door_animations; idx++){
2071 // door open and close sounds
2072 required_string("+Door sounds:");
2073 stuff_int(&m->door_sounds[idx][0]);
2074 stuff_int(&m->door_sounds[idx][1]);
2076 for(idx=0; idx<m->num_door_animations; idx++){
2078 required_string("+Door pan:");
2079 stuff_float(&m->door_sound_pan[idx]);
2082 // tooltip y location
2083 required_string("+Tooltip Y:");
2084 stuff_int(&m->region_yval);
2085 for(idx=0; idx<NUM_REGIONS; idx++){
2086 m->region_descript[idx] = NULL;
2090 if(count < NUM_MAIN_HALLS){
2097 Main_hall_defines[GR_640][1].door_sounds[OPTIONS_REGION][0] = SND_VASUDAN_BUP;
2098 Main_hall_defines[GR_640][1].door_sounds[OPTIONS_REGION][1] = SND_VASUDAN_BUP;
2099 Main_hall_defines[GR_1024][1].door_sounds[OPTIONS_REGION][0] = SND_VASUDAN_BUP;
2100 Main_hall_defines[GR_1024][1].door_sounds[OPTIONS_REGION][1] = SND_VASUDAN_BUP;
2102 // set head anim. hehe
2103 strcpy(Main_hall_defines[GR_640][1].door_anim_name[OPTIONS_REGION], "vhallheads");
2104 strcpy(Main_hall_defines[GR_1024][1].door_anim_name[OPTIONS_REGION], "2_vhallheads");
2106 // set the background
2107 strcpy(Main_hall_defines[GR_640][1].bitmap, "vhallhead");
2108 strcpy(Main_hall_defines[GR_1024][1].bitmap, "2_vhallhead");
2112 // make the vasudan main hall funny
2113 void main_hall_vasudan_funny()
2132 vector sun_pos = vmd_zero_vector;
2136 argh = bm_load("sun01");
2137 bm_lock(argh, 16, BMP_TEX_XPARENT);
2142 g3_set_view_matrix(&vmd_zero_vector, &view, 0.5f);
2143 g3_rotate_vertex(&p1, &sun_pos);
2144 g3_project_vertex(&p1);
2145 gr_zbuffer_set(GR_ZBUFF_NONE);
2146 gr_set_bitmap( argh );
2147 g3_draw_bitmap(&p1, 0, 0.05f, TMAP_FLAG_TEXTURED | TMAP_FLAG_XPARENT);