2 * $Logfile: /Freespace2/code/Network/stand_gui.cpp $
8 * Revision 1.1 2002/05/03 03:28:10 root
12 * 16 8/16/99 4:06p Dave
13 * Big honking checkin.
15 * 15 8/11/99 5:54p Dave
16 * Fixed collision problem. Fixed standalone ghost problem.
18 * 14 8/04/99 5:45p Dave
19 * Upped default standalone server framerate to 60.
21 * 13 5/22/99 5:35p Dave
22 * Debrief and chatbox screens. Fixed small hi-res HUD bug.
24 * 12 5/19/99 4:07p Dave
25 * Moved versioning code into a nice isolated common place. Fixed up
26 * updating code on the pxo screen. Fixed several stub problems.
28 * 11 4/25/99 7:43p Dave
29 * Misc small bug fixes. Made sun draw properly.
31 * 10 2/24/99 2:25p Dave
32 * Fixed up chatbox bugs. Made squad war reporting better. Fixed a respawn
33 * bug for dogfight more.
35 * 9 2/18/99 11:46a Neilk
36 * hires interface coord support
38 * 8 2/12/99 6:16p Dave
39 * Pre-mission Squad War code is 95% done.
41 * 7 11/19/98 4:19p Dave
42 * Put IPX sockets back in psnet. Consolidated all multiplayer config
45 * 6 11/17/98 11:12a Dave
46 * Removed player identification by address. Now assign explicit id #'s.
48 * 5 11/05/98 5:55p Dave
49 * Big pass at reducing #includes
51 * 4 10/09/98 2:57p Dave
52 * Starting splitting up OS stuff.
54 * 3 10/08/98 4:29p Dave
55 * Removed reference to osdefs.h
57 * 2 10/07/98 10:53a Dave
60 * 1 10/07/98 10:50a Dave
62 * 63 9/17/98 11:56a Allender
63 * allow use of return key in edit box
65 * 62 9/04/98 3:52p Dave
66 * Put in validated mission updating and application during stats
69 * 61 7/24/98 9:27a Dave
70 * Tidied up endgame sequencing by removing several old flags and
71 * standardizing _all_ endgame stuff with a single function call.
73 * 60 7/10/98 5:04p Dave
74 * Fix connection speed bug on standalone server.
76 * 59 6/18/98 4:46p Allender
77 * removed test code that I previously forgot to remove
79 * 58 6/18/98 3:52p Allender
80 * make close button actually close down property sheet
82 * 57 6/13/98 6:02p Hoffoss
83 * Externalized all new (or forgot to be added) strings to all the code.
85 * 56 6/13/98 3:19p Hoffoss
86 * NOX()ed out a bunch of strings that shouldn't be translated.
88 * 55 6/10/98 2:56p Dave
89 * Substantial changes to reduce bandwidth and latency problems.
91 * 54 5/24/98 3:45a Dave
92 * Minor object update fixes. Justify channel information on PXO. Add a
93 * bunch of configuration stuff for the standalone.
95 * 53 5/22/98 9:35p Dave
96 * Put in channel based support for PXO. Put in "shutdown" button for
97 * standalone. UI tweaks for TvT
99 * 52 5/21/98 9:45p Dave
100 * Lengthened tracker polling times. Put in initial support for PXO
101 * servers with channel filters. Fixed several small UI bugs.
103 * 51 5/18/98 9:15p Dave
104 * Put in network config file support.
106 * 50 5/15/98 5:16p Dave
107 * Fix a standalone resetting bug.Tweaked PXO interface. Display captaincy
108 * status for team vs. team. Put in asserts to check for invalid team vs.
111 * 49 5/15/98 3:36p John
112 * Fixed bug with new graphics window code and standalone server. Made
113 * hwndApp not be a global anymore.
115 * 48 5/10/98 7:06p Dave
116 * Fix endgame sequencing ESC key. Changed how host options warning popups
117 * are done. Fixed pause/message scrollback/options screen problems in mp.
118 * Make sure observer HUD doesn't try to lock weapons.
120 * 47 5/09/98 7:16p Dave
121 * Put in CD checking. Put in standalone host password. Made pilot into
124 * 46 5/08/98 7:09p Dave
125 * Lots of UI tweaking.
127 * 45 5/08/98 5:05p Dave
128 * Go to the join game screen when quitting multiplayer. Fixed mission
129 * text chat bugs. Put mission type symbols on the create game list.
130 * Started updating standalone gui controls.
132 * 44 5/04/98 1:44p Dave
133 * Fixed up a standalone resetting problem. Fixed multiplayer stats
134 * collection for clients. Make sure all multiplayer ui screens have the
135 * correct palette at all times.
137 * 43 5/02/98 5:38p Dave
138 * Put in new tracker API code. Put in ship information on mp team select
139 * screen. Make standalone server name permanent. Fixed standalone server
142 * 42 5/02/98 1:45a Dave
143 * Make standalone goal tree not flicker.
145 * 41 5/01/98 10:57a Jim
146 * from Dave: fixed mission goal problems
148 * 40 4/29/98 12:11a Dave
149 * Put in first rev of full API support for new master tracker.
151 * 39 4/28/98 5:11p Dave
152 * Fixed multi_quit_game() client side sequencing problem. Turn off
153 * afterburners when ending multiplayer mission. Begin integration of mt
154 * API from Kevin Bentley.
156 * 38 4/25/98 2:02p Dave
157 * Put in multiplayer context help screens. Reworked ingame join ship
158 * select screen. Fixed places where network timestamps get hosed.
160 * 37 4/06/98 6:37p Dave
161 * Put in max_observers netgame server option. Make sure host is always
162 * defaulted to alpha 1 or zeta 1. Changed create game so that MAX_PLAYERS
163 * can always join but need to be kicked before commit can happen. Put in
164 * support for server ending a game and notifying clients of a special
167 * 36 3/31/98 5:18p John
168 * Removed demo/save/restore. Made NDEBUG defined compile. Removed a
169 * bunch of debug stuff out of player file. Made model code be able to
170 * unload models and malloc out only however many models are needed.
173 * 35 3/24/98 5:00p Dave
174 * Fixed several ui bugs. Put in pre and post voice stream playback sound
175 * fx. Put in error specific popups for clients getting dropped from games
176 * through actions other than their own.
178 * 34 3/19/98 5:05p Dave
179 * Put in support for targeted multiplayer text and voice messaging (all,
180 * friendly, hostile, individual).
182 * 33 3/17/98 5:29p Dave
183 * Minor bug fixes in player select menu. Solidified mp joining process.
184 * Made furball mode support ingame joiners and dropped players correctly.
186 * 32 3/15/98 4:17p Dave
187 * Fixed oberver hud problems. Put in handy netplayer macros. Reduced size
188 * of network orientation matrices.
190 * 31 3/03/98 5:12p Dave
191 * 50% done with team vs. team interface issues. Added statskeeping to
192 * secondary weapon blasts. Numerous multiplayer ui bug fixes.
194 * 30 2/12/98 4:41p Dave
195 * Seperated multiplayer kick functionality into its own module. Ui
198 * 29 2/05/98 10:24a Hoffoss
199 * Changed "goal" text to "objective", which is the correct term nowadays.
201 * 28 1/31/98 4:32p Dave
202 * Put in new support for VMT player validation, game logging in, and game
203 * logging out. Need to finish stats transfer.
205 * 27 1/28/98 6:24p Dave
206 * Made standalone use ~8 megs less memory. Fixed multiplayer submenu
207 * sequencing problem.
209 * 26 1/24/98 3:39p Dave
210 * Fixed numerous multiplayer bugs (last frame quit problem, weapon bank
211 * changing, deny packets). Add several controls to standalone server.
213 * 25 1/20/98 2:23p Dave
214 * Removed optimized build warnings. 99% done with ingame join fixes.
216 * 24 1/17/98 2:46a Dave
217 * Reworked multiplayer join/accept process. Ingame join still needs to be
220 * 23 1/16/98 2:34p Dave
221 * Made pause screen work properly (multiplayer). Changed how chat packets
224 * 22 1/13/98 5:37p Dave
225 * Reworked a lot of standalone interface code. Put in single and
226 * multiplayer popups for death sequence. Solidified multiplayer kick
229 * 21 1/11/98 10:03p Allender
230 * removed <winsock.h> from headers which included it. Made psnet_socket
231 * type which is defined just as SOCKET type is.
233 * 20 1/05/98 5:07p Dave
234 * Fixed a chat packet bug. Fixed a few state save/restore bugs. Updated a
235 * few things for multiplayer server transfer.
237 * 19 12/10/97 4:46p Dave
238 * Added in more detailed support for multiplayer packet lag/loss. Fixed
239 * some multiplayer stuff. Added some controls to the standalone.
241 * 18 12/03/97 11:50p Dave
242 * Fixed a bunch of multiplayer bugs (standalone and non)
244 * 17 12/03/97 11:59a Dave
245 * Dependant merge checkin
247 * 16 12/02/97 10:05p Dave
248 * Began some large-scale multiplayer debugging work (mostly standalone)
250 * 15 11/15/97 2:37p Dave
251 * More multiplayer campaign support.
253 * 14 10/29/97 5:18p Dave
254 * More debugging of server transfer. Put in debrief/brief
255 * transition for multiplayer (w/standalone)
257 * 13 10/25/97 7:23p Dave
258 * Moved back to single set stats storing. Put in better respawning
261 * 12 10/24/97 6:19p Dave
262 * More standalone testing/fixing. Added reliable endgame sequencing.
263 * Added reliable ingame joining. Added reliable stats transfer (endgame).
264 * Added support for dropping players in debriefing. Removed a lot of old
267 * 11 10/21/97 5:21p Dave
268 * Fixed pregame mission load/file verify debacle. Added single vs.
269 * multiplayer stats system.
271 * 10 10/14/97 5:38p Dave
272 * Player respawns 99.9% done. Only need to check cases for server/host
275 * 9 10/03/97 4:57p Dave
276 * Added functions for new text controls. Added some more reset controls.
277 * Put in checks for all-players-gone.
279 * 8 9/17/97 9:09a Dave
280 * Observer mode works, put in standalone controls. Fixed up some stuff for
281 * ingame join broken by recent code checkins.
283 * 7 8/29/97 5:03p Dave
284 * Added a ton of new gui controls/features.
286 * 6 8/26/97 5:03p Dave
287 * Added bunch of informational controls. Standardized some functions for
288 * external use. Put in godview mode (conditionaled out though).
290 * 5 8/23/97 11:31a Dave
291 * Put in new gui calls. Added a bunch of display controls.
293 * 4 8/20/97 4:19p Dave
294 * Moved some functions around. Added the standalone state text box.
296 * 3 8/18/97 11:46a Dave
297 * Moved definition of STANDALONE_FRAME_CAP tp multi.h
299 * 2 8/11/97 4:52p Dave
300 * Spliced out standalone GUI stuff from OsApi and WinMain.cpp to its own
303 * 1 8/11/97 4:21p Dave
309 #include <windowsx.h>
310 #include <commctrl.h>
322 #include "lighting.h"
323 #include "linklist.h"
324 #include "freespace.h"
326 #include "stand_gui.h"
336 #include "freespaceresource.h"
338 #include "multimsgs.h"
339 #include "multiutil.h"
340 #include "missiongoals.h"
341 #include "systemvars.h"
343 #include "multi_kick.h"
344 #include "multi_pmsg.h"
346 #include "multi_endgame.h"
347 #include "gamesequence.h"
348 #include "osregistry.h"
352 HANDLE Standalone_thread;
353 DWORD Standalone_thread_id;
354 static HWND Standalone_hwnd = NULL;
356 // -----------------------------------------------------------------------------------------
357 // standalone global defs
359 #define MAX_STANDALONE_PAGES 5
361 #define STD_STATS_UPDATE_TIME 500 // ms between updating player stats on the visible controls
362 #define STD_NG_UPDATE_TIME 100 // ms between updating netgame information are controls
364 // coords for the "shutdown" button (client window coords)
365 static int Std_shutdown_coords[GR_NUM_RESOLUTIONS][2] = {
366 { 130, 450 }, // GR_640
367 { 130, 450 } // GR_640
370 // you should reference Page_handles and Pages with these defines from now on
371 #define CONNECT_PAGE 0
372 #define MULTIPLAYER_PAGE 1
373 #define PLAYER_INFO_PAGE 2
374 #define GODSTUFF_PAGE 3
377 // standalone gui property sheet stuff
379 static HWND Page_handles[MAX_STANDALONE_PAGES];
380 static PROPSHEETPAGE Pages[MAX_STANDALONE_PAGES];
381 static PROPSHEETHEADER Sheet;
383 // index into Page_handles[] representing the currently selected page
384 static int Active_standalone_page;
386 // timestamp for updating currently selected player stats on the player info page
387 int Standalone_stats_stamp;
389 // timestamp for updating the netgame information are text controls
390 int Standalone_ng_stamp;
392 // banned player callsigns
393 #define STANDALONE_MAX_BAN 50
394 char Standalone_ban_list[STANDALONE_MAX_BAN][CALLSIGN_LEN+1];
395 int Standalone_ban_count = 0;
397 // ----------------------------------------------------------------------------------------
398 // mission validation dialog
401 static HWND Multi_gen_dialog = NULL; // the dialog itself
403 // dialog proc for this dialog
404 BOOL CALLBACK std_gen_dialog_proc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
412 Multi_gen_dialog = NULL;
418 // create the validate dialog
419 void std_create_gen_dialog(char *title)
421 // if the dialog is already active, do nothing
422 if(Multi_gen_dialog != NULL){
426 // otherwise create the dialog
427 Multi_gen_dialog = CreateDialog(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_GEN), Psht, (DLGPROC)std_gen_dialog_proc);
428 if(Multi_gen_dialog != NULL){
429 SetWindowText(Multi_gen_dialog, title);
433 // kill the validate dialog();
434 void std_destroy_gen_dialog()
436 // if the dialog is not active, do nothing
437 if(Multi_gen_dialog == NULL){
442 DestroyWindow(Multi_gen_dialog);
443 Multi_gen_dialog = NULL;
446 // set the text in the filename of the validate dialog
447 // valid values for field_num == 0 .. 2
448 void std_gen_set_text(char *str, int field_num)
452 // if the dialog is not active
453 if((Multi_gen_dialog == NULL) || (str == NULL) || (field_num < 0) || (field_num > 2)){
457 // otherwise set the text
458 ctrl = GetDlgItem(Multi_gen_dialog, (int)MAKEINTRESOURCE(IDC_FIELD1));
461 ctrl = GetDlgItem(Multi_gen_dialog,(int)MAKEINTRESOURCE(IDC_FIELD1));
464 ctrl = GetDlgItem(Multi_gen_dialog,(int)MAKEINTRESOURCE(IDC_FIELD2));
467 ctrl = GetDlgItem(Multi_gen_dialog,(int)MAKEINTRESOURCE(IDC_FIELD3));
470 SetWindowText(ctrl, str);
473 // is the validate dialog active
474 int std_gen_is_active()
476 return Multi_gen_dialog != NULL;
479 // ----------------------------------------------------------------------------------------
480 // connection page/tab functions
482 static HWND Multi_std_name; // standalone name text edit control
483 HWND Multi_std_host_passwd; // host password text control
484 int Multi_std_namechange_force;
486 // convert the index of an item in the list box into an index into the net players array
487 int std_connect_lindex_to_npindex(int index);
489 // set the text box indicating how many players are connected, returning the determined count
490 int std_connect_set_connect_count()
497 // setup the text string
498 strcpy(str,XSTR("# Connections : ",911));
500 // determine how many players are actually connected
502 for(idx=0;idx<MAX_PLAYERS;idx++){
503 if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
508 // tack on the player count to the end of the string
509 sprintf(val,"%d",count);
512 // set the text itself
513 ctrl = GetDlgItem(Page_handles[CONNECT_PAGE],(int)MAKEINTRESOURCE(IDC_CON_COUNT));
514 SetWindowText(ctrl,str);
516 // return the num of players found
520 // set the connect status (connected or not) of the game host
521 void std_connect_set_host_connect_status()
526 // first try and find the host
528 for(idx=0;idx<MAX_PLAYERS;idx++){
529 if(MULTI_CONNECTED(Net_players[idx]) && MULTI_HOST(Net_players[idx])){
535 // get the control and set the status
536 ctrl = GetDlgItem(Page_handles[CONNECT_PAGE],(int)MAKEINTRESOURCE(IDC_HOST_IS));
538 SetWindowText(ctrl, XSTR("Host connected ? Yes",912));
540 SetWindowText(ctrl, XSTR("Host connected ? No",913));
544 // add an ip string to the connect page listbox
545 void std_connect_add_ip_string(char *string)
550 ctrl = GetDlgItem(Page_handles[CONNECT_PAGE], (int)MAKEINTRESOURCE(IDC_CONPING));
551 SendMessage(ctrl, LB_ADDSTRING, (WPARAM)0, (LPARAM)(LPCTSTR)string);
554 // remove an ip string from the connect page listbox
555 void std_connect_remove_ip_string(char *string)
560 // get the control handle
561 ctrl = GetDlgItem(Page_handles[CONNECT_PAGE], (int)MAKEINTRESOURCE(IDC_CONPING));
563 // NOTE the use of FINDSTRING and _not_ FINDSTRINGEXACT !!
564 // since we've appended the ping to the end of the string, we can only check the
565 // "prefix" which is the net_players name
566 loc = SendMessage(ctrl, LB_FINDSTRING, (WPARAM)-1, (LPARAM)(LPCTSTR)string);
569 SendMessage(ctrl, LB_DELETESTRING, (WPARAM)loc, (LPARAM)0);
573 // set an ip string on the connect page listbox
574 void std_connect_set_ip_string(char *lookup,char *string)
579 // get the control handle
580 ctrl = GetDlgItem(Page_handles[CONNECT_PAGE],(int)MAKEINTRESOURCE(IDC_CONPING));
582 // NOTE the use of FINDSTRING and _not_ FINDSTRINGEXACT !!
583 // since we've appended the ping to the end of the string, we can only check the
584 // "prefix" which is the net_players name
585 loc = SendMessage(ctrl,LB_FINDSTRING,(WPARAM)-1,(LPARAM)(LPCTSTR)lookup);
588 SendMessage(ctrl,LB_DELETESTRING,(WPARAM)loc,(LPARAM)0);
589 SendMessage(ctrl,LB_INSERTSTRING,(WPARAM)loc,(LPARAM)string);
593 void std_connect_kick_player()
598 // get the control handle
599 ctrl = GetDlgItem(Page_handles[CONNECT_PAGE],(int)MAKEINTRESOURCE(IDC_CONPING));
601 sel = SendMessage(ctrl,LB_GETCURSEL,(WPARAM)0,(LPARAM)0);
602 // attempt to get the player index
604 player_num = std_connect_lindex_to_npindex(sel);
606 // if we found him, then kick the bastard
607 if(player_num != -1){
608 multi_kick_player(player_num,0);
613 // update the ping for this particular player
614 void std_connect_update_ping(net_player *p)
616 char str[40],ping[10],sml_ping[10],lookup[50];
618 // as long as his ping is not -1, do an update
619 if(p->s_info.ping.ping_avg > -1){
620 // get the lookup string
621 psnet_addr_to_string(lookup,&p->p_info.addr);
623 // build the string to replace the ping with
627 // chop it off at pings greater than 1 second
628 if(p->s_info.ping.ping_avg > 1000){
629 strcat(str,XSTR("> 1 sec",914));
630 strcpy(sml_ping,XSTR("> 1 sec",914));
633 sprintf(ping,"%d",p->s_info.ping.ping_avg);
635 strcat(str,XSTR(" ms",915));
636 strcpy(sml_ping,ping); strcat(sml_ping,XSTR(" ms",915));
640 std_connect_set_ip_string(lookup,str);
644 // clear all the controls for this page
645 void std_connect_clear_controls()
649 // set various connect counts
650 std_connect_set_connect_count();
651 std_connect_set_host_connect_status();
653 // reset the list of players and pings
654 handle = GetDlgItem(Page_handles[CONNECT_PAGE],(int)MAKEINTRESOURCE(IDC_CONPING));
655 SendMessage(handle,LB_RESETCONTENT,(WPARAM)0,(LPARAM)0);
658 // set the game name for the standalone. passing NULL uses the default
659 void std_connect_set_gamename(char *name)
661 char buf[MAX_GAMENAME_LEN+1];
663 // use the default name for now
665 // if a permanent name exists, use that instead of the default
666 if(strlen(Multi_options_g.std_pname)){
667 strcpy(Netgame.name, Multi_options_g.std_pname);
669 strcpy(Netgame.name,XSTR("Standalone Server",916));
672 strcpy(Netgame.name,name);
675 // update the text control
676 strcpy(buf,Netgame.name);
677 Multi_std_namechange_force = 0;
678 SetWindowText(Multi_std_name,buf);
679 Multi_std_namechange_force = 1;
682 // the user has changed the text in the server name text box. handle this
683 void std_connect_handle_name_change()
685 char buf[MAX_GAMENAME_LEN+2];
686 int max_len = MAX_GAMENAME_LEN+2;
688 if(Multi_std_namechange_force){
689 memset(buf,0,MAX_GAMENAME_LEN+2);
690 memcpy(&buf[0],&max_len,sizeof(int));
693 SendMessage(Multi_std_name,EM_GETLINE,(WPARAM)0,(LPARAM)(LPCSTR)buf);
695 // just copy it over for now. we may want to process this more later on
696 strcpy(Netgame.name,buf);
698 // copy it to the permanent name
699 strcpy(Multi_options_g.std_pname, buf);
703 // the user has changed the text in the host password text box
704 void std_connect_handle_passwd_change()
706 char buf[STD_PASSWD_LEN+2];
707 int max_len = STD_PASSWD_LEN+2;
709 memset(buf,0,STD_PASSWD_LEN+2);
710 memcpy(&buf[0],&max_len,sizeof(int));
713 SendMessage(Multi_std_host_passwd,EM_GETLINE,(WPARAM)0,(LPARAM)(LPCSTR)buf);
715 // just copy it over for now. we may want to process this more later on
716 strcpy(Multi_options_g.std_passwd, buf);
719 // convert the index of an item in the list box into an index into the net players array
720 int std_connect_lindex_to_npindex(int index)
727 // get the control handle
728 ctrl = GetDlgItem(Page_handles[CONNECT_PAGE],(int)MAKEINTRESOURCE(IDC_CONPING));
730 // get the string contained at a given index
731 SendMessage(ctrl,LB_GETTEXT,(WPARAM)index,(LPARAM)(LPSTR)list_text);
733 // look through the net players array and compare address strings (yuck)
735 for(idx=0;idx<MAX_PLAYERS;idx++){
736 // only look at connected players
737 if(MULTI_CONNECTED(Net_players[idx])){
738 strcpy(addr_text,"");
739 psnet_addr_to_string(addr_text,&Net_players[idx].p_info.addr);
741 // if we found the match
742 if((strlen(addr_text) != 0) && (strstr(list_text,addr_text) != NULL)){
752 // message handler for the connect tab
753 BOOL CALLBACK connect_proc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)
756 // initialize the dialog
758 // setup the page handle array for this page
759 Page_handles[CONNECT_PAGE] = hwndDlg;
761 // create the standalone name text box and limit its text length
762 Multi_std_name = GetDlgItem(hwndDlg, (int)MAKEINTRESOURCE(IDC_STD_NAME));
763 SendMessage(Multi_std_name, EM_SETLIMITTEXT, (WPARAM)MAX_GAMENAME_LEN-1, (LPARAM)0);
764 Multi_std_namechange_force = 1;
766 // create the standalone host password input box
767 Multi_std_host_passwd = GetDlgItem(hwndDlg, (int)MAKEINTRESOURCE(IDC_STD_HOST_PASSWD));
768 SendMessage(Multi_std_host_passwd, EM_SETLIMITTEXT, (WPARAM)STD_PASSWD_LEN, (LPARAM)0);
769 memset(Multi_options_g.std_passwd, 0, STD_PASSWD_LEN+1);
773 // process a command of some kind (usually button presses)
775 switch(HIWORD(wParam)){
778 switch(LOWORD(wParam)){
779 // the reset standalone button
780 case IDC_RESET_MULTI :
781 // multi_standalone_quit_game();
782 multi_quit_game(PROMPT_NONE);
785 // kick the currently selected player
786 case IDC_KICK_BUTTON :
787 std_connect_kick_player();
790 // refresh file list (PXO)
791 case IDC_PXO_REFRESH:
792 if(MULTI_IS_TRACKER_GAME){
793 // delete mvalid.cfg if it exists
794 cf_delete(MULTI_VALID_MISSION_FILE, CF_TYPE_DATA);
797 multi_update_valid_missions();
802 // an edit control text has been changed
804 if((HWND)lParam == Multi_std_name){
805 // update the standalone name field in Netgame.name
806 std_connect_handle_name_change();
807 } else if((HWND)lParam == Multi_std_host_passwd){
808 // update the standalone host passwd
809 std_connect_handle_passwd_change();
815 // a notification message
817 // notification that this is the current selected page. set our own internal data vars
818 if(((LPNMHDR)lParam)->code == PSN_SETACTIVE){
819 Active_standalone_page = CONNECT_PAGE;
820 } else if ( (((LPNMHDR)lParam)->code == PSN_APPLY) || (((LPNMHDR)lParam)->code == PSN_RESET) ) {
821 PostMessage( Psht, WM_DESTROY, 0, 0 );
832 // ----------------------------------------------------------------------------------------
833 // multiplayer page/tab functions
836 static HWND Framecap_trackbar; // trackbar for capping framerate
837 static HWND Standalone_FPS; // text control for displaying framerate
838 static HWND Standalone_mission_name; // text control for showing the current mission name
839 static HWND Standalone_missiontime; // text control for showing current mission time
840 static HIMAGELIST Goal_bitmaps; // bitmaps array for the goal tree control
841 static HWND Standalone_goals; // goal tree control handle
842 static HTREEITEM Goal_items[3]; // primary, secondary, and bonus goal items
843 static HWND Std_ng_max_players; // max players display text control
844 static HWND Std_ng_max_observers; // max observers display text control
845 static HWND Std_ng_security; // netgame security display text control
846 static HWND Std_ng_respawns; // netgame # respawns display text control
848 #define GOALVIEW_X 5 // goal view control extents
849 #define GOALVIEW_Y 242 //
850 #define GOALVIEW_W 160 //
851 #define GOALVIEW_H 168 //
853 // handle the user sliding the framerate cap scrollbar around
854 void std_multi_handle_framecap_scroll(HWND ctrl);
856 // initialize the framerate cap slide control
857 void std_multi_init_framecap_slider(HWND hwndDlg);
859 // initialize all the controls for this page
860 void std_multi_init_multi_controls(HWND hwndDlg);
862 // return the handle to the item matching the given parameters
863 HTREEITEM std_multi_get_goal_item(char *goal_string,int type);
865 // set the mission time in seconds
866 void std_multi_set_standalone_missiontime(float mission_time)
870 fix m_time = fl2f(mission_time);
872 // format the time string and set the text
873 game_format_time(m_time,time_txt);
874 sprintf(txt," : %.1f", mission_time);
875 strcat(time_txt,txt);
876 SetWindowText(Standalone_missiontime,time_txt);
879 // set the mission name
880 void std_multi_set_standalone_mission_name(char *mission_name)
883 SetWindowText(Standalone_mission_name,mission_name);
886 // initialize the goal tree for this mission
887 void std_multi_setup_goal_tree()
890 TV_INSERTSTRUCT tree_insert;
891 char goal_name[NAME_LENGTH+1];
893 // clear out the tree control
894 TreeView_DeleteAllItems(Standalone_goals);
896 // add the primary goal tag
897 new_item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
898 new_item.pszText = goal_name;
899 strcpy(new_item.pszText,XSTR("Primary Objectives",917));
901 new_item.iSelectedImage = 0;
902 tree_insert.hParent = NULL;
903 tree_insert.hInsertAfter = TVI_FIRST;
904 tree_insert.item = new_item;
905 Goal_items[0] = TreeView_InsertItem(Standalone_goals,&tree_insert);
907 // add the secondary goal tag
908 new_item.pszText = goal_name;
909 strcpy(new_item.pszText,XSTR("Secondary Objectives",918));
911 new_item.iSelectedImage = 0;
912 tree_insert.hInsertAfter = TVI_LAST;
913 tree_insert.item = new_item;
914 Goal_items[1] = TreeView_InsertItem(Standalone_goals,&tree_insert);
916 // add the bonus goal tag
917 new_item.pszText = goal_name;
918 strcpy(new_item.pszText,XSTR("Bonus Objectives",919));
920 new_item.iSelectedImage = 0;
921 tree_insert.item = new_item;
922 Goal_items[2] = TreeView_InsertItem(Standalone_goals,&tree_insert);
925 // add all the goals from the current mission to the tree control
926 void std_multi_add_goals()
929 TV_INSERTSTRUCT tree_insert;
930 int idx,goal_flags,perm_goal_flags;
931 char goal_name[NAME_LENGTH+1];
933 // setup data common for every item
934 new_item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
935 tree_insert.hInsertAfter = TVI_LAST;
938 for(idx=0;idx<Num_goals;idx++){
939 // reset the goal flags
942 switch(Mission_goals[idx].type & GOAL_TYPE_MASK){
945 goal_flags |= (1<<1); // (image index == 1, primary goal)
946 perm_goal_flags |= (1<<1);
950 case SECONDARY_GOAL :
951 goal_flags |= (1<<2); // (image index == 1, secondary goal)
952 perm_goal_flags |= (1<<2);
957 goal_flags |= (1<<3); // (image index == 1, bonus goal)
958 perm_goal_flags |= (1<<3);
962 goal_flags |= (1<<0); // (image index == 3, no goal)
966 // first select whether to insert under primary, secondary, or bonus tree roots
967 tree_insert.hParent = Goal_items[Mission_goals[idx].type & GOAL_TYPE_MASK];
970 new_item.pszText = goal_name;
971 strcpy(new_item.pszText,Mission_goals[idx].name);
973 // set the correct image indices
974 new_item.iImage = (goal_flags & (1<<0)) ? 3 : 0;
975 new_item.iSelectedImage = (goal_flags & (1<<0)) ? 3 : 0;
978 tree_insert.item = new_item;
979 TreeView_InsertItem(Standalone_goals,&tree_insert);
982 // check to see if there are any of the three types of mission goals. If not, then
984 if(!(perm_goal_flags & (1<<1))){
985 // insert the "none" item
986 tree_insert.hParent = Goal_items[0];
987 new_item.pszText = goal_name;
988 strcpy(new_item.pszText,XSTR("none",920));
990 new_item.iSelectedImage = 3;
991 tree_insert.item = new_item;
992 TreeView_InsertItem(Standalone_goals,&tree_insert);
994 if(!(perm_goal_flags & (1<<2))){
995 // insert the "none" item
996 tree_insert.hParent = Goal_items[1];
997 new_item.pszText = goal_name;
998 strcpy(new_item.pszText,XSTR("none",920));
1000 new_item.iSelectedImage = 3;
1001 tree_insert.item = new_item;
1002 TreeView_InsertItem(Standalone_goals,&tree_insert);
1004 if(!(perm_goal_flags & (1<<3))){
1005 // insert the "none" item
1006 tree_insert.hParent = Goal_items[1];
1007 new_item.pszText = goal_name;
1008 strcpy(new_item.pszText,XSTR("none",920));
1009 new_item.iImage = 3;
1010 new_item.iSelectedImage = 3;
1011 tree_insert.item = new_item;
1012 TreeView_InsertItem(Standalone_goals,&tree_insert);
1015 // expand out all the tree roots so all goals are shown
1016 for(idx=0;idx<3;idx++){
1017 TreeView_Expand(Standalone_goals,Goal_items[idx],TVE_EXPAND);
1021 // update all the goals in the goal tree based upon the mission status
1022 void std_multi_update_goals()
1024 HTREEITEM update_item;
1025 TV_ITEM setting,lookup;
1026 int idx,should_update;
1028 setting.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
1030 // go through all the goals
1031 for(idx=0;idx<Num_goals;idx++){
1032 // get a handle to the tree item
1034 update_item = std_multi_get_goal_item(Mission_goals[idx].name,Mission_goals[idx].type & GOAL_TYPE_MASK);
1036 // continue if we didn't get a valid item
1037 if(update_item == NULL){
1041 // get the tree item itself (as it currently stands)
1042 lookup.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
1043 lookup.hItem = update_item;
1044 if(!TreeView_GetItem(Standalone_goals,&lookup)){
1049 // determine what image to set for each one (failed, satisfied, incomplete, etc)
1050 switch(Mission_goals[idx].satisfied){
1052 // determine if we should update the item
1053 if((lookup.iImage != 4) && (lookup.iSelectedImage != 4)){
1055 setting.iSelectedImage = 4;
1060 case GOAL_COMPLETE :
1061 // determine if we should update the item
1062 if((lookup.iImage != 2) && (lookup.iSelectedImage != 2)){
1064 setting.iSelectedImage = 2;
1070 case GOAL_INCOMPLETE :
1071 // determine if we should update the item
1072 if((lookup.iImage != 1) && (lookup.iSelectedImage != 1)){
1074 setting.iSelectedImage = 1;
1081 // set the actual image
1083 setting.hItem = update_item;
1084 TreeView_SetItem(Standalone_goals,&setting);
1089 // set the framerate text box for this page
1090 void std_multi_set_framerate(float f)
1094 // set the window text
1095 sprintf(fr,"%.1f",f);
1096 SetWindowText(Standalone_FPS,fr);
1099 // clear all the controls for this page
1100 void std_multi_clear_controls()
1102 // clear out the mission name text static
1103 SetWindowText(Standalone_mission_name,"");
1105 // clear out the framerate text box
1106 SetWindowText(Standalone_FPS,"");
1108 // clear out the misison time text box
1109 SetWindowText(Standalone_missiontime,"");
1111 // clear out the netgame max players text box
1112 SetWindowText(Std_ng_max_players,"");
1114 // clear out the netgame max observer text box
1115 SetWindowText(Std_ng_max_observers,"");
1117 // clear out the netgame security text box
1118 SetWindowText(Std_ng_security,"");
1120 // clear out the netgame respawns # text box
1121 SetWindowText(Std_ng_respawns,"");
1123 // clear the goal tree control
1124 std_multi_setup_goal_tree();
1127 // update the netgame information area controls with the current Netgame settings
1128 void std_multi_update_netgame_info_controls()
1134 // update the max players control
1135 sprintf(buf,"%d",Netgame.max_players);
1136 SetWindowText(Std_ng_max_players,buf);
1138 // update the max observers control
1139 sprintf(buf,"%d",Netgame.options.max_observers);
1140 SetWindowText(Std_ng_max_observers,buf);
1142 // update the netgame security control
1143 sprintf(buf,"%d",Netgame.security);
1144 SetWindowText(Std_ng_security,buf);
1146 // update the netgame respawns # control
1147 sprintf(buf,"%d",Netgame.respawn);
1148 SetWindowText(Std_ng_respawns,buf);
1151 // handle the user sliding the framerate cap scrollbar around
1152 void std_multi_handle_framecap_scroll(HWND ctrl)
1157 // determine where the slider now is
1158 pos = SendMessage(ctrl,TBM_GETPOS,(WPARAM)0,(LPARAM)0);
1160 // update the text display
1161 sprintf(pos_text,"%d",pos);
1162 SetWindowText(GetDlgItem(Page_handles[MULTIPLAYER_PAGE],(int)MAKEINTRESOURCE(IDC_FRAMECAP_STATIC)),pos_text);
1164 // set the framecap var
1165 Multi_options_g.std_framecap = pos;
1168 // initialize the framerate cap slide control
1169 void std_multi_init_framecap_slider(HWND hwndDlg)
1174 // create the trackbar object
1175 Framecap_trackbar = CreateWindowEx(0,TRACKBAR_CLASS,NULL,WS_CHILD | WS_VISIBLE,
1176 10,10,300,30,hwndDlg,NULL,GetModuleHandle(NULL),NULL);
1178 // set the range of the framerate cap
1179 wp = (WPARAM)(BOOL)TRUE;
1180 lp = (LPARAM)MAKELONG(1, 100);
1181 SendMessage(Framecap_trackbar,TBM_SETRANGE,wp,lp);
1183 // set the default framerate cap the be the standalone default
1184 wp = (WPARAM)(BOOL)TRUE;
1185 lp = (LPARAM)(LONG)30;
1186 SendMessage(Framecap_trackbar,TBM_SETPOS,wp,lp);
1188 // call this to update the standalone framecap on this first run
1189 std_multi_handle_framecap_scroll(Framecap_trackbar);
1192 // initialize all the controls for this page
1193 void std_multi_init_multi_controls(HWND hwndDlg)
1198 // create the framecap slider
1199 std_multi_init_framecap_slider(hwndDlg);
1201 // create the framerate display text box
1202 Standalone_FPS = GetDlgItem(hwndDlg,(int)MAKEINTRESOURCE(IDC_STANDALONE_FPS));
1204 // create the missiontime text box
1205 Standalone_missiontime = GetDlgItem(hwndDlg,(int)MAKEINTRESOURCE(IDC_STANDALONE_MTIME));
1207 // create the mission name text box
1208 Standalone_mission_name = GetDlgItem(hwndDlg,(int)MAKEINTRESOURCE(IDC_MISSION_NAME));
1210 // create the netgame max players text box
1211 Std_ng_max_players = GetDlgItem(hwndDlg,(int)MAKEINTRESOURCE(IDC_NG_MAXPLAYERS));
1213 // create the netgame max observers text box
1214 Std_ng_max_observers = GetDlgItem(hwndDlg,(int)MAKEINTRESOURCE(IDC_NG_MAXOBSERVERS));
1216 // create the netgame security text box
1217 Std_ng_security = GetDlgItem(hwndDlg,(int)MAKEINTRESOURCE(IDC_NG_SECURITY));
1219 // create the netgame respawns # text box
1220 Std_ng_respawns = GetDlgItem(hwndDlg,(int)MAKEINTRESOURCE(IDC_NG_RESPAWNS));
1222 // load the goal tree-view bitmaps
1223 Goal_bitmaps = ImageList_Create(16,16,ILC_COLOR4 | ILC_MASK,5,0);
1226 ref = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_GOAL_ORD));
1227 ImageList_AddMasked(Goal_bitmaps,ref,mask);
1229 ref = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_GOAL_INC));
1231 ImageList_AddMasked(Goal_bitmaps,ref,mask);
1233 ref = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_GOAL_COMP));
1235 ImageList_AddMasked(Goal_bitmaps,ref,mask);
1237 ref = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_GOAL_NONE));
1239 ImageList_AddMasked(Goal_bitmaps,ref,mask);
1241 ref = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_GOAL_FAIL));
1243 ImageList_AddMasked(Goal_bitmaps,ref,mask);
1245 // create the tree view control and associate its image list
1246 Standalone_goals = CreateWindowEx(0, WC_TREEVIEW, XSTR("Tree View",921),
1247 WS_VISIBLE | WS_CHILD | WS_BORDER | TVS_HASLINES,
1248 GOALVIEW_X,GOALVIEW_Y,GOALVIEW_W,GOALVIEW_H,
1249 hwndDlg, NULL, GetModuleHandle(NULL), NULL);
1250 TreeView_SetImageList(Standalone_goals,Goal_bitmaps,TVSIL_NORMAL);
1253 // return the handle to the item matching the given parameters
1254 HTREEITEM std_multi_get_goal_item(char *goal_string,int type)
1256 HTREEITEM ret,moveup;
1259 char goal_name_text[NAME_LENGTH+1];
1261 // look under the correct root item
1262 lookup.mask = TVIF_TEXT;
1263 lookup.pszText = goal_name_text;
1264 lookup.cchTextMax = NAME_LENGTH;
1265 strcpy(lookup.pszText,goal_string);
1267 // search through all the items
1270 moveup = TreeView_GetChild(Standalone_goals,Goal_items[type]);
1271 while(!done && moveup!=NULL){
1272 lookup.hItem = moveup;
1273 TreeView_GetItem(Standalone_goals,&lookup);
1274 if(strcmp(lookup.pszText,goal_string)==0){
1279 moveup = TreeView_GetNextItem(Standalone_goals,moveup,TVGN_NEXT);
1285 // message handler for the multiplayer tab
1286 BOOL CALLBACK multi_proc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)
1289 // initialize the page
1291 // set the page handle
1292 Page_handles[MULTIPLAYER_PAGE] = hwndDlg;
1294 // initialize all the controls
1295 std_multi_init_multi_controls(hwndDlg);
1299 // a scroll message from the framerate cap trackbar
1301 std_multi_handle_framecap_scroll((HWND)lParam);
1305 // notification that this page has been set as active
1307 // setup our own internal vars
1308 if(((LPNMHDR)lParam)->code == PSN_SETACTIVE){
1309 Active_standalone_page = MULTIPLAYER_PAGE;
1310 } else if ( (((LPNMHDR)lParam)->code == PSN_APPLY) || (((LPNMHDR)lParam)->code == PSN_RESET) ) {
1311 // PostMessage( Psht, WM_DESTROY, 0, 0 );
1312 gameseq_post_event(GS_EVENT_QUIT_GAME);
1324 // ---------------------------------------------------------------------------------------
1325 // player info page/tab functions
1328 #define MAX_PLAYER_STAT_FIELDS 11 // the # of stats fields for a given set
1329 static HWND Player_name_list; // the listbox control with player callsigns in it
1330 static HWND Player_ship_type; // the current player's ship type
1331 static HWND Player_ping_time; // the current player's ping time
1332 static HWND Player_stats[MAX_PLAYER_STAT_FIELDS]; // text boxes for player alltime statistics info
1333 static HWND Player_mstats[MAX_PLAYER_STAT_FIELDS]; // text boxes for player mission statistics info
1335 // sprintf and set window text to the passed int
1336 #define STD_ADDSTRING(hwnd,val) { sprintf(txt,"%d",(int)val); SetWindowText(hwnd,txt); }
1338 // intialize all the controls in the player info tab
1339 void std_pinfo_init_player_info_controls(HWND hwndDlg);
1341 // returns true or false depending on whether the passed netplayer is the currently selected guy
1342 int std_pinfo_player_is_active(net_player *p);
1344 // start displaying info for the passed player on this page
1345 void std_pinfo_display_player_info(net_player *p)
1349 // set his ship type
1350 SetWindowText(Player_ship_type,Ship_info[p->p_info.ship_class].name);
1352 // display his ping time
1353 std_pinfo_update_ping(p);
1355 // his alltime stats
1356 scoring_struct *ptr = &p->player->stats;
1357 STD_ADDSTRING(Player_stats[0],ptr->p_shots_fired);
1358 STD_ADDSTRING(Player_stats[1],ptr->p_shots_hit);
1359 STD_ADDSTRING(Player_stats[2],ptr->p_bonehead_hits);
1360 STD_ADDSTRING(Player_stats[3],
1361 (int)((float)100.0*((float)ptr->p_shots_hit/(float)ptr->p_shots_fired)));
1362 STD_ADDSTRING(Player_stats[4],
1363 (int)((float)100.0*((float)ptr->p_bonehead_hits/(float)ptr->p_shots_fired)));
1364 STD_ADDSTRING(Player_stats[5],ptr->s_shots_fired);
1365 STD_ADDSTRING(Player_stats[6],ptr->s_shots_hit);
1366 STD_ADDSTRING(Player_stats[7],ptr->s_bonehead_hits);
1367 STD_ADDSTRING(Player_stats[8],
1368 (int)((float)100.0*((float)ptr->s_shots_hit/(float)ptr->s_shots_fired)));
1369 STD_ADDSTRING(Player_stats[9],
1370 (int)((float)100.0*((float)ptr->s_bonehead_hits/(float)ptr->s_shots_fired)));
1371 STD_ADDSTRING(Player_stats[10],ptr->assists);
1373 // his stats for the current mission
1374 STD_ADDSTRING(Player_mstats[0],ptr->mp_shots_fired);
1375 STD_ADDSTRING(Player_mstats[1],ptr->mp_shots_hit);
1376 STD_ADDSTRING(Player_mstats[2],ptr->mp_bonehead_hits);
1377 STD_ADDSTRING(Player_mstats[3],
1378 (int)((float)100.0*((float)ptr->mp_shots_hit/(float)ptr->mp_shots_fired)));
1379 STD_ADDSTRING(Player_mstats[4],
1380 (int)((float)100.0*((float)ptr->mp_bonehead_hits/(float)ptr->mp_shots_fired)));
1381 STD_ADDSTRING(Player_mstats[5],ptr->ms_shots_fired);
1382 STD_ADDSTRING(Player_mstats[6],ptr->ms_shots_hit);
1383 STD_ADDSTRING(Player_mstats[7],ptr->ms_bonehead_hits);
1384 STD_ADDSTRING(Player_mstats[8],
1385 (int)((float)100.0*((float)ptr->ms_shots_hit/(float)ptr->ms_shots_fired)));
1386 STD_ADDSTRING(Player_mstats[9],
1387 (int)((float)100.0*((float)ptr->ms_bonehead_hits/(float)ptr->ms_shots_fired)));
1388 STD_ADDSTRING(Player_mstats[10],ptr->m_assists);
1391 // check to see if this player is the one being displayed, and if so, then update the display info
1392 // return 1 if the player was updated
1393 int std_pinfo_maybe_update_player_info(net_player *p)
1395 // only update if this is the currently active player
1396 if(std_pinfo_player_is_active(p)){
1397 std_pinfo_display_player_info(p);
1403 // add a player to the list on the player info page
1404 void std_pinfo_add_player_list_item(net_player *p)
1407 SendMessage(Player_name_list,CB_ADDSTRING,(WPARAM)0,(LPARAM)(LPCTSTR)p->player->callsign);
1409 // if this is the first item on the list, then select it and display it
1410 if(SendMessage(Player_name_list,CB_GETCOUNT,(WPARAM)0,(LPARAM)0) == 1){
1412 SendMessage(Player_name_list,CB_SETCURSEL,(WPARAM)0,(LPARAM)0);
1414 // display this players info
1415 std_pinfo_display_player_info(p);
1419 // remove a player from the list on the player info page
1420 void std_pinfo_remove_player_list_item(net_player *p)
1424 // lookup thie player
1425 loc = SendMessage(Player_name_list,CB_FINDSTRINGEXACT,(WPARAM)-1,(LPARAM)(LPCTSTR)p->player->callsign);
1427 // if we found the entry, then delete it
1429 SendMessage(Player_name_list,CB_DELETESTRING,(WPARAM)loc,(LPARAM)0);
1433 // update the ping display for this player
1434 void std_pinfo_update_ping(net_player *p)
1438 // chop it off at pings greater than 1 second
1439 if(p->s_info.ping.ping_avg > 1000){
1440 strcpy(sml_ping,XSTR("> 1 sec",914));
1442 // use the ping itself
1444 sprintf(sml_ping,"%d",p->s_info.ping.ping_avg);
1445 strcat(sml_ping,XSTR(" ms",915));
1448 SetWindowText(Player_ping_time,sml_ping);
1451 // clear the player info page controls
1452 void std_pinfo_clear_controls()
1456 // clear the player selection list
1457 SendMessage(Player_name_list,CB_RESETCONTENT,(WPARAM)0,(LPARAM)0);
1459 // clear out misc items
1460 SetWindowText(Player_ship_type,"");
1461 SetWindowText(Player_ping_time,"");
1463 // clear out the player stats
1464 for(idx=0;idx<MAX_PLAYER_STAT_FIELDS;idx++){
1465 SetWindowText(Player_stats[idx],"");
1466 SetWindowText(Player_mstats[idx],"");
1470 // intialize all the controls in the player info tab
1471 void std_pinfo_init_player_info_controls(HWND hwndDlg)
1473 // create the player callsign listbox
1474 Player_name_list = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_PLAYER_LIST));
1476 // create the player ship type text box
1477 Player_ship_type = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_PSHIP_TYPE));
1479 // create the player ping time text box
1480 Player_ping_time = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_PING_TIME));
1482 // initialize the various and sundry statistics text controls (alltime)
1483 Player_stats[0] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_PSHOTS));
1484 Player_stats[1] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_PHITS));
1485 Player_stats[2] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_PBHHITS));
1486 Player_stats[3] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_PPCT));
1487 Player_stats[4] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_PBHPCT));
1488 Player_stats[5] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_SSHOTS));
1489 Player_stats[6] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_SECHITS));
1490 Player_stats[7] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_SBHHITS));
1491 Player_stats[8] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_SPCT));
1492 Player_stats[9] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_SBHPCT));
1493 Player_stats[10] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_ASSISTS));
1495 // initialize the various and sundry statistics text controls (this mission)
1496 Player_mstats[0] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MPSHOTS));
1497 Player_mstats[1] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MPHITS));
1498 Player_mstats[2] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MPBHHITS));
1499 Player_mstats[3] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MPPCT));
1500 Player_mstats[4] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MPBHPCT));
1501 Player_mstats[5] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MSSHOTS));
1502 Player_mstats[6] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MSECHITS));
1503 Player_mstats[7] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MSBHHITS));
1504 Player_mstats[8] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MSPCT));
1505 Player_mstats[9] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MSBHPCT));
1506 Player_mstats[10] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MASSISTS));
1509 // returns true or false depending on whether the passed netplayer is the currently selected guy
1510 int std_pinfo_player_is_active(net_player *p)
1515 // get the index of the currently selected item
1516 sel = SendMessage(Player_name_list,CB_GETCURSEL,(WPARAM)0,(LPARAM)0);
1518 // if we didn't find the item, return a 0 length string
1523 // otherwise, get the callsign of the given player
1524 SendMessage(Player_name_list,CB_GETLBTEXT,(WPARAM)sel,(LPARAM)player);
1526 // if there is a valid player selected and he's the guy we want
1527 return ((strlen(player) != 0) && (strcmp(p->player->callsign,player) == 0)) ? 1 : 0;
1530 // message handler for the player info tab
1531 BOOL CALLBACK player_info_proc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)
1537 // initialize the dialog
1539 // set the page handle
1540 Page_handles[PLAYER_INFO_PAGE] = hwndDlg;
1542 // intialize all the control
1543 std_pinfo_init_player_info_controls(hwndDlg);
1547 // a command message of some kind
1549 switch(HIWORD(wParam)){
1550 // a listbox selection change message
1551 case CBN_SELCHANGE :
1552 // get the newly selected item
1553 val = SendMessage(Player_name_list,CB_GETCURSEL,(WPARAM)0,(LPARAM)0);
1556 if(SendMessage(Player_name_list,CB_GETLBTEXT,(WPARAM)val,(LPARAM)callsign) != CB_ERR){
1557 // lookup the player
1558 player_num = multi_find_player_by_callsign(callsign);
1560 // if we found him then display his info
1561 if(player_num != -1){
1562 std_pinfo_display_player_info(&Net_players[player_num]);
1570 // a notification message
1572 // set our page to be the active one
1573 if(((LPNMHDR)lParam)->code == PSN_SETACTIVE){
1574 Active_standalone_page = PLAYER_INFO_PAGE;
1575 } else if ( (((LPNMHDR)lParam)->code == PSN_APPLY) || (((LPNMHDR)lParam)->code == PSN_RESET) ) {
1576 PostMessage( Psht, WM_DESTROY, 0, 0 );
1588 // ---------------------------------------------------------------------------------------
1589 // player god stuff page/tab functions
1592 #define GODSTUFF_MAX_ITEMS 19 // how many items we can fit on the chatbox at one time
1594 static HWND God_player_list; // the listbox of player callsigns
1595 static HWND Godstuff_fps; // the framerate text box
1596 static HWND Godstuff_broadcast_text; // the text input box for sending messages to players
1597 static HWND Godstuff_broadcast_button; // the button to send the text messages
1598 static HWND Godstuff_player_messages; // handle to the list box containing player chatter
1600 // initialize all the controls in the godstuff tab
1601 void std_gs_init_godstuff_controls(HWND hwndDlg);
1603 // add a player to the listbox on the godstuff page
1604 void std_gs_add_god_player(net_player *p)
1607 SendMessage(God_player_list,CB_ADDSTRING,(WPARAM)0,(LPARAM)(LPCTSTR)p->player->callsign);
1609 // if this is the first item on the list, then select it
1610 if(SendMessage(God_player_list,CB_GETCOUNT,(WPARAM)0,(LPARAM)0) == 1){
1612 SendMessage(God_player_list,CB_SETCURSEL,(WPARAM)0,(LPARAM)0);
1616 // remove a player from the listbox on the godstuff page
1617 void std_gs_remove_god_player(net_player *p)
1621 // lookup the player
1622 loc = SendMessage(God_player_list,CB_FINDSTRINGEXACT,(WPARAM)-1,(LPARAM)(LPCTSTR)p->player->callsign);
1624 // if we found him, them delete the item
1626 SendMessage(God_player_list,CB_DELETESTRING,(WPARAM)loc,(LPARAM)0);
1630 // send a message as if the standalone were a player
1631 void std_gs_send_godstuff_message()
1635 // get the text in the edit control
1638 SendMessage(Godstuff_broadcast_text,EM_GETLINE,(WPARAM)0,(LPARAM)&txt[0]);
1640 // if the string is not zero length
1641 if(strlen(txt) > 0){
1642 // send a game chat packet
1643 send_game_chat_packet(Net_player, txt, MULTI_MSG_ALL,NULL);
1645 // add the text to our own control
1646 std_add_chat_text(txt, MY_NET_PLAYER_NUM,1);
1648 // clear the text control
1649 SetWindowText(Godstuff_broadcast_text, "");
1653 // set the framerate text box for this page
1654 void std_gs_set_framerate(float f)
1658 // set the window text
1659 sprintf(fr,"%.1f",f);
1660 SetWindowText(Godstuff_fps,fr);
1663 // clear the godstuff page controlsv
1664 void std_gs_clear_controls()
1666 // clear the framerate area
1667 SetWindowText(Godstuff_fps, "0");
1669 // clear the text area
1670 SetWindowText(Godstuff_broadcast_text,"");
1672 // reset the combo box
1673 SendMessage(God_player_list, CB_RESETCONTENT, (WPARAM)0, (LPARAM)0);
1675 // clear the player chatter listbox
1676 SendMessage(Godstuff_player_messages, LB_RESETCONTENT, (WPARAM)0, (LPARAM)0);
1679 // initialize all the controls in the godstuff tab
1680 void std_gs_init_godstuff_controls(HWND hwndDlg)
1682 // initialize the player listbox control
1683 God_player_list = GetDlgItem(Page_handles[GODSTUFF_PAGE], (int)MAKEINTRESOURCE(IDC_PLAYER_GOD_LIST));
1685 // initialize the framerate text box
1686 Godstuff_fps = GetDlgItem(Page_handles[GODSTUFF_PAGE], (int)MAKEINTRESOURCE(IDC_GODSTUFF_FPS));
1688 // initialize the messaging edit control
1689 Godstuff_broadcast_text = GetDlgItem(Page_handles[GODSTUFF_PAGE], (int)MAKEINTRESOURCE(IDC_GODSTUFF_BROADCAST));
1690 SendMessage(Godstuff_broadcast_text, EM_SETLIMITTEXT, (WPARAM)CHATBOX_MAX_LEN, (LPARAM)0);
1691 SendMessage(Godstuff_broadcast_text, EM_FMTLINES, (WPARAM)TRUE, (LPARAM)0);
1693 // create the player chatter list box
1694 Godstuff_player_messages = GetDlgItem(Page_handles[GODSTUFF_PAGE], (int)MAKEINTRESOURCE(IDC_GOD_CHAT));
1696 // initialize the message broadcast button
1697 Godstuff_broadcast_button = GetDlgItem(Page_handles[GODSTUFF_PAGE], (int)MAKEINTRESOURCE(IDC_GODSTUFF_SENDMESS));
1698 // hide the button -- we can now process return key
1699 ShowWindow(Godstuff_broadcast_button, SW_HIDE);
1703 // message handler for the godstuff tab
1704 BOOL CALLBACK godstuff_proc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
1707 // initialize the dialog
1709 // setup the page handle
1710 Page_handles[GODSTUFF_PAGE] = hwndDlg;
1712 // initialize the controls for this page
1713 std_gs_init_godstuff_controls(hwndDlg);
1717 // a notification message
1719 // set this page to be the currently active one
1720 if(((LPNMHDR)lParam)->code == PSN_SETACTIVE){
1721 Active_standalone_page = GODSTUFF_PAGE;
1722 } else if ( (((LPNMHDR)lParam)->code == PSN_APPLY) || (((LPNMHDR)lParam)->code == PSN_RESET) ) {
1723 PostMessage( Psht, WM_DESTROY, 0, 0 );
1728 // a command message of some kind
1730 switch(HIWORD(wParam)){
1733 switch(LOWORD(wParam)){
1734 // send the message to the player
1735 case IDC_GODSTUFF_SENDMESS :
1736 std_gs_send_godstuff_message();
1752 // ---------------------------------------------------------------------------------------
1753 // debug page/tab functions
1756 static HWND Standalone_state_string; // the text control box
1758 // initialize the controls for the debug page
1759 void std_debug_init_debug_controls(HWND hwndDlg);
1761 // set the text on the standalones state indicator box
1762 void std_debug_set_standalone_state_string(char *str)
1765 SetWindowText(Standalone_state_string,str);
1768 // clear the debug page controls
1769 void std_debug_clear_controls()
1771 // set the current debug state
1772 std_debug_set_standalone_state_string("");
1775 // initialize the controls for the debug page
1776 void std_debug_init_debug_controls(HWND hwndDlg)
1778 // create the state string text box
1779 Standalone_state_string = GetDlgItem(hwndDlg,(int)MAKEINTRESOURCE(IDC_STANDALONE_STATE));
1781 // standalone state indicator
1782 SetWindowText(Standalone_state_string,"");
1785 // message handler for the godstuff tab
1786 BOOL CALLBACK debug_proc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)
1789 // initialize the dialog
1791 // setup the page handle
1792 Page_handles[DEBUG_PAGE] = hwndDlg;
1794 // intialize the controls for this page
1795 std_debug_init_debug_controls(hwndDlg);
1799 // a notification message
1801 // set the currently active page to this one
1802 if(((LPNMHDR)lParam)->code == PSN_SETACTIVE){
1803 Active_standalone_page = DEBUG_PAGE;
1804 } else if ( (((LPNMHDR)lParam)->code == PSN_APPLY) || (((LPNMHDR)lParam)->code == PSN_RESET) ) {
1805 PostMessage( Psht, WM_DESTROY, 0, 0 );
1817 // ---------------------------------------------------------------------------------------
1818 // general functions
1821 // add a player and take care of updating all gui/data details
1822 void std_add_player(net_player *p)
1826 // get his ip string and add it to the list
1827 psnet_addr_to_string(ip_string,&p->p_info.addr);
1828 std_connect_add_ip_string(ip_string);
1830 // add to the player info player list box, and update his info
1831 std_pinfo_add_player_list_item(p);
1832 std_pinfo_maybe_update_player_info(p);
1834 // add to the god stuff player list box
1835 std_gs_add_god_player(p);
1837 // check to see if this guy is the host.
1838 std_connect_set_host_connect_status();
1840 // set the connection count
1841 std_connect_set_connect_count();
1844 // remove a player and take care of updateing all gui/data details
1845 int std_remove_player(net_player *p)
1850 // determine his ip string and remove it from the list
1851 psnet_addr_to_string(ip_string,&p->p_info.addr);
1852 std_connect_remove_ip_string(ip_string);
1854 // remove from the player info player list box
1855 std_pinfo_remove_player_list_item(p);
1857 // remove from the godstuff list box
1858 std_gs_remove_god_player(p);
1860 // update the host connect count
1861 std_connect_set_host_connect_status();
1863 // update the currently connected players
1864 count = std_connect_set_connect_count();
1867 // multi_standalone_quit_game();
1868 multi_quit_game(PROMPT_NONE);
1875 // set any relevant controls which display the framerate of the standalone
1876 void std_set_standalone_fps(float fps)
1878 // set the framerate in the multiplayer dialog
1879 std_multi_set_framerate(fps);
1881 // set the framerate in the godstuff dialog
1882 std_gs_set_framerate(fps);
1885 // update any relveant controls which display the ping for the given player
1886 void std_update_player_ping(net_player *p)
1888 // update the ping on the connect page
1889 std_connect_update_ping(p);
1891 // update the ping on the player info page
1892 std_pinfo_update_ping(p);
1895 // reset everything in the standalone gui (all the controls)
1896 void std_reset_standalone_gui()
1898 // clear the connect page controls
1899 std_connect_clear_controls();
1901 // clear the multi page controls
1902 std_multi_clear_controls();
1904 // clear the player info page controls
1905 std_pinfo_clear_controls();
1907 // clear the godstuff page controls
1908 std_gs_clear_controls();
1910 // clear the debug page controls
1911 std_debug_clear_controls();
1913 // set all framerate displays to 0
1914 std_set_standalone_fps((float)0);
1916 // set the mission time
1917 std_multi_set_standalone_missiontime((float)0);
1919 // reset the stats update timestamp
1920 Standalone_stats_stamp = -1;
1922 // reset the netgame info timestamp
1923 Standalone_ng_stamp = -1;
1926 // do any gui related issues on the standalone (like periodically updating player stats, etc...)
1927 void std_do_gui_frame()
1931 // check to see if the timestamp for updating player selected stats has popped
1932 if((Standalone_stats_stamp == -1) || timestamp_elapsed(Standalone_stats_stamp)){
1933 // reset the timestamp
1934 Standalone_stats_stamp = timestamp(STD_STATS_UPDATE_TIME);
1936 // update any player currently selected
1937 // there's probably a nicer way to do this, but...
1938 for(idx=0;idx<MAX_PLAYERS;idx++){
1939 if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
1940 if(std_pinfo_maybe_update_player_info(&Net_players[idx])){
1947 // check to see if the timestamp for updating the netgame information controls has popped
1948 if((Standalone_ng_stamp == -1) || timestamp_elapsed(Standalone_ng_stamp)){
1949 // reset the timestamp
1950 Standalone_ng_stamp = timestamp(STD_NG_UPDATE_TIME);
1952 // update the controls
1953 std_multi_update_netgame_info_controls();
1957 // notify the user that the standalone has failed to login to the tracker on startup
1958 void std_notify_tracker_login_fail()
1960 MessageBox(Psht,XSTR("The standalone server has failed to log in to Parallax Online!",922),XSTR("VMT Warning!",923),MB_OK);
1963 // attempt to log the standalone into the tracker
1964 void std_tracker_login()
1968 // reset all stand gui timestamps
1969 void std_reset_timestamps()
1971 // reset the stats update stamp
1972 Standalone_stats_stamp = timestamp(STD_STATS_UPDATE_TIME);
1974 // reset the netgame controls update timestamp
1975 Standalone_ng_stamp = timestamp(STD_NG_UPDATE_TIME);
1978 // add a line of text chat to the standalone
1979 void std_add_chat_text(char *text,int player_index,int add_id)
1981 int num_items,ret_val;
1985 if(player_index == -1){
1989 // format the chat text nicely
1991 if(MULTI_STANDALONE(Net_players[player_index])){
1992 sprintf(format,XSTR("<SERVER> %s",924),text);
1994 sprintf(format,"%s: %s",Net_players[player_index].player->callsign,text);
1997 strcpy(format,text);
2000 // insert the text string into the godstuff chat box and scroll it down to the bottom
2001 SendMessage(Godstuff_player_messages,LB_INSERTSTRING,(WPARAM)-1,(LPARAM)format);
2002 num_items = SendMessage(Godstuff_player_messages,LB_GETCOUNT,(WPARAM)0,(LPARAM)0);
2004 ret_val = SendMessage(Godstuff_player_messages,LB_SETTOPINDEX,(WPARAM)num_items - GODSTUFF_MAX_ITEMS,(LPARAM)0);
2008 // if the standalone is host password protected
2009 int std_is_host_passwd()
2011 return (strlen(Multi_options_g.std_passwd) > 0) ? 1 : 0;
2014 // change the default property sheet interface into something more useful
2015 void std_mutate_sheet()
2017 HWND ok_button = NULL;
2018 HWND cancel_button = NULL;
2019 HWND apply_button = NULL;
2020 HWND help_button = NULL;
2023 // get the buttons on the property sheet itself
2024 HWND child = GetWindow(Psht,GW_CHILD);
2025 while(child != NULL){
2026 // get the text of the window
2027 memset(lookup,0,512);
2028 GetWindowText(child,lookup,511);
2030 // if its the OK button
2031 if(!stricmp(lookup,XSTR("ok",925))){
2035 // if its the cancel button
2036 if(!stricmp(lookup,XSTR("cancel",926))){
2037 cancel_button = child;
2040 // if its the apply button
2041 if(!stricmp(lookup,XSTR("&apply",927))){
2042 apply_button = child;
2045 // if its the help button
2046 if(!stricmp(lookup,XSTR("help",928))){
2047 help_button = child;
2050 child = GetWindow(child,GW_HWNDNEXT);
2054 if(apply_button != NULL){
2055 DestroyWindow(apply_button);
2058 // rename the shutdown button and move it over a bit
2059 if(ok_button != NULL){
2061 SetWindowText(ok_button,XSTR("Shutdown",929));
2064 SetWindowPos(ok_button,
2066 Std_shutdown_coords[gr_screen.res][0],
2067 Std_shutdown_coords[gr_screen.res][1],
2069 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOZORDER
2074 if(cancel_button != NULL){
2075 DestroyWindow(cancel_button);
2079 if(help_button != NULL){
2080 DestroyWindow(help_button);
2083 // now we want to mess with the titlebar controls
2086 // if the given callsign is banned from the server
2087 int std_player_is_banned(char *name)
2091 // go through the ban list
2092 for(idx=0;idx<Standalone_ban_count;idx++){
2093 if(!stricmp(name,Standalone_ban_list[idx])){
2102 // add a callsign to the ban list
2103 void std_add_ban(char *name)
2105 // if we've reached the max bans
2106 if(Standalone_ban_count >= STANDALONE_MAX_BAN){
2111 memset(Standalone_ban_list[Standalone_ban_count],0,CALLSIGN_LEN+1);
2112 strcpy(Standalone_ban_list[Standalone_ban_count++],name);
2116 // -------------------------------------------------------------------------------
2117 // property sheet/page creation and handling
2120 void std_init_property_pages()
2125 p = &Pages[CONNECT_PAGE];
2126 p->dwSize = sizeof(PROPSHEETPAGE);
2127 p->dwFlags = PSP_DEFAULT;
2128 p->hInstance = GetModuleHandle(NULL);
2129 p->pszTemplate = MAKEINTRESOURCE(IDD_CONNECT);
2131 p->pfnDlgProc = (DLGPROC)connect_proc;
2132 p->pszTitle = XSTR("Connections",930);
2134 p->pfnCallback = NULL;
2137 p = &Pages[MULTIPLAYER_PAGE];
2138 p->dwSize = sizeof(PROPSHEETPAGE);
2139 p->dwFlags = PSP_DEFAULT;
2140 p->hInstance = GetModuleHandle(NULL);
2141 p->pszTemplate = MAKEINTRESOURCE(IDD_MULTI);
2143 p->pfnDlgProc = (DLGPROC)multi_proc;
2144 p->pszTitle = XSTR("Multi-Player",931);
2146 p->pfnCallback = NULL;
2149 p = &Pages[PLAYER_INFO_PAGE];
2150 p->dwSize = sizeof(PROPSHEETPAGE);
2151 p->dwFlags = PSP_DEFAULT;
2152 p->hInstance = GetModuleHandle(NULL);
2153 p->pszTemplate = MAKEINTRESOURCE(IDD_PLAYER_DIALOG);
2155 p->pfnDlgProc = (DLGPROC)player_info_proc;
2156 p->pszTitle = XSTR("Player info",932);
2158 p->pfnCallback = NULL;
2161 p = &Pages[GODSTUFF_PAGE];
2162 p->dwSize = sizeof(PROPSHEETPAGE);
2163 p->dwFlags = PSP_DEFAULT;
2164 p->hInstance = GetModuleHandle(NULL);
2165 p->pszTemplate = MAKEINTRESOURCE(IDD_GODSTUFF);
2167 p->pfnDlgProc = (DLGPROC)godstuff_proc;
2168 p->pszTitle = XSTR("God Stuff",933);
2170 p->pfnCallback = NULL;
2173 p = &Pages[DEBUG_PAGE];
2174 p->dwSize = sizeof(PROPSHEETPAGE);
2175 p->dwFlags = PSP_DEFAULT;
2176 p->hInstance = GetModuleHandle(NULL);
2177 p->pszTemplate = MAKEINTRESOURCE(IDD_DEBUG_DIALOG);
2179 p->pfnDlgProc = (DLGPROC)debug_proc;
2180 p->pszTitle = XSTR("Debug",934);
2182 p->pfnCallback = NULL;
2185 // build a title string
2186 void std_build_title_string(char *str)
2192 // build the version #
2193 memset(part1, 0, 256);
2194 memset(cat, 0, 256);
2195 memset(temp, 0, 256);
2197 sprintf(part1, "%s %d.", XSTR("Freespace Standalone",935), FS_VERSION_MAJOR);
2198 if(FS_VERSION_MINOR < 10){
2200 strcat(cat, itoa(FS_VERSION_MINOR, temp, 10));
2202 sprintf(cat, "%d", FS_VERSION_MINOR);
2206 if(FS_VERSION_BUILD < 10){
2208 strcat(cat, itoa(FS_VERSION_BUILD, temp, 10));
2210 sprintf(cat, "%d", FS_VERSION_BUILD);
2217 #ifdef STANDALONE_ONLY_BUILD
2218 sprintf(cat, " %s %d", "Release", STANDALONE_ONLY_RELEASE_VERSION);
2223 // initialize the property sheet itself
2224 HWND std_init_property_sheet(HWND hwndDlg)
2228 // initialize the property pages
2229 std_init_property_pages();
2231 // create the property sheet
2232 Sheet.dwSize = sizeof(PROPSHEETHEADER);
2233 Sheet.dwFlags = PSH_PROPSHEETPAGE | PSH_MODELESS | PSH_NOAPPLYNOW;
2234 Sheet.hwndParent = hwndDlg;
2235 Sheet.hInstance = GetModuleHandle(NULL);
2236 Sheet.nPages = MAX_STANDALONE_PAGES;
2238 // set the title bar appropriately
2239 char title_str[512];
2240 memset(title_str, 0, 512);
2241 std_build_title_string(title_str);
2242 Sheet.pszCaption = title_str;
2244 Sheet.nStartPage = 0;
2245 Sheet.ppsp = &Pages[0];
2246 Sheet.pfnCallback = NULL;
2247 Psht = (HWND)PropertySheet(&Sheet);
2249 // set the window style to include a minimize button
2250 //styles = GetWindowLong(Psht, GWL_STYLE );
2251 //if ( styles != 0 ) {
2252 // SetWindowLong(Psht, GWL_STYLE, styles | WS_MINIMIZEBOX );
2255 styles = GetWindowLong(Psht, GWL_EXSTYLE );
2256 if ( styles != 0 ) {
2257 SetWindowLong( Psht, GWL_EXSTYLE, (styles & ~WS_EX_CONTEXTHELP) );
2260 memset(Multi_options_g.std_pname, 0, MAX_GAMENAME_LEN+1);
2262 // change the default property sheet interface into something more useful
2265 // return a handle to this property sheet
2269 extern int Lighting_flag;
2271 BOOL std_create_standalone_window()
2273 Standalone_hwnd = std_init_property_sheet(NULL);
2275 // this is kind of a big-ass hack. But here's what it does. Property sheets only
2276 // initialize their individual pages the first time (and ONLY the first time) they
2277 // are selected. So before any of this happens, their control handles are bogus. So,
2278 // by calling PropSheet_SetCurSel for all the pages, WM_INITDIALOG is sent to all of
2279 // them, and their controls become valid. However, its kind of silly because each
2280 // page will blink into existence for a second. I can't see another way arount this
2283 for(idx=MAX_STANDALONE_PAGES-1;idx>=0;idx--){
2284 PropSheet_SetCurSel(Psht,(HPROPSHEETPAGE)&Pages[idx],idx);
2287 // main_window_inited = 1;
2289 // turn off lighting effects
2292 // turn off all sound and music
2293 Cmdline_freespace_no_sound = 1;
2294 Cmdline_freespace_no_music = 1;
2296 // reset all standalone gui items
2297 std_reset_standalone_gui();
2299 // initialize the debug outwindow
2307 // just like the osapi version for the nonstandalone mode of Freespace
2308 DWORD standalone_process(WORD lparam)
2312 if ( !std_create_standalone_window() )
2317 if(PropSheet_GetCurrentPageHwnd(Psht)==NULL){
2318 mprintf(("prop sheet is destroyed -- exiting\n"));
2319 DestroyWindow(Psht);
2322 std_deinit_standalone();
2326 if (WaitMessage()) {
2327 while(PeekMessage(&msg,0,0,0,PM_REMOVE)) {
2329 // if the dialog should be destroyed, then exit.
2330 if ( msg.message == WM_DESTROY ) {
2331 DestroyWindow(Psht);
2333 gameseq_post_event(GS_EVENT_QUIT_GAME);
2337 // see if the message is destined for the edit control, and what the message is.
2338 // intercept if a return
2339 if ( msg.hwnd == Godstuff_broadcast_text ) {
2342 virt_key = (int)msg.wParam;
2343 if ( (msg.message == WM_KEYDOWN) && (virt_key == VK_RETURN) ) {
2344 std_gs_send_godstuff_message();
2349 TranslateMessage(&msg);
2350 DispatchMessage(&msg);
2357 // called when freespace initialized
2358 void std_init_standalone()
2360 // start the main thread
2361 Standalone_thread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)standalone_process, NULL, 0, &Standalone_thread_id );
2363 os_init_registry_stuff(Osreg_company_name, Osreg_app_name,NULL);
2365 // set the close functions
2366 atexit(std_deinit_standalone);
2369 // called when freespace closes
2370 void std_deinit_standalone()
2372 if (Standalone_thread) {
2373 CloseHandle(Standalone_thread);
2374 Standalone_thread = NULL;