2 * $Logfile: /Freespace2/code/MenuUI/MainHallMenu.cpp $
7 * Header file for main-hall menu code
10 * Revision 1.2 2002/05/27 22:43:02 theoddone33
11 * Fix more glide symbols
13 * Revision 1.1.1.1 2002/05/03 03:28:09 root
17 * 62 10/28/99 2:04a Jefff
20 * 61 9/15/99 6:28p Dave
21 * No load mission button in RELEASE_REAL
23 * 60 9/13/99 4:52p Dave
26 * 59 9/13/99 11:30a Dave
27 * Added checkboxes and functionality for disabling PXO banners as well as
28 * disabling d3d zbuffer biasing.
30 * 58 9/07/99 6:55p Jefff
31 * added jump-to-campaign-mission cheat
33 * 57 9/07/99 4:01p Dave
34 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
35 * does everything properly (setting up address when binding). Remove
36 * black rectangle background from UI_INPUTBOX.
38 * 56 9/06/99 6:38p Dave
39 * Improved CD detection code.
41 * 55 9/06/99 1:30a Dave
42 * Intermediate checkin. Started on enforcing CD-in-drive to play the
45 * 54 9/03/99 1:31a Dave
46 * CD checking by act. Added support to play 2 cutscenes in a row
47 * seamlessly. Fixed super low level cfile bug related to files in the
48 * root directory of a CD. Added cheat code to set campaign mission # in
51 * 53 9/01/99 11:02p Dave
52 * Made head guy look right when not animating.
54 * 52 8/27/99 12:04a Dave
55 * Campaign loop screen.
57 * 51 8/26/99 9:45a Dave
58 * First pass at easter eggs and cheats.
60 * 50 8/25/99 11:57a Jefff
61 * freespace -> freespace 2 in tooltip strings
63 * 49 8/25/99 10:50a Dave
64 * Added music to the mainhall.tbl
66 * 48 8/24/99 8:55p Dave
67 * Make sure nondimming pixels work properly in tech menu.
69 * 47 8/18/99 11:44a Jefff
72 * 46 8/10/99 4:45p Jefff
75 * 45 8/06/99 1:01p Andsager
76 * disable quick start (g) for demo
78 * 44 8/05/99 10:34a Jefff
79 * more mouseover sound fixes
81 * 43 8/04/99 9:12p Andsager
82 * Add campaign room popup allowing restart of campaign in demo.
84 * 42 8/04/99 5:36p Dave
85 * Make glide and D3D switch out properly.
87 * 41 8/04/99 4:35p Jefff
88 * fixed tech room & options sounds playing only once
90 * 40 8/03/99 5:41p Jefff
91 * made "f1 for help" draw after animations, and stop if help overlay
94 * 39 8/03/99 4:42p Jefff
97 * 38 8/03/99 3:48p Jefff
99 * 37 8/02/99 9:13p Dave
102 * 36 8/02/99 2:26p Jefff
103 * "press f1.." text reworked
105 * 35 8/02/99 12:19p Andsager
106 * disable "L" load screen
108 * 34 8/02/99 11:12a Jefff
109 * adjusted tooltip shader stuff for more a more pleasing effect.
111 * 33 7/30/99 6:05p Jefff
112 * added shader behind tooltip text
114 * 32 7/30/99 4:20p Andsager
115 * Added user click sounds to main hall
117 * 31 7/29/99 10:47p Dave
118 * Standardized D3D fogging using vertex fog. Shook out Savage 4 bugs.
120 * 30 7/27/99 6:53p Dave
121 * Hi-res main hall support.
123 * 29 7/16/99 1:49p Dave
124 * 8 bit aabitmaps. yay.
126 * 28 7/15/99 9:20a Andsager
127 * FS2_DEMO initial checkin
129 * 27 7/13/99 1:15p Dave
130 * 32 bit support. Whee!
132 * 26 6/25/99 2:51p Jasons
133 * Changed wording of network error message.
135 * 25 6/21/99 1:30p Alanl
136 * changed main menu music tag
138 * 24 6/19/99 3:56p Dave
139 * Moved main hall definitions into a table file. Whee!
141 * 23 6/11/99 11:13a Dave
142 * last minute changes before press tour build.
144 * 22 5/09/99 8:57p Dave
145 * Final E3 build preparations.
147 * 21 4/25/99 3:02p Dave
148 * Build defines for the E3 build.
150 * 20 4/12/99 10:07p Dave
151 * Made network startup more forgiving. Added checkmarks to dogfight
152 * screen for players who hit commit.
154 * 19 3/28/99 5:58p Dave
155 * Added early demo code. Make objects move. Nice and framerate
156 * independant, but not much else. Don't use yet unless you're me :)
158 * 18 3/25/99 5:47p Dave
161 * 17 3/19/99 9:51a Dave
162 * Checkin to repair massive source safe crash. Also added support for
163 * pof-style nebulae, and some new weapons code.
165 * 16 2/25/99 4:19p Dave
166 * Added multiplayer_beta defines. Added cd_check define. Fixed a few
167 * release build warnings. Added more data to the squad war request and
170 * 15 2/03/99 11:44a Dave
171 * Fixed d3d transparent textures.
173 * 14 1/30/99 5:08p Dave
174 * More new hi-res stuff.Support for nice D3D textures.
176 * 13 1/27/99 9:56a Dave
177 * Temporary checkin of beam weapons for Dan to make cool sounds.
179 * 12 12/31/98 11:23a Dave
180 * Put mini-indicators for status of ships.tbl and weapons.tbl in the
181 * lower left corner of the main hall.
183 * 11 12/18/98 1:13a Dave
184 * Rough 1024x768 support for Direct3D. Proper detection and usage through
187 * 10 11/30/98 1:07p Dave
188 * 16 bit conversion, first run.
190 * 9 11/20/98 4:08p Dave
191 * Fixed flak effect in multiplayer.
193 * 8 11/20/98 11:16a Dave
194 * Fixed up IPX support a bit. Making sure that switching modes and
195 * loading/saving pilot files maintains proper state.
197 * 7 11/19/98 4:57p Dave
198 * Ignore PXO option if IPX is selected.
200 * 6 11/19/98 4:19p Dave
201 * Put IPX sockets back in psnet. Consolidated all multiplayer config
204 * 5 11/05/98 5:55p Dave
205 * Big pass at reducing #includes
207 * 4 11/05/98 4:18p Dave
208 * First run nebula support. Beefed up localization a bit. Removed all
209 * conditional compiles for foreign versions. Modified mission file
212 * 3 10/13/98 9:28a Dave
213 * Started neatening up freespace.h. Many variables renamed and
214 * reorganized. Added AlphaColors.[h,cpp]
216 * 2 10/07/98 10:53a Dave
219 * 1 10/07/98 10:49a Dave
221 * 103 10/02/98 3:22p Allender
222 * fix up the -connect option and fix the -port option
224 * 102 8/20/98 5:31p Dave
225 * Put in handy multiplayer logfile system. Now need to put in useful
226 * applications of it all over the code.
228 * 101 8/07/98 10:40a Allender
229 * new command line flags for starting netgames. Only starting currently
230 * works, and PXO isn't implemented yet
232 * 100 7/13/98 10:46a Lawrance
233 * Index another localized string
235 * 99 7/10/98 1:13a Allender
236 * lots of small multiplayer update changes. Code in launcher to specify
237 * connection speed. A couple of small fixes regarding empty mission
238 * files. Time out players after 10 second when they don't connect on
239 * their reliable socket.
241 * 98 6/09/98 10:31a Hoffoss
242 * Created index numbers for all xstr() references. Any new xstr() stuff
243 * added from here on out should be added to the end if the list. The
244 * current list count can be found in FreeSpace.cpp (search for
247 * 97 6/05/98 9:50a Lawrance
250 * 96 6/01/98 11:43a John
251 * JAS & MK: Classified all strings for localization.
253 * 95 5/22/98 9:02p Allender
254 * remove G key from main hall
256 * 94 5/22/98 10:54a Allender
257 * new dialog information for networking to tell user if connection type
258 * doesn't match the setup specified type
260 * 93 5/15/98 5:15p Dave
261 * Fix a standalone resetting bug.Tweaked PXO interface. Display captaincy
262 * status for team vs. team. Put in asserts to check for invalid team vs.
265 * 92 5/13/98 12:23a Lawrance
266 * Don't init main hall if already inited... not needed now, but may be
267 * useful if we don't always want to call main_hall_close() when switching
270 * 91 5/12/98 2:46a Dave
271 * Rudimentary communication between Parallax Online and freespace. Can
272 * get and store channel lists.
274 * 90 5/08/98 5:33p Lawrance
275 * check for CD when trying to enter ready room in single player
282 #include "mainhallmenu.h"
286 #include "gamesequence.h"
287 #include "animplay.h"
291 #include "snazzyui.h"
293 #include "audiostr.h"
295 #include "eventmusic.h"
297 #include "contexthelp.h"
301 #include "multiutil.h"
305 #include "playermenu.h"
306 #include "freespace.h"
307 #include "multi_voice.h"
309 #include "alphacolors.h"
311 #include "fishtank.h"
313 // #include "movie.h"
315 // ----------------------------------------------------------------------------
316 // MAIN HALL DATA DEFINES
318 #define MAX_RANDOM_INTERCOM_SOUNDS 10
319 #define NUM_RANDOM_INTERCOM_SOUNDS_0 3
320 #define NUM_RANDOM_INTERCOM_SOUNDS_1 3
322 #define MAX_MISC_ANIMATIONS 10
323 #define NUM_MISC_ANIMATIONS_0 2
324 #define NUM_MISC_ANIMATIONS_1 4
326 #define MAX_DOOR_ANIMATIONS 10
327 #define NUM_DOOR_ANIMATIONS_0 6
328 #define NUM_DOOR_ANIMATIONS_1 6
330 #define MAX_DOOR_SOUNDS 10
331 #define NUM_DOOR_SOUNDS_0 6
332 #define NUM_DOOR_SOUNDS_1 6
334 #define MISC_ANIM_MODE_LOOP 0 // loop the animation
335 #define MISC_ANIM_MODE_HOLD 1 // play to the end and hold the animation
336 #define MISC_ANIM_MODE_TIMED 2 // uses timestamps to determine when a finished anim should be checked again
338 #define NUM_REGIONS 7 // (6 + 1 for multiplayer equivalent of campaign room)
339 typedef struct main_hall_defines {
341 char bitmap[MAX_FILENAME_LEN+1];
342 char mask[MAX_FILENAME_LEN+1];
345 char music[MAX_FILENAME_LEN+1];
347 // intercom defines -------------------
349 // # of intercom sounds
350 int num_random_intercom_sounds;
352 // random (min/max) delays between playing intercom sounds
353 int intercom_delay[MAX_RANDOM_INTERCOM_SOUNDS][2];
355 // intercom sounds themselves
356 int intercom_sounds[MAX_RANDOM_INTERCOM_SOUNDS];
358 // intercom sound pan values
359 float intercom_sound_pan[MAX_RANDOM_INTERCOM_SOUNDS];
362 // misc animations --------------------
364 // # of misc animations
365 int num_misc_animations;
367 // filenames of the misc animations
368 char misc_anim_name[MAX_MISC_ANIMATIONS][MAX_FILENAME_LEN+1];
370 // Time until we will next play a given misc animation, min delay, and max delay
371 int misc_anim_delay[MAX_MISC_ANIMATIONS][3];
373 // coords of where to play the misc anim
374 int misc_anim_coords[MAX_MISC_ANIMATIONS][2];
376 // misc anim play modes (see MISC_ANIM_MODE_* above)
377 int misc_anim_modes[MAX_MISC_ANIMATIONS];
379 // panning values for each of the misc anims
380 float misc_anim_sound_pan[MAX_MISC_ANIMATIONS];
382 // [N][0] == # of sounds, [N][1-9] sound index
383 int misc_anim_special_sounds[MAX_MISC_ANIMATIONS][10];
385 // [N][0] == # of triggers, [N][1-9] >= frame num
386 int misc_anim_special_trigger[MAX_MISC_ANIMATIONS][10];
388 // [N][0] == # of handles, [N][1-9] == sound handle num
389 int misc_anim_sound_handles[MAX_MISC_ANIMATIONS][10];
391 // [N][0] == # of handles, [N][1-9] == sound "should" be playing
392 int misc_anim_sound_flag[MAX_MISC_ANIMATIONS][10];
395 // door animations --------------------
397 // # of door animations
398 int num_door_animations;
400 // filenames of the door animations
401 char door_anim_name[MAX_DOOR_ANIMATIONS][MAX_FILENAME_LEN+1];
403 // first pair : coords of where to play a given door anim
404 // second pair : center of a given door anim in windowed mode
405 int door_anim_coords[MAX_DOOR_ANIMATIONS][4];
408 // door sounds ------------------------
413 // sounds for each region (open/close)
414 int door_sounds[MAX_DOOR_SOUNDS][2];
416 // pan values for the door sounds
417 float door_sound_pan[MAX_DOOR_SOUNDS];
420 // region descriptions ----------------
422 // text (tooltip) description
423 char *region_descript[NUM_REGIONS];
425 // y coord of where to draw tooltip text
431 // use main hall 0 by default
432 main_hall_defines Main_hall_defines[GR_NUM_RESOLUTIONS][NUM_MAIN_HALLS];
433 main_hall_defines *Main_hall = &Main_hall_defines[0][0];
435 int Vasudan_funny = 0;
436 int Vasudan_funny_plate = -1;
438 char Main_hall_campaign_cheat[512] = "";
440 // ----------------------------------------------------------------------------
441 // MISC interface data
443 // is the main hall inited (for reentrancy)
444 int Main_hall_inited = 0;
446 // handle to the playing music
447 int Main_hall_music_handle = -1;
449 // background bitmap handle
450 int Main_hall_bitmap;
452 // background bitmap mask handle
455 // variable used for automatic netgame starting/joining
456 int Main_hall_netgame_started = 0;
458 // bitmap struct for th background mask bitmap
459 bitmap *Main_hall_mask_bitmap;
461 // actual data for the background mask bitmap
462 ubyte *Main_hall_mask_data;
464 int Main_hall_mask_w, Main_hall_mask_h;
467 // ----------------------------------------------------------------------------
468 // MOUSE clicking stuff
470 // indicates whether a right click occured
471 int Main_hall_right_click;
473 // use this to cycle through the selectable regions instead of the mouse's current region
474 int Main_hall_last_clicked_region;
476 // use this to determine how long the cursor has to linger on a region before it starts playing
477 #define MAIN_HALL_REGION_LINGER 175 // in ms
478 int Main_hall_region_linger_stamp = -1;
480 // handle any right clicks which may have occured
481 void main_hall_handle_right_clicks();
484 // ----------------------------------------------------------------------------
485 // RANDOM intercom sounds
488 // next random intercom sound to play
489 int Main_hall_next_intercom_sound = 0;
491 // delay for the next intercom sound
492 int Main_hall_next_intercom_sound_stamp = -1;
494 // handle to any playing instance of a random intercom sound
495 int Main_hall_intercom_sound_handle = -1;
497 // handle any details related to random intercom sounds
498 void main_hall_handle_random_intercom_sounds();
501 // ----------------------------------------------------------------------------
505 // the misc animations themselves
506 anim *Main_hall_misc_anim[MAX_MISC_ANIMATIONS];
508 // the instance of a given misc animation
509 anim_instance *Main_hall_misc_anim_instance[MAX_MISC_ANIMATIONS];
511 // handle starting, stopping and randomizing misc animations
512 void main_hall_handle_misc_anims();
514 // cull any finished misc animation instances
515 void main_hall_cull_misc_anim_instances();
517 // render all playing misc animations
518 void main_hall_render_misc_anims(float frametime);
521 // ----------------------------------------------------------------------------
522 // DOOR animations (not all of these are doors anymore, but they're doorlike _regions_)
524 #define DOOR_TEXT_X 100
525 #define DOOR_TEXT_Y 450
527 // the door animations themselves
528 anim *Main_hall_door_anim[MAX_DOOR_ANIMATIONS];
530 // the instance of a given door animation
531 anim_instance *Main_hall_door_anim_instance[MAX_DOOR_ANIMATIONS];
533 // render all playing door animations
534 void main_hall_render_door_anims(float frametime);
537 // ----------------------------------------------------------------------------
540 #define NUM_MAIN_HALL_REGIONS 10
541 #define NUM_MAIN_HALL_MOUSE_REGIONS 6
543 // region mask #'s (identifiers)
544 #define EXIT_REGION 0
545 #define BARRACKS_REGION 1
546 #define READY_ROOM_REGION 2
547 #define TECH_ROOM_REGION 3
548 #define OPTIONS_REGION 4
549 #define CAMPAIGN_ROOM_REGION 5
550 #define MULTIPLAYER_REGION 10
551 #define LOAD_MISSION_REGION 11
552 #define QUICK_START_REGION 12
553 #define SKILL_LEVEL_REGION 13
555 // all the menu regions in the main hall
556 MENU_REGION Main_hall_region[NUM_MAIN_HALL_REGIONS];
558 // # of regions (options) on this screen. parsed from a table
559 int Main_hall_num_options;
561 // region over which the mouse is currently residing, or -1 if over no region
562 // NOTE : you should nevery change this directly. Always use main_hall_handle_mouse_location(int)
563 // to do this. Otherwise, the door opening and closing animations will get screwed up
564 int Main_hall_mouse_region;
566 // set this to skip a frame
567 int Main_hall_frame_skip;
569 // do any necessary processing based upon the mouse location
570 void main_hall_handle_mouse_location(int cur_region);
572 // if the mouse has moved off of the currently active region, handle the anim accordingly
573 void main_hall_mouse_release_region(int region);
575 // if the mouse has moved on this region, handle it accordingly
576 void main_hall_mouse_grab_region(int region);
579 // ----------------------------------------------------------------------------
580 // SOUND data / handlers
583 // toaster oven room sound idex
584 #define TOASTER_REGION 3
586 // everyone's favorite desk guardian
587 #define ALLENDER_REGION 4
589 // handles to the sound instances of the doors opening/closing
590 int Main_hall_door_sound_handles[MAX_DOOR_SOUNDS] = {
594 // sound handle for looping ambient sound
595 int Main_hall_ambient_loop = -1;
597 // cull any door sounds that have finished playing
598 void main_hall_cull_door_sounds();
600 // handle starting, stopping and reversing "door" animations
601 void main_hall_handle_region_anims();
604 // ----------------------------------------------------------------------------
605 // warning/notification messages
607 #define MAIN_HALL_NOTIFY_TIME 3500
609 // timestamp for the notification messages
610 int Main_hall_notify_stamp = -1;
612 // text to display as the current notification message
613 char Main_hall_notify_text[300]="";
615 // set the current notification string and the associated timestamp
616 void main_hall_set_notify_string(char *str);
618 // handle any drawing, culling, etc of notification messages
619 void main_hall_notify_do();
622 // ----------------------------------------------------------------------------
626 // upper _RIGHT_ corner for the version text
627 #define MAIN_HALL_VERSION_X 630
628 #define MAIN_HALL_VERSION_Y 467
630 // main hall help overlay ID
631 int Main_hall_overlay_id;
633 // blit the freespace version #
634 void main_hall_blit_version();
636 // blit any necessary tooltips
637 void main_hall_maybe_blit_tooltips();
639 // shader for behind tooltips
640 shader Main_hall_tooltip_shader;
642 // num pixels shader is above/below tooltip text
643 static int Main_hall_tooltip_padding[GR_NUM_RESOLUTIONS] = {
647 static int Main_hall_f1_text_frame = 0;
648 static int F1_text_done = 0;
650 // read in main hall table
651 void main_hall_read_table();
653 // "press f1" for help stuff
654 #define MAIN_HALL_HELP_TIME 5000
655 int Main_hall_help_stamp = -1;
656 void main_hall_process_help_stuff();
659 // ----------------------------------------------------------------------------
660 // VOICE RECORDING STUFF
663 // are we currently recording voice?
667 // called when multiplayer clicks on the ready room door. May pop up dialog depending on network
668 // connection status and errors
669 void main_hall_do_multi_ready()
673 error = psnet_get_network_status();
675 case NETWORK_ERROR_NO_TYPE:
676 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));
678 case NETWORK_ERROR_NO_WINSOCK:
679 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));
681 case NETWORK_ERROR_NO_PROTOCOL:
682 if(Multi_options_g.protocol == NET_TCP){
683 popup( PF_NO_NETWORKING, 1, POPUP_OK, XSTR( "TCP/IP protocol not found. This protocol is required for multiplayer FreeSpace.", 362));
685 Assert(Multi_options_g.protocol == NET_IPX);
686 popup( PF_NO_NETWORKING, 1, POPUP_OK, XSTR( "IPX protocol not found. This protocol is required for multiplayer FreeSpace.", 362));
689 case NETWORK_ERROR_CONNECT_TO_ISP:
690 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));
692 case NETWORK_ERROR_LAN_AND_RAS:
693 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));
696 case NETWORK_ERROR_NONE:
701 // if our selected protocol is not active
702 if((Multi_options_g.protocol == NET_TCP) && !Tcp_active){
703 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));
706 if((Multi_options_g.protocol == NET_IPX) && !Ipx_active){
707 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));
711 if ( error != NETWORK_ERROR_NONE ){
715 // 7/9/98 -- MWA. Deal with the connection speed issue. make a call to the multiplayer code to
716 // determine is a valid connection setting exists
717 if ( Multi_connection_speed == CONNECTION_SPEED_NONE ) {
718 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) );
722 // go to parallax online
723 #ifdef MULTIPLAYER_BETA_BUILD // do we want this for FS2_DEMO
724 Multi_options_g.pxo = 1;
725 Multi_options_g.protocol = NET_TCP;
726 gameseq_post_event( GS_EVENT_PXO );
729 // go to the regular join game screen
730 gameseq_post_event( GS_EVENT_MULTI_JOIN_GAME );
734 psnet_use_protocol(Multi_options_g.protocol);
737 // blit some small color indicators to show whether ships.tbl and weapons.tbl are valid
738 // green == valid, red == invalid.
739 // ships.tbl will be on the left, weapons.tbl on the right
740 int Mh_ship_table_status[GR_NUM_RESOLUTIONS][2] = {
744 int Mh_weapon_table_status[GR_NUM_RESOLUTIONS][2] = {
748 void main_hall_blit_table_status()
750 // blit ship table status
751 gr_set_color_fast(Game_ships_tbl_valid ? &Color_bright_green : &Color_bright_red);
752 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]);
754 // blit weapon table status
755 gr_set_color_fast(Game_weapons_tbl_valid ? &Color_bright_green : &Color_bright_red);
756 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]);
759 // bash the player to a specific mission in a campaign
760 void main_hall_campaign_cheat()
762 char *ret = popup_input(0, XSTR("Enter mission name.\n\n* This will destroy all legitimate progress in this campaign. *", -1));
766 // strcpy(Main_hall_campaign_cheat, ret);
767 mission_campaign_jump_to_mission(ret);
771 // -------------------------------------------------------------------------------------------------------------------
772 // FUNCTION DEFINITIONS BEGIN
775 // initialize the main hall proper
776 void main_hall_init(int main_hall_num)
778 if ( Main_hall_inited ) {
783 char temp[100], whee[100];
785 // read in the main hall table
786 main_hall_read_table();
788 // create the snazzy interface and load up the info from the table
790 read_menu_tbl(NOX("MAIN HALL"), temp, whee, Main_hall_region, &Main_hall_num_options, 0);
792 // assign the proper main hall data
793 Assert((main_hall_num >= 0) && (main_hall_num < NUM_MAIN_HALLS));
794 Main_hall = &Main_hall_defines[gr_screen.res][main_hall_num];
797 Main_hall->region_descript[0] = XSTR( "Exit FreeSpace 2", 353);
798 Main_hall->region_descript[1] = XSTR( "Barracks - Manage your FreeSpace 2 pilots", 354);
799 Main_hall->region_descript[2] = XSTR( "Ready room - Start or continue a campaign", 355);
800 Main_hall->region_descript[3] = XSTR( "Tech room - View specifications of FreeSpace 2 ships and weaponry", 356);
801 Main_hall->region_descript[4] = XSTR( "Options - Change your FreeSpace 2 options", 357);
802 Main_hall->region_descript[5] = XSTR( "Campaign Room - View all available campaigns", 358);
803 Main_hall->region_descript[6] = XSTR( "Multiplayer - Start or join a multiplayer game", 359);
805 // init tooltip shader
806 float gray_intensity = 0.02f; // nearly black
807 float c = (gr_screen.mode == GR_DIRECT3D) ? 0.11f : 0.07f; // adjust for renderer differences
808 gr_create_shader(&Main_hall_tooltip_shader, gray_intensity, gray_intensity, gray_intensity, c);
810 // load the background bitmap
811 Main_hall_bitmap = bm_load(Main_hall->bitmap);
812 if(Main_hall_bitmap < 0){
813 nprintf(("General","WARNING! Couldn't load main hall background bitmap %s\n", Main_hall->bitmap));
816 // remove any multiplayer flags from the game mode
817 Game_mode &= ~(GM_MULTIPLAYER);
819 // set the interface palette
820 #ifndef HARDWARE_ONLY
821 palette_use_bm_palette(Main_hall_bitmap);
824 Main_hall_mask_w = -1;
825 Main_hall_mask_h = -1;
828 Main_hall_mask = bm_load(Main_hall->mask);
829 if (Main_hall_mask < 0) {
830 Error(LOCATION,"Could not load in %s!", Main_hall->mask);
832 // get a pointer to bitmap by using bm_lock(), so we can feed it to he snazzy menu system
833 Main_hall_mask_bitmap = bm_lock(Main_hall_mask, 8, BMP_AABITMAP);
834 Main_hall_mask_data = (ubyte*)Main_hall_mask_bitmap->data;
835 bm_get_info(Main_hall_mask, &Main_hall_mask_w, &Main_hall_mask_h);
838 // load up the misc animations, and nullify all the delay timestamps for the misc animations
839 for(idx=0;idx<Main_hall->num_misc_animations;idx++) {
840 Main_hall_misc_anim[idx] = NULL;
841 Main_hall_misc_anim[idx] = anim_load(Main_hall->misc_anim_name[idx]);
842 if(Main_hall_misc_anim[idx] == NULL) {
843 nprintf(("General","WARNING!, Could not load misc %s anim in main hall\n",Main_hall->misc_anim_name));
846 // null out the animation instances
847 Main_hall_misc_anim_instance[idx] = NULL;
849 // null out the delay timestamps
850 Main_hall->misc_anim_delay[idx][0] = -1;
853 // load up the door animations
854 for(idx=0;idx<Main_hall->num_door_animations;idx++) {
855 Main_hall_door_anim[idx] = NULL;
856 Main_hall_door_anim[idx] = anim_load(Main_hall->door_anim_name[idx]);
857 if(Main_hall_door_anim[idx] == NULL){
858 nprintf(("General","WARNING!, Could not load door anim %s in main hall\n",Main_hall->door_anim_name[idx]));
861 // null out the animation instances
862 Main_hall_door_anim_instance[idx] = NULL;
865 // load in help overlay bitmap
866 if(Main_hall == &Main_hall_defines[gr_screen.res][0]) {
867 Main_hall_overlay_id = MH_OVERLAY;
869 Assert(Main_hall == &Main_hall_defines[gr_screen.res][1]);
870 Main_hall_overlay_id = MH2_OVERLAY;
872 help_overlay_load(Main_hall_overlay_id);
873 help_overlay_set_state(Main_hall_overlay_id,0);
875 // check to see if the "very first pilot" flag is set, and load the overlay if so
877 if (Main_hall_f1_text_frame == 0) {
878 Main_hall_help_stamp = timestamp(MAIN_HALL_HELP_TIME);
885 if(Player_select_very_first_pilot) {
886 Main_hall_help_stamp = timestamp(MAIN_HALL_HELP_TIME);
888 // don't display the "press f1" message more than once
889 Player_select_very_first_pilot = 0;
891 Main_hall_help_stamp = -1;
894 Main_hall_region_linger_stamp = -1;
896 strcpy(Main_hall_campaign_cheat, "");
898 // zero out the door sounds
899 for(idx=0;idx<Main_hall->num_door_sounds;idx++){
900 Main_hall_door_sound_handles[idx] = -1;
903 // zero out the misc anim sounds
904 for(idx=0;idx<Main_hall->num_misc_animations;idx++){
905 for(s_idx = 1;s_idx < 10;s_idx++){
906 Main_hall->misc_anim_sound_handles[idx][s_idx] = -1;
907 Main_hall->misc_anim_sound_flag[idx][s_idx] = 0;
911 // skip the first frame
912 Main_hall_frame_skip = 1;
914 // initialize the music
915 main_hall_start_music();
917 // initialize the main hall notify text
918 Main_hall_notify_stamp = 1;
920 // initialize the random intercom sound stuff
921 Main_hall_next_intercom_sound = 0;
922 Main_hall_next_intercom_sound_stamp = -1;
923 Main_hall_intercom_sound_handle = -1;
925 // set the placement of the mouse cursor (start at the ready room)
926 Main_hall_mouse_region = -1;
927 Main_hall_last_clicked_region = READY_ROOM_REGION;
928 mouse_set_pos(Main_hall->door_anim_coords[READY_ROOM_REGION][2],Main_hall->door_anim_coords[READY_ROOM_REGION][3]);
930 Main_hall_inited = 1;
932 // determine if we have a right click
933 Main_hall_right_click = mouse_down(MOUSE_RIGHT_BUTTON);
935 // set the game_mode based on the type of player
936 Assert( Player != NULL );
937 if ( Player->flags & PLAYER_FLAGS_IS_MULTI ){
938 Game_mode = GM_MULTIPLAYER;
940 Game_mode = GM_NORMAL;
943 if ( (Cmdline_start_netgame || (Cmdline_connect_addr != NULL)) && !Main_hall_netgame_started ) {
944 Main_hall_netgame_started = 1;
945 main_hall_do_multi_ready();
949 void main_hall_exit_game()
951 #if defined(NDEBUG) || defined(INTERPLAYQA)
955 main_hall_stop_music();
956 main_hall_stop_ambient();
957 choice = popup( PF_NO_NETWORKING | PF_BODY_BIG, 2, POPUP_NO, POPUP_YES, XSTR( "Exit Game?", 365));
959 gameseq_post_event(GS_EVENT_QUIT_GAME);
961 main_hall_start_music();
962 main_hall_start_ambient();
965 gameseq_post_event(GS_EVENT_QUIT_GAME);
970 // do a frame for the main hall
971 void main_hall_do(float frametime)
973 int code, key, snazzy_action;
975 // need to ensure ambient is playing, since it may be stopped by a playing movie
976 main_hall_start_ambient();
978 // handle any animation details
979 main_hall_handle_misc_anims();
980 main_hall_handle_region_anims();
982 // handle any random intercom sound details
983 main_hall_handle_random_intercom_sounds();
985 // handle any mouse clicks
986 main_hall_handle_right_clicks();
988 // handle any sound details
989 main_hall_cull_door_sounds();
991 // process any keypresses/mouse events
993 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);
996 extern void game_process_cheats(int k);
997 game_process_cheats(key);
1001 snazzy_action = SNAZZY_CLICKED;
1007 // movie_play("endprt2b.mve", 0);
1011 // movie_play_two("endprt2a.mve", "endprt2b.mve", 0);
1014 main_hall_campaign_cheat();
1016 case KEY_DEBUGGED + KEY_D:
1017 demo_start_playback("test.fsd");
1024 // do any processing based upon what happened to the snazzy menu
1025 switch (snazzy_action) {
1027 main_hall_handle_mouse_location(code);
1030 case SNAZZY_CLICKED:
1032 // clicked on the exit region
1034 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1035 main_hall_exit_game();
1038 // clicked on the readyroom region
1039 case READY_ROOM_REGION:
1040 #ifdef MULTIPLAYER_BETA_BUILD
1041 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1042 Player->flags |= PLAYER_FLAGS_IS_MULTI;
1043 main_hall_do_multi_ready();
1044 #elif defined(E3_BUILD) || defined(PRESS_TOUR_BUILD)
1045 gameseq_post_event(GS_EVENT_NEW_CAMPAIGN);
1047 if (Player->flags & PLAYER_FLAGS_IS_MULTI){
1048 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1049 main_hall_do_multi_ready();
1051 if(strlen(Main_hall_campaign_cheat)){
1052 gameseq_post_event(GS_EVENT_CAMPAIGN_CHEAT);
1054 gameseq_post_event(GS_EVENT_NEW_CAMPAIGN);
1056 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1061 // clicked on the tech room region
1062 case TECH_ROOM_REGION:
1063 #if defined(FS2_DEMO)
1064 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1065 game_feature_not_in_demo_popup();
1067 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1068 gameseq_post_event( GS_EVENT_TECH_MENU );
1072 // clicked on the options region
1073 case OPTIONS_REGION:
1074 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1075 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
1078 // clicked on the campaign toom region
1079 case CAMPAIGN_ROOM_REGION:
1080 #if !defined(MULTIPLAYER_BETA_BUILD) && !defined(E3_BUILD) && !defined(PRESS_TOUR_BUILD)
1083 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1085 //game_feature_not_in_demo_popup();
1086 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.");
1087 if (reset_campaign == 1) {
1088 mission_campaign_savefile_delete(Campaign.filename);
1089 mission_campaign_load(Campaign.filename);
1090 mission_campaign_next_mission();
1095 if(Player->flags & PLAYER_FLAGS_IS_MULTI){
1096 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1097 main_hall_set_notify_string(XSTR( "Campaign Room not valid for multiplayer pilots", 366));
1099 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1100 gameseq_post_event(GS_EVENT_CAMPAIGN_ROOM);
1107 // clicked on the multiplayer region
1108 case MULTIPLAYER_REGION:
1109 #if defined(DEMO) || defined(OEM_BUILD) // not for FS2_DEMO
1110 game_feature_not_in_demo_popup();
1112 if (Player->flags & PLAYER_FLAGS_IS_MULTI){
1113 // NOTE : this isn't a great thing to be calling this anymore. But we'll leave it for now
1114 gameseq_post_event( GS_EVENT_MULTI_JOIN_GAME );
1116 main_hall_set_notify_string(XSTR( "Not a valid multiplayer pilot!!", 367));
1121 // load mission key was pressed
1122 case LOAD_MISSION_REGION:
1125 #if !(defined(MULTIPLAYER_BETA_BUILD) || defined(FS2_DEMO))
1126 //#if !defined(NDEBUG) || defined(INTERPLAYQA)
1127 if (Player->flags & PLAYER_FLAGS_IS_MULTI){
1128 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1129 main_hall_set_notify_string(XSTR( "Load Mission not valid for multiplayer pilots", 368));
1131 #ifdef GAME_CD_CHECK
1132 // if ( !game_do_cd_check() ) {
1136 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1137 gameseq_post_event( GS_EVENT_LOAD_MISSION_MENU );
1144 // quick start a game region
1145 case QUICK_START_REGION:
1146 #if !defined(NDEBUG) && !defined(FS2_DEMO)
1147 if (Player->flags & PLAYER_FLAGS_IS_MULTI){
1148 main_hall_set_notify_string(XSTR( "Quick Start not valid for multiplayer pilots", 369));
1151 if (Num_recent_missions > 0) {
1152 strncpy( Game_current_mission_filename, Recent_missions[0], MAX_FILENAME_LEN );
1154 mission_load_up_campaign();
1155 strncpy( Game_current_mission_filename, Campaign.missions[0].name, MAX_FILENAME_LEN );
1158 Campaign.current_mission = -1;
1159 gameseq_post_event(GS_EVENT_START_GAME_QUICK);
1164 // clicked on the barracks region
1165 case BARRACKS_REGION:
1166 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1167 gameseq_post_event( GS_EVENT_BARRACKS_MENU );
1170 // increate the skill level
1171 case SKILL_LEVEL_REGION:
1174 game_increase_skill_level();
1175 sprintf(temp, XSTR( "Skill level set to %s.", 370), Skill_level_names(Game_skill_level));
1176 main_hall_set_notify_string(temp);
1179 // escape was pressed
1181 // if there is a help overlay active, then don't quit the game - just kill the overlay
1182 if(!help_overlay_active(Main_hall_overlay_id)){
1183 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1184 main_hall_exit_game();
1188 help_overlay_set_state(Main_hall_overlay_id,0);
1193 // if the escape key wasn't pressed handle any mouse position related events
1194 if (code != ESC_PRESSED){
1195 main_hall_handle_mouse_location(code);
1200 main_hall_handle_mouse_location(-1);
1204 if ( mouse_down(MOUSE_LEFT_BUTTON) ) {
1205 help_overlay_set_state(Main_hall_overlay_id, 0);
1208 // draw the background bitmap
1210 GR_MAYBE_CLEAR_RES(Main_hall_bitmap);
1211 if(Main_hall_bitmap >= 0){
1212 gr_set_bitmap(Main_hall_bitmap);
1216 // draw any pending notification messages
1217 main_hall_notify_do();
1219 // render misc animations
1220 main_hall_render_misc_anims(frametime);
1222 // render door animtions
1223 main_hall_render_door_anims(frametime);
1225 // blit any appropriate tooltips
1226 main_hall_maybe_blit_tooltips();
1231 // process any help "hit f1" timestamps and display any messages if necessary
1232 if (!F1_text_done) {
1233 main_hall_process_help_stuff();
1236 // blit help overlay if active
1237 help_overlay_maybe_blit(Main_hall_overlay_id);
1239 // blit the freespace version #
1240 main_hall_blit_version();
1242 // blit ship and weapon table status
1243 main_hall_blit_table_status();
1245 // if we're in nice D3D texture format
1247 gr_set_color_fast(&Color_white);
1250 if(gr_screen.mode == GR_DIRECT3D){
1251 if(Bm_pixel_format == BM_PIXEL_FORMAT_ARGB_D3D){
1252 gr_string(320, gr_screen.max_h - 10, "D3D ARGB");
1254 extern int D3d_rendition_uvs;
1255 extern int D3D_32bit;
1256 extern int D3D_fog_mode;
1257 extern int D3D_zbias;
1258 if(D3d_rendition_uvs){
1259 gr_string(320, gr_screen.max_h - 20, "D3D rendition");
1262 gr_string(320, gr_screen.max_h - 30, "D3D 32bit");
1264 gr_printf(320, gr_screen.max_h - 40, "Fog : %d", D3D_fog_mode);
1265 gr_printf(320, gr_screen.max_h - 50, "Zbias : %d", D3D_zbias);
1266 // extern void d3d_test();
1268 } else if(gr_screen.mode == GR_GLIDE){
1270 extern int Glide_voodoo3;
1272 gr_string(320, gr_screen.max_h - 20, "VOODOO 3");
1280 // maybe run the player tips popup
1281 // #if defined(FS2_DEMO) && defined(NDEBUG)
1282 player_tips_popup();
1285 // if we were supposed to skip a frame, then stop doing it after 1 frame
1286 if(Main_hall_frame_skip){
1287 Main_hall_frame_skip = 0;
1291 // close the main hall proper
1292 void main_hall_close()
1296 if(!Main_hall_inited){
1300 // unload the main hall bitmap
1301 if(Main_hall_bitmap != -1){
1302 bm_unload(Main_hall_bitmap);
1305 // unload any bitmaps
1306 if(Main_hall_mask >= 0){
1307 // make sure we unlock the mask bitmap so it can be unloaded
1308 bm_unlock(Main_hall_mask);
1309 if(!bm_unload(Main_hall_mask)){
1310 nprintf(("General","WARNING! Couldn't unload main hall mask bitmap!\n"));
1314 // free up any (possibly) playing misc animation handles
1315 for(idx=0;idx<Main_hall->num_misc_animations;idx++){
1316 if(Main_hall_misc_anim_instance[idx]!=NULL){
1317 anim_stop_playing(Main_hall_misc_anim_instance[idx]);
1318 Main_hall_misc_anim_instance[idx] = NULL;
1322 // free up any (possibly) playing door animation handles
1323 for(idx=0;idx<Main_hall->num_door_animations;idx++){
1324 if(Main_hall_door_anim_instance[idx]!=NULL){
1325 anim_stop_playing(Main_hall_door_anim_instance[idx]);
1326 Main_hall_door_anim_instance[idx] = NULL;
1331 // free up any misc animations/instances
1332 for(idx=0;idx<Main_hall->num_misc_animations;idx++){
1333 if((Main_hall_misc_anim_instance[idx]!=NULL) && (anim_playing(Main_hall_misc_anim_instance[idx]))){
1334 Main_hall_misc_anim_instance[idx] = NULL;
1336 if(Main_hall_misc_anim[idx]!=NULL){
1337 if(anim_free(Main_hall_misc_anim[idx]) == -1){
1338 nprintf(("General","WARNING!, Could not free up misc anim %s in main hall\n",Main_hall->misc_anim_name[idx]));
1343 // free up any door animations/instances
1344 for(idx=0;idx<Main_hall->num_door_animations;idx++){
1345 if((Main_hall_door_anim_instance[idx]!=NULL) && (anim_playing(Main_hall_door_anim_instance[idx]))){
1346 Main_hall_door_anim_instance[idx] = NULL;
1348 if(Main_hall_door_anim[idx]!=NULL){
1349 if(anim_free(Main_hall_door_anim[idx]) == -1){
1350 nprintf(("General","WARNING!, Could not free up door anim %s in main hall\n",Main_hall->door_anim_name[idx]));
1355 // stop any playing door sounds
1356 for(idx=0;idx<Main_hall->num_door_sounds-2;idx++){ // don't cut off the glow sounds (requested by Dan)
1357 if((Main_hall_door_sound_handles[idx] != -1) && snd_is_playing(Main_hall_door_sound_handles[idx])){
1358 snd_stop(Main_hall_door_sound_handles[idx]);
1359 Main_hall_door_sound_handles[idx] = -1;
1363 // stop any playing misc animation sounds
1364 for(idx=0;idx<Main_hall->num_misc_animations;idx++){
1365 for(s_idx=1;s_idx<10;s_idx++){
1366 if(snd_is_playing(Main_hall->misc_anim_sound_handles[idx][s_idx])){
1367 snd_stop(Main_hall->misc_anim_sound_handles[idx][s_idx]);
1368 Main_hall->misc_anim_sound_handles[idx][s_idx] = -1;
1373 // unload the overlay bitmap
1374 help_overlay_unload(Main_hall_overlay_id);
1376 // close any snazzy menu details
1377 snazzy_menu_close();
1380 palette_restore_palette();
1385 // not inited anymore
1386 Main_hall_inited = 0;
1389 // start the main hall music playing
1390 void main_hall_start_music()
1392 // start a looping ambient sound
1393 main_hall_start_ambient();
1395 // if we have selected no music, then don't do this
1396 if ( Cmdline_freespace_no_music ) {
1400 int main_hall_spooled_music_index = event_music_get_spooled_music_index(Main_hall->music);
1402 if ((Main_hall_music_handle == -1) && (main_hall_spooled_music_index != -1)) {
1403 char *music_wavfile_name = Spooled_music[main_hall_spooled_music_index].filename;
1404 if (music_wavfile_name != NULL) {
1405 Main_hall_music_handle = audiostream_open( music_wavfile_name, ASF_EVENTMUSIC );
1406 if ( Main_hall_music_handle != -1 )
1407 audiostream_play(Main_hall_music_handle, Master_event_music_volume);
1410 nprintf(("Warning", "No music file exists to play music at the main menu!\n"));
1415 // stop the main hall music
1416 void main_hall_stop_music()
1418 if ( Main_hall_music_handle != -1 ) {
1419 audiostream_close_file(Main_hall_music_handle);
1420 Main_hall_music_handle = -1;
1424 // do any necessary instantiation of misc animations
1425 void main_hall_handle_misc_anims()
1429 if(Main_hall_frame_skip)
1432 for(idx=0;idx<Main_hall->num_misc_animations;idx++){
1433 // if the anim isn't playing
1434 if(Main_hall_misc_anim_instance[idx] == NULL){
1435 // if the timestamp is -1, then reset it to some random value (based on MIN and MAX) and continue
1436 if(Main_hall->misc_anim_delay[idx][0] == -1){
1437 Main_hall->misc_anim_delay[idx][0] = timestamp(Main_hall->misc_anim_delay[idx][1] +
1438 (int)(((float)rand()/(float)RAND_MAX) * (float)(Main_hall->misc_anim_delay[idx][2] - Main_hall->misc_anim_delay[idx][1])));
1440 // if the timestamp is not -1 and has popped, play the anim and make the timestap -1
1441 } else if (timestamp_elapsed(Main_hall->misc_anim_delay[idx][0]) && Main_hall_misc_anim[idx]) {
1442 anim_play_struct aps;
1444 anim_play_init(&aps, Main_hall_misc_anim[idx], Main_hall->misc_anim_coords[idx][0], Main_hall->misc_anim_coords[idx][1]);
1445 aps.screen_id = GS_STATE_MAIN_MENU;
1446 aps.framerate_independent = 1;
1448 Main_hall_misc_anim_instance[idx] = anim_play(&aps);
1450 // kill the timestamp
1451 Main_hall->misc_anim_delay[idx][0] = -1;
1453 // reset the "should be playing" flags
1454 for(s_idx=1;s_idx<10;s_idx++){
1455 Main_hall->misc_anim_sound_flag[idx][s_idx] = 0;
1459 // if the anim is playing
1461 // check to see if any special trigger points have been reached by the animation
1462 // since the frame triggers must be in ascending order, we will count down so that we don't trigger too many sounds
1463 for(s_idx=Main_hall->misc_anim_special_sounds[idx][0]; s_idx > 0; s_idx--){
1464 // if we've passed the trigger point, then play the sound and break out of the loop
1465 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]){
1466 Main_hall->misc_anim_sound_flag[idx][s_idx] = 1;
1468 // if the sound is already playing, then kill it. This is a pretty safe thing to do since we can assume that
1469 // by the time we get to this point again, the sound will have been long finished
1470 if(snd_is_playing(Main_hall->misc_anim_sound_handles[idx][s_idx])){
1471 snd_stop(Main_hall->misc_anim_sound_handles[idx][s_idx]);
1472 Main_hall->misc_anim_sound_handles[idx][s_idx] = -1;
1475 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]);
1480 // if the animation mode is MISC_ANIM_MODE_HOLD, pause it at the last frame
1481 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)){
1482 anim_pause(Main_hall_misc_anim_instance[idx]);
1483 Main_hall_misc_anim_instance[idx]->stop_now = FALSE;
1486 // if the animation mode is MISC_ANIM_MODE_LOOP, check to see if it should be looped
1487 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)){
1488 anim_release_render_instance(Main_hall_misc_anim_instance[idx]);
1490 // start it playing again
1491 anim_play_struct aps;
1493 anim_play_init(&aps, Main_hall_misc_anim[idx], Main_hall->misc_anim_coords[idx][0], Main_hall->misc_anim_coords[idx][1]);
1494 aps.screen_id = GS_STATE_MAIN_MENU;
1495 aps.framerate_independent = 1;
1497 Main_hall_misc_anim_instance[idx] = anim_play(&aps);
1499 // kill the timestamp
1500 Main_hall->misc_anim_delay[idx][0] = -1;
1502 // reset the "should be playing" flags
1503 for(s_idx=1;s_idx<10;s_idx++){
1504 Main_hall->misc_anim_sound_flag[idx][s_idx] = 0;
1508 // cull any misc animations which are marked as done (!is_playing)
1509 if(!anim_playing(Main_hall_misc_anim_instance[idx])){
1510 Main_hall_misc_anim_instance[idx] = NULL;
1516 // render all playing misc animations
1517 void main_hall_render_misc_anims(float frametime)
1521 // HACKETY HACK HACK - always render misc anim 3 first, if it is playing
1522 if(Main_hall_misc_anim_instance[2] != NULL){
1523 anim_render_one(GS_STATE_MAIN_MENU,Main_hall_misc_anim_instance[2],frametime);
1526 // render all other animations
1527 for(idx=0;idx<MAX_MISC_ANIMATIONS;idx++){
1528 // skip anim 3, which was previously rendered, if at all
1534 if(Main_hall_misc_anim_instance[idx] != NULL){
1535 anim_render_one(GS_STATE_MAIN_MENU,Main_hall_misc_anim_instance[idx],frametime);
1540 // render all playing door animations
1541 void main_hall_render_door_anims(float frametime)
1545 // render all door animations
1546 for(idx=0;idx<MAX_DOOR_ANIMATIONS;idx++){
1548 if(Main_hall_door_anim_instance[idx] != NULL){
1549 anim_render_one(GS_STATE_MAIN_MENU,Main_hall_door_anim_instance[idx],frametime);
1554 // handle starting, stopping and reversing "door" animations
1555 void main_hall_handle_region_anims()
1559 if(Main_hall_frame_skip)
1562 // make sure we make any finished door animations NULL
1563 for(idx=0;idx<Main_hall->num_door_animations;idx++){
1564 if((Main_hall_door_anim_instance[idx] != NULL) && !anim_playing(Main_hall_door_anim_instance[idx])){
1565 Main_hall_door_anim_instance[idx] = NULL;
1569 // go through each region animation
1570 for(idx=0;idx<Main_hall->num_door_animations;idx++){
1571 // if the instance is not null and the animation is playing
1572 if((Main_hall_door_anim_instance[idx] != NULL) && anim_playing(Main_hall_door_anim_instance[idx])){
1573 // check to see if we should hold a given door "open"
1574 if((Main_hall_mouse_region == idx) && (Main_hall_door_anim_instance[idx]->frame_num == Main_hall_door_anim_instance[idx]->stop_at)){
1575 anim_pause(Main_hall_door_anim_instance[idx]);
1576 Main_hall_door_anim_instance[idx]->stop_now = FALSE;
1578 // check to see if we should close a door being held open
1579 if((Main_hall_mouse_region != idx) && (Main_hall_door_anim_instance[idx]->paused)){
1580 anim_unpause(Main_hall_door_anim_instance[idx]);
1586 // do any necessary processing based upon the mouse location
1587 void main_hall_handle_mouse_location(int cur_region)
1589 if(Main_hall_frame_skip)
1592 if(cur_region > NUM_MAIN_HALL_MOUSE_REGIONS) {
1593 // MWA -- inserted return since Int3() was tripped when hitting L from main
1598 // if the mouse is now over a resgion
1599 if (cur_region != -1) {
1600 // if we're still over the same region we were last frame, check stuff
1601 if (cur_region == Main_hall_mouse_region) {
1602 // if we have a linger timestamp set and it has expired, then get moving
1603 if ((Main_hall_region_linger_stamp != -1) && timestamp_elapsed(Main_hall_region_linger_stamp)) {
1604 main_hall_mouse_grab_region(cur_region);
1606 // release the region linger stamp
1607 Main_hall_region_linger_stamp = -1;
1610 // if we're currently on another region, release it
1611 if ((Main_hall_mouse_region != -1) && (cur_region != Main_hall_mouse_region)) {
1612 main_hall_mouse_release_region(Main_hall_mouse_region);
1615 // set the linger time
1616 if (Main_hall_region_linger_stamp == -1) {
1617 Main_hall_mouse_region = cur_region;
1618 Main_hall_region_linger_stamp = timestamp(MAIN_HALL_REGION_LINGER);
1622 // if it was over a region but isn't anymore, release that region
1624 if (Main_hall_mouse_region != -1) {
1625 main_hall_mouse_release_region(Main_hall_mouse_region);
1626 Main_hall_mouse_region = -1;
1628 // release the region linger timestamp
1629 Main_hall_region_linger_stamp = -1;
1634 // if the mouse has moved off of the currently active region, handle the anim accordingly
1635 void main_hall_mouse_release_region(int region)
1637 if(Main_hall_frame_skip){
1641 // if the animation is currently playing in the forward direction, change direction and be done, otherwise don't do a thing
1642 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)){
1643 anim_reverse_direction(Main_hall_door_anim_instance[region]);
1646 // check for door sounds, ignoring the OPTIONS_REGION (which isn't a door)
1647 if ((Main_hall_door_anim_instance[region] != NULL)) {
1648 // don't stop the toaster oven or microwave regions from playing all the way through
1649 if (Main_hall_door_sound_handles[region] != -1) {
1650 snd_stop(Main_hall_door_sound_handles[region]);
1652 Main_hall_door_sound_handles[region] = snd_play(&Snds_iface[Main_hall->door_sounds[region][1]], Main_hall->door_sound_pan[region]);
1654 // make sure to set the sound to play from the right spot
1655 snd_set_pos(Main_hall_door_sound_handles[region], &Snds_iface[SND_MAIN_HALL_DOOR_CLOSE],
1656 (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);
1660 // if the mouse has moved on this region, handle it accordingly
1661 void main_hall_mouse_grab_region(int region)
1663 if (Main_hall_frame_skip) {
1667 // if the animation is not playing, start it playing
1668 if ( !Main_hall_door_anim_instance[region] ) {
1669 if ( Main_hall_door_anim[region] ) {
1670 anim_play_struct aps;
1672 anim_play_init(&aps, Main_hall_door_anim[region], Main_hall->door_anim_coords[region][0], Main_hall->door_anim_coords[region][1]);
1673 aps.screen_id = GS_STATE_MAIN_MENU;
1674 aps.framerate_independent = 1;
1676 Main_hall_door_anim_instance[region] = anim_play(&aps);
1679 // otherwise if its playing in the reverse direction, change it to the forward direction
1680 else if (Main_hall_door_anim_instance[region]->direction == ANIM_DIRECT_REVERSE) {
1681 anim_reverse_direction(Main_hall_door_anim_instance[region]);
1684 // check for opening/starting sounds
1685 // kill the currently playing sounds if necessary
1686 if(Main_hall_door_sound_handles[region] != -1){
1687 snd_stop(Main_hall_door_sound_handles[region]);
1689 Main_hall_door_sound_handles[region] = snd_play(&Snds_iface[Main_hall->door_sounds[region][0]],Main_hall->door_sound_pan[region]);
1691 // start the sound playing at the right spot relative to the completion of the animation
1692 if(Main_hall_door_anim_instance[region]->frame_num != -1){
1693 snd_set_pos(Main_hall_door_sound_handles[region],&Snds_iface[SND_MAIN_HALL_DOOR_OPEN],
1694 (float)Main_hall_door_anim_instance[region]->frame_num / (float)Main_hall_door_anim_instance[region]->parent->total_frames,1);
1698 // handle any right clicks which may have occured
1699 void main_hall_handle_right_clicks()
1703 if(Main_hall_frame_skip)
1706 // check to see if the button has been clicked
1707 if(!Main_hall_right_click){
1708 if(mouse_down(MOUSE_RIGHT_BUTTON)){
1709 // cycle through the available regions
1710 if(Main_hall_last_clicked_region == NUM_MAIN_HALL_MOUSE_REGIONS - 1){
1713 new_region = Main_hall_last_clicked_region + 1;
1715 // set the position of the mouse cursor and the newly clicked region
1716 mouse_set_pos(Main_hall->door_anim_coords[new_region][2],Main_hall->door_anim_coords[new_region][3]);
1718 main_hall_handle_mouse_location(new_region);
1719 Main_hall_last_clicked_region = new_region;
1721 // set the mouse as being clicked
1722 Main_hall_right_click = 1;
1725 // set the mouse as being unclicked
1726 else if(Main_hall_right_click && !(mouse_down(MOUSE_RIGHT_BUTTON))){
1727 Main_hall_right_click = 0;
1731 // cull any door sounds that have finished playing
1732 void main_hall_cull_door_sounds()
1735 // 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
1736 for(idx=0;idx<Main_hall->num_door_sounds;idx++){
1737 if((Main_hall_door_sound_handles[idx] != -1) && !snd_is_playing(Main_hall_door_sound_handles[idx])){
1738 Main_hall_door_sound_handles[idx] = -1;
1743 void main_hall_handle_random_intercom_sounds()
1745 // if we have no timestamp for the next random sound, then set on
1746 if((Main_hall_next_intercom_sound_stamp == -1) && (Main_hall_intercom_sound_handle == -1)){
1747 Main_hall_next_intercom_sound_stamp = timestamp((int)(((float)rand()/(float)RAND_MAX) *
1748 (float)(Main_hall->intercom_delay[Main_hall_next_intercom_sound][1]
1749 - Main_hall->intercom_delay[Main_hall_intercom_sound_handle][0])) );
1752 // if the there is no sound playing
1753 if(Main_hall_intercom_sound_handle == -1){
1754 // if the timestamp has popped, play a sound
1755 if((Main_hall_next_intercom_sound_stamp != -1) && (timestamp_elapsed(Main_hall_next_intercom_sound_stamp))){
1757 Main_hall_intercom_sound_handle = snd_play(&Snds_iface[Main_hall->intercom_sounds[Main_hall_next_intercom_sound]]);
1759 // unset the timestamp
1760 Main_hall_next_intercom_sound_stamp = -1;
1763 // if the sound is playing
1765 // if the sound has finished, set the timestamp and continue
1766 if(!snd_is_playing(Main_hall_intercom_sound_handle)){
1767 // increment the next sound
1768 if(Main_hall_next_intercom_sound >= (Main_hall->num_random_intercom_sounds-1)){
1769 Main_hall_next_intercom_sound = 0;
1771 Main_hall_next_intercom_sound++;
1774 // set the timestamp
1775 Main_hall_next_intercom_sound_stamp = timestamp((int)(((float)rand()/(float)RAND_MAX) *
1776 (float)(Main_hall->intercom_delay[Main_hall_next_intercom_sound][1]
1777 - Main_hall->intercom_delay[Main_hall_next_intercom_sound][0])) );
1779 // release the sound handle
1780 Main_hall_intercom_sound_handle = -1;
1785 // set the notification string with its decay timeout
1786 void main_hall_set_notify_string(char *str)
1788 strcpy(Main_hall_notify_text,str);
1789 Main_hall_notify_stamp = timestamp(MAIN_HALL_NOTIFY_TIME);
1792 void main_hall_notify_do()
1794 // check to see if we should try and do something
1795 if(Main_hall_notify_stamp != -1){
1796 // if the text time has expired
1797 if(timestamp_elapsed(Main_hall_notify_stamp)){
1798 strcpy(Main_hall_notify_text,"");
1799 Main_hall_notify_stamp = -1;
1802 gr_set_color_fast(&Color_bright);
1804 gr_get_string_size(&w,&h,Main_hall_notify_text);
1805 gr_printf((gr_screen.max_w - w)/2, gr_screen.max_h - 40, Main_hall_notify_text);
1810 // start a looping ambient sound for main hall
1811 void main_hall_start_ambient()
1813 int play_ambient_loop = 0;
1815 if ( Main_hall_ambient_loop == -1 ) {
1816 play_ambient_loop = 1;
1818 if ( !snd_is_playing(Main_hall_ambient_loop) ) {
1819 play_ambient_loop = 1;
1823 if ( play_ambient_loop ) {
1824 Main_hall_ambient_loop = snd_play_looping(&Snds_iface[SND_MAIN_HALL_AMBIENT]);
1828 // stop a looping ambient sound for the main hall
1829 void main_hall_stop_ambient()
1831 if ( Main_hall_ambient_loop != -1 ) {
1832 snd_stop(Main_hall_ambient_loop);
1833 Main_hall_ambient_loop = -1;
1837 // Reset the volume of the looping ambient sound. This is called from the options
1838 // screen when the looping ambient sound might be playing.
1839 void main_hall_reset_ambient_vol()
1841 if ( Main_hall_ambient_loop >= 0 ) {
1842 snd_set_volume(Main_hall_ambient_loop, Snds_iface[SND_MAIN_HALL_AMBIENT].default_volume);
1846 // blit the freespace version #
1847 void main_hall_blit_version()
1849 char version_string[100];
1852 // format the version string
1853 get_version_string(version_string);
1855 // get the length of the string
1856 gr_get_string_size(&w,NULL,version_string);
1858 // print the string out in the lower right corner
1859 gr_set_color_fast(&Color_white);
1860 gr_string(gr_screen.max_w - 55, gr_screen.max_h - 12, version_string);
1863 // blit any necessary tooltips
1864 void main_hall_maybe_blit_tooltips()
1869 // if we're over no region - don't blit anything
1870 if(Main_hall_mouse_region < 0) {
1874 // get the index of the proper text to be using
1875 if(Main_hall_mouse_region == READY_ROOM_REGION) {
1876 // if this is a multiplayer pilot, the ready room region becomes the multiplayer region
1877 if(Player->flags & PLAYER_FLAGS_IS_MULTI){
1878 text_index = NUM_REGIONS - 1;
1880 text_index = READY_ROOM_REGION;
1883 text_index = Main_hall_mouse_region;
1886 // set the color and blit the string
1887 if(!help_overlay_active(Main_hall_overlay_id)) {
1888 int shader_y = (Main_hall->region_yval) - Main_hall_tooltip_padding[gr_screen.res]; // subtract more to pull higher
1889 // get the width of the string
1890 gr_get_string_size(&w, NULL, Main_hall->region_descript[text_index]);
1892 gr_set_shader(&Main_hall_tooltip_shader);
1893 gr_shade(0, shader_y, gr_screen.clip_width, (gr_screen.clip_height - shader_y));
1895 gr_set_color_fast(&Color_bright_white);
1896 gr_string((gr_screen.max_w - w)/2, Main_hall->region_yval, Main_hall->region_descript[text_index]);
1901 void main_hall_process_help_stuff()
1906 // if the timestamp has popped, don't do anything
1907 if(Main_hall_help_stamp == -1) {
1911 // if the timestamp has popped, advance frame
1912 if(timestamp_elapsed(Main_hall_help_stamp)) {
1913 Main_hall_f1_text_frame++;
1916 // otherwise print out the message
1917 strcpy(str, XSTR( "Press F1 for help", 371));
1918 gr_get_string_size(&w, &h, str);
1920 int y_anim_offset = Main_hall_f1_text_frame;
1922 // if anim is off the screen finally, stop altogether
1923 if ( (y_anim_offset >= (2*Main_hall_tooltip_padding[gr_screen.res]) + h) || (help_overlay_active(Main_hall_overlay_id)) ) {
1924 Main_hall_f1_text_frame = -1;
1925 Main_hall_help_stamp = -1;
1930 // set the color and print out text and shader
1931 gr_set_color_fast(&Color_bright_white);
1932 gr_shade(0, 0, gr_screen.max_w, (2*Main_hall_tooltip_padding[gr_screen.res]) + h - y_anim_offset);
1933 gr_string((gr_screen.max_w - w)/2, Main_hall_tooltip_padding[gr_screen.res] - y_anim_offset, str);
1936 // what main hall we're on (should be 0 or 1)
1939 // only 1 of 2 main halls
1940 if(Main_hall == &Main_hall_defines[gr_screen.res][0]){
1947 // read in main hall table
1948 void main_hall_read_table()
1950 main_hall_defines *m, temp;
1951 int count, idx, s_idx, m_idx;
1954 read_file_text("mainhall.tbl");
1959 while(!optional_string("#end")){
1961 // read in 2 resolutions
1962 for(m_idx=0; m_idx<GR_NUM_RESOLUTIONS; m_idx++){
1963 // maybe use a temp main hall stuct
1964 if(count >= NUM_MAIN_HALLS){
1967 m = &Main_hall_defines[m_idx][count];
1971 required_string("$Main Hall");
1974 required_string("+Bitmap:");
1975 stuff_string(m->bitmap, F_NAME, NULL, MAX_FILENAME_LEN);
1976 required_string("+Mask:");
1977 stuff_string(m->mask, F_NAME, NULL, MAX_FILENAME_LEN);
1978 required_string("+Music:");
1979 stuff_string(m->music, F_NAME, NULL, MAX_FILENAME_LEN);
1982 required_string("+Num Intercom Sounds:");
1983 stuff_int(&m->num_random_intercom_sounds);
1984 for(idx=0; idx<m->num_random_intercom_sounds; idx++){
1986 required_string("+Intercom delay:");
1987 stuff_int(&m->intercom_delay[idx][0]);
1988 stuff_int(&m->intercom_delay[idx][1]);
1990 for(idx=0; idx<m->num_random_intercom_sounds; idx++){
1991 // intercom sound id
1992 required_string("+Intercom sound:");
1993 stuff_int(&m->intercom_sounds[idx]);
1995 for(idx=0; idx<m->num_random_intercom_sounds; idx++){
1997 required_string("+Intercom pan:");
1998 stuff_float(&m->intercom_sound_pan[idx]);
2002 required_string("+Num Misc Animations:");
2003 stuff_int(&m->num_misc_animations);
2004 for(idx=0; idx<m->num_misc_animations; idx++){
2006 required_string("+Misc anim:");
2007 stuff_string(m->misc_anim_name[idx], F_NAME, NULL);
2009 for(idx=0; idx<m->num_misc_animations; idx++){
2011 required_string("+Misc anim delay:");
2012 stuff_int(&m->misc_anim_delay[idx][0]);
2013 stuff_int(&m->misc_anim_delay[idx][1]);
2014 stuff_int(&m->misc_anim_delay[idx][2]);
2016 for(idx=0; idx<m->num_misc_animations; idx++){
2018 required_string("+Misc anim coords:");
2019 stuff_int(&m->misc_anim_coords[idx][0]);
2020 stuff_int(&m->misc_anim_coords[idx][1]);
2022 for(idx=0; idx<m->num_misc_animations; idx++){
2024 required_string("+Misc anim mode:");
2025 stuff_int(&m->misc_anim_modes[idx]);
2027 for(idx=0; idx<m->num_misc_animations; idx++){
2029 required_string("+Misc anim pan:");
2030 stuff_float(&m->misc_anim_sound_pan[idx]);
2032 for(idx=0; idx<m->num_misc_animations; idx++){
2034 required_string("+Misc anim sounds:");
2035 stuff_int(&m->misc_anim_special_sounds[idx][0]);
2036 for(s_idx=0; s_idx<m->misc_anim_special_sounds[idx][0]; s_idx++){
2037 stuff_int(&m->misc_anim_special_sounds[idx][s_idx + 1]);
2040 for(idx=0; idx<m->num_misc_animations; idx++){
2041 // anim sound triggers
2042 required_string("+Misc anim trigger:");
2043 stuff_int(&m->misc_anim_special_trigger[idx][0]);
2044 for(s_idx=0; s_idx<m->misc_anim_special_trigger[idx][0]; s_idx++){
2045 stuff_int(&m->misc_anim_special_trigger[idx][s_idx + 1]);
2048 for(idx=0; idx<m->num_misc_animations; idx++){
2049 // anim sound handles
2050 required_string("+Misc anim handles:");
2051 stuff_int(&m->misc_anim_sound_handles[idx][0]);
2053 for(idx=0; idx<m->num_misc_animations; idx++){
2055 required_string("+Misc anim flags:");
2056 stuff_int(&m->misc_anim_sound_flag[idx][0]);
2060 required_string("+Num Door Animations:");
2061 stuff_int(&m->num_door_animations);
2062 for(idx=0; idx<m->num_door_animations; idx++){
2064 required_string("+Door anim:");
2065 stuff_string(m->door_anim_name[idx], F_NAME, NULL);
2067 for(idx=0; idx<m->num_door_animations; idx++){
2069 required_string("+Door coords:");
2070 stuff_int(&m->door_anim_coords[idx][0]);
2071 stuff_int(&m->door_anim_coords[idx][1]);
2072 stuff_int(&m->door_anim_coords[idx][2]);
2073 stuff_int(&m->door_anim_coords[idx][3]);
2075 for(idx=0; idx<m->num_door_animations; idx++){
2076 // door open and close sounds
2077 required_string("+Door sounds:");
2078 stuff_int(&m->door_sounds[idx][0]);
2079 stuff_int(&m->door_sounds[idx][1]);
2081 for(idx=0; idx<m->num_door_animations; idx++){
2083 required_string("+Door pan:");
2084 stuff_float(&m->door_sound_pan[idx]);
2087 // tooltip y location
2088 required_string("+Tooltip Y:");
2089 stuff_int(&m->region_yval);
2090 for(idx=0; idx<NUM_REGIONS; idx++){
2091 m->region_descript[idx] = NULL;
2095 if(count < NUM_MAIN_HALLS){
2102 Main_hall_defines[GR_640][1].door_sounds[OPTIONS_REGION][0] = SND_VASUDAN_BUP;
2103 Main_hall_defines[GR_640][1].door_sounds[OPTIONS_REGION][1] = SND_VASUDAN_BUP;
2104 Main_hall_defines[GR_1024][1].door_sounds[OPTIONS_REGION][0] = SND_VASUDAN_BUP;
2105 Main_hall_defines[GR_1024][1].door_sounds[OPTIONS_REGION][1] = SND_VASUDAN_BUP;
2107 // set head anim. hehe
2108 strcpy(Main_hall_defines[GR_640][1].door_anim_name[OPTIONS_REGION], "vhallheads");
2109 strcpy(Main_hall_defines[GR_1024][1].door_anim_name[OPTIONS_REGION], "2_vhallheads");
2111 // set the background
2112 strcpy(Main_hall_defines[GR_640][1].bitmap, "vhallhead");
2113 strcpy(Main_hall_defines[GR_1024][1].bitmap, "2_vhallhead");
2117 // make the vasudan main hall funny
2118 void main_hall_vasudan_funny()
2137 vector sun_pos = vmd_zero_vector;
2141 argh = bm_load("sun01");
2142 bm_lock(argh, 16, BMP_TEX_XPARENT);
2147 g3_set_view_matrix(&vmd_zero_vector, &view, 0.5f);
2148 g3_rotate_vertex(&p1, &sun_pos);
2149 g3_project_vertex(&p1);
2150 gr_zbuffer_set(GR_ZBUFF_NONE);
2151 gr_set_bitmap( argh );
2152 g3_draw_bitmap(&p1, 0, 0.05f, TMAP_FLAG_TEXTURED | TMAP_FLAG_XPARENT);