2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/Network/stand_gui.cpp $
16 * Revision 1.2 2002/06/09 04:41:24 relnev
17 * added copyright header
19 * Revision 1.1.1.1 2002/05/03 03:28:10 root
23 * 16 8/16/99 4:06p Dave
24 * Big honking checkin.
26 * 15 8/11/99 5:54p Dave
27 * Fixed collision problem. Fixed standalone ghost problem.
29 * 14 8/04/99 5:45p Dave
30 * Upped default standalone server framerate to 60.
32 * 13 5/22/99 5:35p Dave
33 * Debrief and chatbox screens. Fixed small hi-res HUD bug.
35 * 12 5/19/99 4:07p Dave
36 * Moved versioning code into a nice isolated common place. Fixed up
37 * updating code on the pxo screen. Fixed several stub problems.
39 * 11 4/25/99 7:43p Dave
40 * Misc small bug fixes. Made sun draw properly.
42 * 10 2/24/99 2:25p Dave
43 * Fixed up chatbox bugs. Made squad war reporting better. Fixed a respawn
44 * bug for dogfight more.
46 * 9 2/18/99 11:46a Neilk
47 * hires interface coord support
49 * 8 2/12/99 6:16p Dave
50 * Pre-mission Squad War code is 95% done.
52 * 7 11/19/98 4:19p Dave
53 * Put IPX sockets back in psnet. Consolidated all multiplayer config
56 * 6 11/17/98 11:12a Dave
57 * Removed player identification by address. Now assign explicit id #'s.
59 * 5 11/05/98 5:55p Dave
60 * Big pass at reducing #includes
62 * 4 10/09/98 2:57p Dave
63 * Starting splitting up OS stuff.
65 * 3 10/08/98 4:29p Dave
66 * Removed reference to osdefs.h
68 * 2 10/07/98 10:53a Dave
71 * 1 10/07/98 10:50a Dave
73 * 63 9/17/98 11:56a Allender
74 * allow use of return key in edit box
76 * 62 9/04/98 3:52p Dave
77 * Put in validated mission updating and application during stats
80 * 61 7/24/98 9:27a Dave
81 * Tidied up endgame sequencing by removing several old flags and
82 * standardizing _all_ endgame stuff with a single function call.
84 * 60 7/10/98 5:04p Dave
85 * Fix connection speed bug on standalone server.
87 * 59 6/18/98 4:46p Allender
88 * removed test code that I previously forgot to remove
90 * 58 6/18/98 3:52p Allender
91 * make close button actually close down property sheet
93 * 57 6/13/98 6:02p Hoffoss
94 * Externalized all new (or forgot to be added) strings to all the code.
96 * 56 6/13/98 3:19p Hoffoss
97 * NOX()ed out a bunch of strings that shouldn't be translated.
99 * 55 6/10/98 2:56p Dave
100 * Substantial changes to reduce bandwidth and latency problems.
102 * 54 5/24/98 3:45a Dave
103 * Minor object update fixes. Justify channel information on PXO. Add a
104 * bunch of configuration stuff for the standalone.
106 * 53 5/22/98 9:35p Dave
107 * Put in channel based support for PXO. Put in "shutdown" button for
108 * standalone. UI tweaks for TvT
110 * 52 5/21/98 9:45p Dave
111 * Lengthened tracker polling times. Put in initial support for PXO
112 * servers with channel filters. Fixed several small UI bugs.
114 * 51 5/18/98 9:15p Dave
115 * Put in network config file support.
117 * 50 5/15/98 5:16p Dave
118 * Fix a standalone resetting bug.Tweaked PXO interface. Display captaincy
119 * status for team vs. team. Put in asserts to check for invalid team vs.
122 * 49 5/15/98 3:36p John
123 * Fixed bug with new graphics window code and standalone server. Made
124 * hwndApp not be a global anymore.
126 * 48 5/10/98 7:06p Dave
127 * Fix endgame sequencing ESC key. Changed how host options warning popups
128 * are done. Fixed pause/message scrollback/options screen problems in mp.
129 * Make sure observer HUD doesn't try to lock weapons.
131 * 47 5/09/98 7:16p Dave
132 * Put in CD checking. Put in standalone host password. Made pilot into
135 * 46 5/08/98 7:09p Dave
136 * Lots of UI tweaking.
138 * 45 5/08/98 5:05p Dave
139 * Go to the join game screen when quitting multiplayer. Fixed mission
140 * text chat bugs. Put mission type symbols on the create game list.
141 * Started updating standalone gui controls.
143 * 44 5/04/98 1:44p Dave
144 * Fixed up a standalone resetting problem. Fixed multiplayer stats
145 * collection for clients. Make sure all multiplayer ui screens have the
146 * correct palette at all times.
148 * 43 5/02/98 5:38p Dave
149 * Put in new tracker API code. Put in ship information on mp team select
150 * screen. Make standalone server name permanent. Fixed standalone server
153 * 42 5/02/98 1:45a Dave
154 * Make standalone goal tree not flicker.
156 * 41 5/01/98 10:57a Jim
157 * from Dave: fixed mission goal problems
159 * 40 4/29/98 12:11a Dave
160 * Put in first rev of full API support for new master tracker.
162 * 39 4/28/98 5:11p Dave
163 * Fixed multi_quit_game() client side sequencing problem. Turn off
164 * afterburners when ending multiplayer mission. Begin integration of mt
165 * API from Kevin Bentley.
167 * 38 4/25/98 2:02p Dave
168 * Put in multiplayer context help screens. Reworked ingame join ship
169 * select screen. Fixed places where network timestamps get hosed.
171 * 37 4/06/98 6:37p Dave
172 * Put in max_observers netgame server option. Make sure host is always
173 * defaulted to alpha 1 or zeta 1. Changed create game so that MAX_PLAYERS
174 * can always join but need to be kicked before commit can happen. Put in
175 * support for server ending a game and notifying clients of a special
178 * 36 3/31/98 5:18p John
179 * Removed demo/save/restore. Made NDEBUG defined compile. Removed a
180 * bunch of debug stuff out of player file. Made model code be able to
181 * unload models and malloc out only however many models are needed.
184 * 35 3/24/98 5:00p Dave
185 * Fixed several ui bugs. Put in pre and post voice stream playback sound
186 * fx. Put in error specific popups for clients getting dropped from games
187 * through actions other than their own.
189 * 34 3/19/98 5:05p Dave
190 * Put in support for targeted multiplayer text and voice messaging (all,
191 * friendly, hostile, individual).
193 * 33 3/17/98 5:29p Dave
194 * Minor bug fixes in player select menu. Solidified mp joining process.
195 * Made furball mode support ingame joiners and dropped players correctly.
197 * 32 3/15/98 4:17p Dave
198 * Fixed oberver hud problems. Put in handy netplayer macros. Reduced size
199 * of network orientation matrices.
201 * 31 3/03/98 5:12p Dave
202 * 50% done with team vs. team interface issues. Added statskeeping to
203 * secondary weapon blasts. Numerous multiplayer ui bug fixes.
205 * 30 2/12/98 4:41p Dave
206 * Seperated multiplayer kick functionality into its own module. Ui
209 * 29 2/05/98 10:24a Hoffoss
210 * Changed "goal" text to "objective", which is the correct term nowadays.
212 * 28 1/31/98 4:32p Dave
213 * Put in new support for VMT player validation, game logging in, and game
214 * logging out. Need to finish stats transfer.
216 * 27 1/28/98 6:24p Dave
217 * Made standalone use ~8 megs less memory. Fixed multiplayer submenu
218 * sequencing problem.
220 * 26 1/24/98 3:39p Dave
221 * Fixed numerous multiplayer bugs (last frame quit problem, weapon bank
222 * changing, deny packets). Add several controls to standalone server.
224 * 25 1/20/98 2:23p Dave
225 * Removed optimized build warnings. 99% done with ingame join fixes.
227 * 24 1/17/98 2:46a Dave
228 * Reworked multiplayer join/accept process. Ingame join still needs to be
231 * 23 1/16/98 2:34p Dave
232 * Made pause screen work properly (multiplayer). Changed how chat packets
235 * 22 1/13/98 5:37p Dave
236 * Reworked a lot of standalone interface code. Put in single and
237 * multiplayer popups for death sequence. Solidified multiplayer kick
240 * 21 1/11/98 10:03p Allender
241 * removed <winsock.h> from headers which included it. Made psnet_socket
242 * type which is defined just as SOCKET type is.
244 * 20 1/05/98 5:07p Dave
245 * Fixed a chat packet bug. Fixed a few state save/restore bugs. Updated a
246 * few things for multiplayer server transfer.
248 * 19 12/10/97 4:46p Dave
249 * Added in more detailed support for multiplayer packet lag/loss. Fixed
250 * some multiplayer stuff. Added some controls to the standalone.
252 * 18 12/03/97 11:50p Dave
253 * Fixed a bunch of multiplayer bugs (standalone and non)
255 * 17 12/03/97 11:59a Dave
256 * Dependant merge checkin
258 * 16 12/02/97 10:05p Dave
259 * Began some large-scale multiplayer debugging work (mostly standalone)
261 * 15 11/15/97 2:37p Dave
262 * More multiplayer campaign support.
264 * 14 10/29/97 5:18p Dave
265 * More debugging of server transfer. Put in debrief/brief
266 * transition for multiplayer (w/standalone)
268 * 13 10/25/97 7:23p Dave
269 * Moved back to single set stats storing. Put in better respawning
272 * 12 10/24/97 6:19p Dave
273 * More standalone testing/fixing. Added reliable endgame sequencing.
274 * Added reliable ingame joining. Added reliable stats transfer (endgame).
275 * Added support for dropping players in debriefing. Removed a lot of old
278 * 11 10/21/97 5:21p Dave
279 * Fixed pregame mission load/file verify debacle. Added single vs.
280 * multiplayer stats system.
282 * 10 10/14/97 5:38p Dave
283 * Player respawns 99.9% done. Only need to check cases for server/host
286 * 9 10/03/97 4:57p Dave
287 * Added functions for new text controls. Added some more reset controls.
288 * Put in checks for all-players-gone.
290 * 8 9/17/97 9:09a Dave
291 * Observer mode works, put in standalone controls. Fixed up some stuff for
292 * ingame join broken by recent code checkins.
294 * 7 8/29/97 5:03p Dave
295 * Added a ton of new gui controls/features.
297 * 6 8/26/97 5:03p Dave
298 * Added bunch of informational controls. Standardized some functions for
299 * external use. Put in godview mode (conditionaled out though).
301 * 5 8/23/97 11:31a Dave
302 * Put in new gui calls. Added a bunch of display controls.
304 * 4 8/20/97 4:19p Dave
305 * Moved some functions around. Added the standalone state text box.
307 * 3 8/18/97 11:46a Dave
308 * Moved definition of STANDALONE_FRAME_CAP tp multi.h
310 * 2 8/11/97 4:52p Dave
311 * Spliced out standalone GUI stuff from OsApi and WinMain.cpp to its own
314 * 1 8/11/97 4:21p Dave
320 #include <windowsx.h>
321 #include <commctrl.h>
333 #include "lighting.h"
334 #include "linklist.h"
335 #include "freespace.h"
337 #include "stand_gui.h"
347 #include "freespaceresource.h"
349 #include "multimsgs.h"
350 #include "multiutil.h"
351 #include "missiongoals.h"
352 #include "systemvars.h"
354 #include "multi_kick.h"
355 #include "multi_pmsg.h"
357 #include "multi_endgame.h"
358 #include "gamesequence.h"
359 #include "osregistry.h"
363 HANDLE Standalone_thread;
364 DWORD Standalone_thread_id;
365 static HWND Standalone_hwnd = NULL;
367 // -----------------------------------------------------------------------------------------
368 // standalone global defs
370 #define MAX_STANDALONE_PAGES 5
372 #define STD_STATS_UPDATE_TIME 500 // ms between updating player stats on the visible controls
373 #define STD_NG_UPDATE_TIME 100 // ms between updating netgame information are controls
375 // coords for the "shutdown" button (client window coords)
376 static int Std_shutdown_coords[GR_NUM_RESOLUTIONS][2] = {
377 { 130, 450 }, // GR_640
378 { 130, 450 } // GR_640
381 // you should reference Page_handles and Pages with these defines from now on
382 #define CONNECT_PAGE 0
383 #define MULTIPLAYER_PAGE 1
384 #define PLAYER_INFO_PAGE 2
385 #define GODSTUFF_PAGE 3
388 // standalone gui property sheet stuff
390 static HWND Page_handles[MAX_STANDALONE_PAGES];
391 static PROPSHEETPAGE Pages[MAX_STANDALONE_PAGES];
392 static PROPSHEETHEADER Sheet;
394 // index into Page_handles[] representing the currently selected page
395 static int Active_standalone_page;
397 // timestamp for updating currently selected player stats on the player info page
398 int Standalone_stats_stamp;
400 // timestamp for updating the netgame information are text controls
401 int Standalone_ng_stamp;
403 // banned player callsigns
404 #define STANDALONE_MAX_BAN 50
405 char Standalone_ban_list[STANDALONE_MAX_BAN][CALLSIGN_LEN+1];
406 int Standalone_ban_count = 0;
408 // ----------------------------------------------------------------------------------------
409 // mission validation dialog
412 static HWND Multi_gen_dialog = NULL; // the dialog itself
414 // dialog proc for this dialog
415 BOOL CALLBACK std_gen_dialog_proc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
423 Multi_gen_dialog = NULL;
429 // create the validate dialog
430 void std_create_gen_dialog(char *title)
432 // if the dialog is already active, do nothing
433 if(Multi_gen_dialog != NULL){
437 // otherwise create the dialog
438 Multi_gen_dialog = CreateDialog(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_GEN), Psht, (DLGPROC)std_gen_dialog_proc);
439 if(Multi_gen_dialog != NULL){
440 SetWindowText(Multi_gen_dialog, title);
444 // kill the validate dialog();
445 void std_destroy_gen_dialog()
447 // if the dialog is not active, do nothing
448 if(Multi_gen_dialog == NULL){
453 DestroyWindow(Multi_gen_dialog);
454 Multi_gen_dialog = NULL;
457 // set the text in the filename of the validate dialog
458 // valid values for field_num == 0 .. 2
459 void std_gen_set_text(char *str, int field_num)
463 // if the dialog is not active
464 if((Multi_gen_dialog == NULL) || (str == NULL) || (field_num < 0) || (field_num > 2)){
468 // otherwise set the text
469 ctrl = GetDlgItem(Multi_gen_dialog, (int)MAKEINTRESOURCE(IDC_FIELD1));
472 ctrl = GetDlgItem(Multi_gen_dialog,(int)MAKEINTRESOURCE(IDC_FIELD1));
475 ctrl = GetDlgItem(Multi_gen_dialog,(int)MAKEINTRESOURCE(IDC_FIELD2));
478 ctrl = GetDlgItem(Multi_gen_dialog,(int)MAKEINTRESOURCE(IDC_FIELD3));
481 SetWindowText(ctrl, str);
484 // is the validate dialog active
485 int std_gen_is_active()
487 return Multi_gen_dialog != NULL;
490 // ----------------------------------------------------------------------------------------
491 // connection page/tab functions
493 static HWND Multi_std_name; // standalone name text edit control
494 HWND Multi_std_host_passwd; // host password text control
495 int Multi_std_namechange_force;
497 // convert the index of an item in the list box into an index into the net players array
498 int std_connect_lindex_to_npindex(int index);
500 // set the text box indicating how many players are connected, returning the determined count
501 int std_connect_set_connect_count()
508 // setup the text string
509 strcpy(str,XSTR("# Connections : ",911));
511 // determine how many players are actually connected
513 for(idx=0;idx<MAX_PLAYERS;idx++){
514 if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
519 // tack on the player count to the end of the string
520 sprintf(val,"%d",count);
523 // set the text itself
524 ctrl = GetDlgItem(Page_handles[CONNECT_PAGE],(int)MAKEINTRESOURCE(IDC_CON_COUNT));
525 SetWindowText(ctrl,str);
527 // return the num of players found
531 // set the connect status (connected or not) of the game host
532 void std_connect_set_host_connect_status()
537 // first try and find the host
539 for(idx=0;idx<MAX_PLAYERS;idx++){
540 if(MULTI_CONNECTED(Net_players[idx]) && MULTI_HOST(Net_players[idx])){
546 // get the control and set the status
547 ctrl = GetDlgItem(Page_handles[CONNECT_PAGE],(int)MAKEINTRESOURCE(IDC_HOST_IS));
549 SetWindowText(ctrl, XSTR("Host connected ? Yes",912));
551 SetWindowText(ctrl, XSTR("Host connected ? No",913));
555 // add an ip string to the connect page listbox
556 void std_connect_add_ip_string(char *string)
561 ctrl = GetDlgItem(Page_handles[CONNECT_PAGE], (int)MAKEINTRESOURCE(IDC_CONPING));
562 SendMessage(ctrl, LB_ADDSTRING, (WPARAM)0, (LPARAM)(LPCTSTR)string);
565 // remove an ip string from the connect page listbox
566 void std_connect_remove_ip_string(char *string)
571 // get the control handle
572 ctrl = GetDlgItem(Page_handles[CONNECT_PAGE], (int)MAKEINTRESOURCE(IDC_CONPING));
574 // NOTE the use of FINDSTRING and _not_ FINDSTRINGEXACT !!
575 // since we've appended the ping to the end of the string, we can only check the
576 // "prefix" which is the net_players name
577 loc = SendMessage(ctrl, LB_FINDSTRING, (WPARAM)-1, (LPARAM)(LPCTSTR)string);
580 SendMessage(ctrl, LB_DELETESTRING, (WPARAM)loc, (LPARAM)0);
584 // set an ip string on the connect page listbox
585 void std_connect_set_ip_string(char *lookup,char *string)
590 // get the control handle
591 ctrl = GetDlgItem(Page_handles[CONNECT_PAGE],(int)MAKEINTRESOURCE(IDC_CONPING));
593 // NOTE the use of FINDSTRING and _not_ FINDSTRINGEXACT !!
594 // since we've appended the ping to the end of the string, we can only check the
595 // "prefix" which is the net_players name
596 loc = SendMessage(ctrl,LB_FINDSTRING,(WPARAM)-1,(LPARAM)(LPCTSTR)lookup);
599 SendMessage(ctrl,LB_DELETESTRING,(WPARAM)loc,(LPARAM)0);
600 SendMessage(ctrl,LB_INSERTSTRING,(WPARAM)loc,(LPARAM)string);
604 void std_connect_kick_player()
609 // get the control handle
610 ctrl = GetDlgItem(Page_handles[CONNECT_PAGE],(int)MAKEINTRESOURCE(IDC_CONPING));
612 sel = SendMessage(ctrl,LB_GETCURSEL,(WPARAM)0,(LPARAM)0);
613 // attempt to get the player index
615 player_num = std_connect_lindex_to_npindex(sel);
617 // if we found him, then kick the bastard
618 if(player_num != -1){
619 multi_kick_player(player_num,0);
624 // update the ping for this particular player
625 void std_connect_update_ping(net_player *p)
627 char str[40],ping[10],sml_ping[10],lookup[50];
629 // as long as his ping is not -1, do an update
630 if(p->s_info.ping.ping_avg > -1){
631 // get the lookup string
632 psnet_addr_to_string(lookup,&p->p_info.addr);
634 // build the string to replace the ping with
638 // chop it off at pings greater than 1 second
639 if(p->s_info.ping.ping_avg > 1000){
640 strcat(str,XSTR("> 1 sec",914));
641 strcpy(sml_ping,XSTR("> 1 sec",914));
644 sprintf(ping,"%d",p->s_info.ping.ping_avg);
646 strcat(str,XSTR(" ms",915));
647 strcpy(sml_ping,ping); strcat(sml_ping,XSTR(" ms",915));
651 std_connect_set_ip_string(lookup,str);
655 // clear all the controls for this page
656 void std_connect_clear_controls()
660 // set various connect counts
661 std_connect_set_connect_count();
662 std_connect_set_host_connect_status();
664 // reset the list of players and pings
665 handle = GetDlgItem(Page_handles[CONNECT_PAGE],(int)MAKEINTRESOURCE(IDC_CONPING));
666 SendMessage(handle,LB_RESETCONTENT,(WPARAM)0,(LPARAM)0);
669 // set the game name for the standalone. passing NULL uses the default
670 void std_connect_set_gamename(char *name)
672 char buf[MAX_GAMENAME_LEN+1];
674 // use the default name for now
676 // if a permanent name exists, use that instead of the default
677 if(strlen(Multi_options_g.std_pname)){
678 strcpy(Netgame.name, Multi_options_g.std_pname);
680 strcpy(Netgame.name,XSTR("Standalone Server",916));
683 strcpy(Netgame.name,name);
686 // update the text control
687 strcpy(buf,Netgame.name);
688 Multi_std_namechange_force = 0;
689 SetWindowText(Multi_std_name,buf);
690 Multi_std_namechange_force = 1;
693 // the user has changed the text in the server name text box. handle this
694 void std_connect_handle_name_change()
696 char buf[MAX_GAMENAME_LEN+2];
697 int max_len = MAX_GAMENAME_LEN+2;
699 if(Multi_std_namechange_force){
700 memset(buf,0,MAX_GAMENAME_LEN+2);
701 memcpy(&buf[0],&max_len,sizeof(int));
704 SendMessage(Multi_std_name,EM_GETLINE,(WPARAM)0,(LPARAM)(LPCSTR)buf);
706 // just copy it over for now. we may want to process this more later on
707 strcpy(Netgame.name,buf);
709 // copy it to the permanent name
710 strcpy(Multi_options_g.std_pname, buf);
714 // the user has changed the text in the host password text box
715 void std_connect_handle_passwd_change()
717 char buf[STD_PASSWD_LEN+2];
718 int max_len = STD_PASSWD_LEN+2;
720 memset(buf,0,STD_PASSWD_LEN+2);
721 memcpy(&buf[0],&max_len,sizeof(int));
724 SendMessage(Multi_std_host_passwd,EM_GETLINE,(WPARAM)0,(LPARAM)(LPCSTR)buf);
726 // just copy it over for now. we may want to process this more later on
727 strcpy(Multi_options_g.std_passwd, buf);
730 // convert the index of an item in the list box into an index into the net players array
731 int std_connect_lindex_to_npindex(int index)
738 // get the control handle
739 ctrl = GetDlgItem(Page_handles[CONNECT_PAGE],(int)MAKEINTRESOURCE(IDC_CONPING));
741 // get the string contained at a given index
742 SendMessage(ctrl,LB_GETTEXT,(WPARAM)index,(LPARAM)(LPSTR)list_text);
744 // look through the net players array and compare address strings (yuck)
746 for(idx=0;idx<MAX_PLAYERS;idx++){
747 // only look at connected players
748 if(MULTI_CONNECTED(Net_players[idx])){
749 strcpy(addr_text,"");
750 psnet_addr_to_string(addr_text,&Net_players[idx].p_info.addr);
752 // if we found the match
753 if((strlen(addr_text) != 0) && (strstr(list_text,addr_text) != NULL)){
763 // message handler for the connect tab
764 BOOL CALLBACK connect_proc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)
767 // initialize the dialog
769 // setup the page handle array for this page
770 Page_handles[CONNECT_PAGE] = hwndDlg;
772 // create the standalone name text box and limit its text length
773 Multi_std_name = GetDlgItem(hwndDlg, (int)MAKEINTRESOURCE(IDC_STD_NAME));
774 SendMessage(Multi_std_name, EM_SETLIMITTEXT, (WPARAM)MAX_GAMENAME_LEN-1, (LPARAM)0);
775 Multi_std_namechange_force = 1;
777 // create the standalone host password input box
778 Multi_std_host_passwd = GetDlgItem(hwndDlg, (int)MAKEINTRESOURCE(IDC_STD_HOST_PASSWD));
779 SendMessage(Multi_std_host_passwd, EM_SETLIMITTEXT, (WPARAM)STD_PASSWD_LEN, (LPARAM)0);
780 memset(Multi_options_g.std_passwd, 0, STD_PASSWD_LEN+1);
784 // process a command of some kind (usually button presses)
786 switch(HIWORD(wParam)){
789 switch(LOWORD(wParam)){
790 // the reset standalone button
791 case IDC_RESET_MULTI :
792 // multi_standalone_quit_game();
793 multi_quit_game(PROMPT_NONE);
796 // kick the currently selected player
797 case IDC_KICK_BUTTON :
798 std_connect_kick_player();
801 // refresh file list (PXO)
802 case IDC_PXO_REFRESH:
803 if(MULTI_IS_TRACKER_GAME){
804 // delete mvalid.cfg if it exists
805 cf_delete(MULTI_VALID_MISSION_FILE, CF_TYPE_DATA);
808 multi_update_valid_missions();
813 // an edit control text has been changed
815 if((HWND)lParam == Multi_std_name){
816 // update the standalone name field in Netgame.name
817 std_connect_handle_name_change();
818 } else if((HWND)lParam == Multi_std_host_passwd){
819 // update the standalone host passwd
820 std_connect_handle_passwd_change();
826 // a notification message
828 // notification that this is the current selected page. set our own internal data vars
829 if(((LPNMHDR)lParam)->code == PSN_SETACTIVE){
830 Active_standalone_page = CONNECT_PAGE;
831 } else if ( (((LPNMHDR)lParam)->code == PSN_APPLY) || (((LPNMHDR)lParam)->code == PSN_RESET) ) {
832 PostMessage( Psht, WM_DESTROY, 0, 0 );
843 // ----------------------------------------------------------------------------------------
844 // multiplayer page/tab functions
847 static HWND Framecap_trackbar; // trackbar for capping framerate
848 static HWND Standalone_FPS; // text control for displaying framerate
849 static HWND Standalone_mission_name; // text control for showing the current mission name
850 static HWND Standalone_missiontime; // text control for showing current mission time
851 static HIMAGELIST Goal_bitmaps; // bitmaps array for the goal tree control
852 static HWND Standalone_goals; // goal tree control handle
853 static HTREEITEM Goal_items[3]; // primary, secondary, and bonus goal items
854 static HWND Std_ng_max_players; // max players display text control
855 static HWND Std_ng_max_observers; // max observers display text control
856 static HWND Std_ng_security; // netgame security display text control
857 static HWND Std_ng_respawns; // netgame # respawns display text control
859 #define GOALVIEW_X 5 // goal view control extents
860 #define GOALVIEW_Y 242 //
861 #define GOALVIEW_W 160 //
862 #define GOALVIEW_H 168 //
864 // handle the user sliding the framerate cap scrollbar around
865 void std_multi_handle_framecap_scroll(HWND ctrl);
867 // initialize the framerate cap slide control
868 void std_multi_init_framecap_slider(HWND hwndDlg);
870 // initialize all the controls for this page
871 void std_multi_init_multi_controls(HWND hwndDlg);
873 // return the handle to the item matching the given parameters
874 HTREEITEM std_multi_get_goal_item(char *goal_string,int type);
876 // set the mission time in seconds
877 void std_multi_set_standalone_missiontime(float mission_time)
881 fix m_time = fl2f(mission_time);
883 // format the time string and set the text
884 game_format_time(m_time,time_txt);
885 sprintf(txt," : %.1f", mission_time);
886 strcat(time_txt,txt);
887 SetWindowText(Standalone_missiontime,time_txt);
890 // set the mission name
891 void std_multi_set_standalone_mission_name(char *mission_name)
894 SetWindowText(Standalone_mission_name,mission_name);
897 // initialize the goal tree for this mission
898 void std_multi_setup_goal_tree()
901 TV_INSERTSTRUCT tree_insert;
902 char goal_name[NAME_LENGTH+1];
904 // clear out the tree control
905 TreeView_DeleteAllItems(Standalone_goals);
907 // add the primary goal tag
908 new_item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
909 new_item.pszText = goal_name;
910 strcpy(new_item.pszText,XSTR("Primary Objectives",917));
912 new_item.iSelectedImage = 0;
913 tree_insert.hParent = NULL;
914 tree_insert.hInsertAfter = TVI_FIRST;
915 tree_insert.item = new_item;
916 Goal_items[0] = TreeView_InsertItem(Standalone_goals,&tree_insert);
918 // add the secondary goal tag
919 new_item.pszText = goal_name;
920 strcpy(new_item.pszText,XSTR("Secondary Objectives",918));
922 new_item.iSelectedImage = 0;
923 tree_insert.hInsertAfter = TVI_LAST;
924 tree_insert.item = new_item;
925 Goal_items[1] = TreeView_InsertItem(Standalone_goals,&tree_insert);
927 // add the bonus goal tag
928 new_item.pszText = goal_name;
929 strcpy(new_item.pszText,XSTR("Bonus Objectives",919));
931 new_item.iSelectedImage = 0;
932 tree_insert.item = new_item;
933 Goal_items[2] = TreeView_InsertItem(Standalone_goals,&tree_insert);
936 // add all the goals from the current mission to the tree control
937 void std_multi_add_goals()
940 TV_INSERTSTRUCT tree_insert;
941 int idx,goal_flags,perm_goal_flags;
942 char goal_name[NAME_LENGTH+1];
944 // setup data common for every item
945 new_item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
946 tree_insert.hInsertAfter = TVI_LAST;
949 for(idx=0;idx<Num_goals;idx++){
950 // reset the goal flags
953 switch(Mission_goals[idx].type & GOAL_TYPE_MASK){
956 goal_flags |= (1<<1); // (image index == 1, primary goal)
957 perm_goal_flags |= (1<<1);
961 case SECONDARY_GOAL :
962 goal_flags |= (1<<2); // (image index == 1, secondary goal)
963 perm_goal_flags |= (1<<2);
968 goal_flags |= (1<<3); // (image index == 1, bonus goal)
969 perm_goal_flags |= (1<<3);
973 goal_flags |= (1<<0); // (image index == 3, no goal)
977 // first select whether to insert under primary, secondary, or bonus tree roots
978 tree_insert.hParent = Goal_items[Mission_goals[idx].type & GOAL_TYPE_MASK];
981 new_item.pszText = goal_name;
982 strcpy(new_item.pszText,Mission_goals[idx].name);
984 // set the correct image indices
985 new_item.iImage = (goal_flags & (1<<0)) ? 3 : 0;
986 new_item.iSelectedImage = (goal_flags & (1<<0)) ? 3 : 0;
989 tree_insert.item = new_item;
990 TreeView_InsertItem(Standalone_goals,&tree_insert);
993 // check to see if there are any of the three types of mission goals. If not, then
995 if(!(perm_goal_flags & (1<<1))){
996 // insert the "none" item
997 tree_insert.hParent = Goal_items[0];
998 new_item.pszText = goal_name;
999 strcpy(new_item.pszText,XSTR("none",920));
1000 new_item.iImage = 3;
1001 new_item.iSelectedImage = 3;
1002 tree_insert.item = new_item;
1003 TreeView_InsertItem(Standalone_goals,&tree_insert);
1005 if(!(perm_goal_flags & (1<<2))){
1006 // insert the "none" item
1007 tree_insert.hParent = Goal_items[1];
1008 new_item.pszText = goal_name;
1009 strcpy(new_item.pszText,XSTR("none",920));
1010 new_item.iImage = 3;
1011 new_item.iSelectedImage = 3;
1012 tree_insert.item = new_item;
1013 TreeView_InsertItem(Standalone_goals,&tree_insert);
1015 if(!(perm_goal_flags & (1<<3))){
1016 // insert the "none" item
1017 tree_insert.hParent = Goal_items[1];
1018 new_item.pszText = goal_name;
1019 strcpy(new_item.pszText,XSTR("none",920));
1020 new_item.iImage = 3;
1021 new_item.iSelectedImage = 3;
1022 tree_insert.item = new_item;
1023 TreeView_InsertItem(Standalone_goals,&tree_insert);
1026 // expand out all the tree roots so all goals are shown
1027 for(idx=0;idx<3;idx++){
1028 TreeView_Expand(Standalone_goals,Goal_items[idx],TVE_EXPAND);
1032 // update all the goals in the goal tree based upon the mission status
1033 void std_multi_update_goals()
1035 HTREEITEM update_item;
1036 TV_ITEM setting,lookup;
1037 int idx,should_update;
1039 setting.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
1041 // go through all the goals
1042 for(idx=0;idx<Num_goals;idx++){
1043 // get a handle to the tree item
1045 update_item = std_multi_get_goal_item(Mission_goals[idx].name,Mission_goals[idx].type & GOAL_TYPE_MASK);
1047 // continue if we didn't get a valid item
1048 if(update_item == NULL){
1052 // get the tree item itself (as it currently stands)
1053 lookup.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
1054 lookup.hItem = update_item;
1055 if(!TreeView_GetItem(Standalone_goals,&lookup)){
1060 // determine what image to set for each one (failed, satisfied, incomplete, etc)
1061 switch(Mission_goals[idx].satisfied){
1063 // determine if we should update the item
1064 if((lookup.iImage != 4) && (lookup.iSelectedImage != 4)){
1066 setting.iSelectedImage = 4;
1071 case GOAL_COMPLETE :
1072 // determine if we should update the item
1073 if((lookup.iImage != 2) && (lookup.iSelectedImage != 2)){
1075 setting.iSelectedImage = 2;
1081 case GOAL_INCOMPLETE :
1082 // determine if we should update the item
1083 if((lookup.iImage != 1) && (lookup.iSelectedImage != 1)){
1085 setting.iSelectedImage = 1;
1092 // set the actual image
1094 setting.hItem = update_item;
1095 TreeView_SetItem(Standalone_goals,&setting);
1100 // set the framerate text box for this page
1101 void std_multi_set_framerate(float f)
1105 // set the window text
1106 sprintf(fr,"%.1f",f);
1107 SetWindowText(Standalone_FPS,fr);
1110 // clear all the controls for this page
1111 void std_multi_clear_controls()
1113 // clear out the mission name text static
1114 SetWindowText(Standalone_mission_name,"");
1116 // clear out the framerate text box
1117 SetWindowText(Standalone_FPS,"");
1119 // clear out the misison time text box
1120 SetWindowText(Standalone_missiontime,"");
1122 // clear out the netgame max players text box
1123 SetWindowText(Std_ng_max_players,"");
1125 // clear out the netgame max observer text box
1126 SetWindowText(Std_ng_max_observers,"");
1128 // clear out the netgame security text box
1129 SetWindowText(Std_ng_security,"");
1131 // clear out the netgame respawns # text box
1132 SetWindowText(Std_ng_respawns,"");
1134 // clear the goal tree control
1135 std_multi_setup_goal_tree();
1138 // update the netgame information area controls with the current Netgame settings
1139 void std_multi_update_netgame_info_controls()
1145 // update the max players control
1146 sprintf(buf,"%d",Netgame.max_players);
1147 SetWindowText(Std_ng_max_players,buf);
1149 // update the max observers control
1150 sprintf(buf,"%d",Netgame.options.max_observers);
1151 SetWindowText(Std_ng_max_observers,buf);
1153 // update the netgame security control
1154 sprintf(buf,"%d",Netgame.security);
1155 SetWindowText(Std_ng_security,buf);
1157 // update the netgame respawns # control
1158 sprintf(buf,"%d",Netgame.respawn);
1159 SetWindowText(Std_ng_respawns,buf);
1162 // handle the user sliding the framerate cap scrollbar around
1163 void std_multi_handle_framecap_scroll(HWND ctrl)
1168 // determine where the slider now is
1169 pos = SendMessage(ctrl,TBM_GETPOS,(WPARAM)0,(LPARAM)0);
1171 // update the text display
1172 sprintf(pos_text,"%d",pos);
1173 SetWindowText(GetDlgItem(Page_handles[MULTIPLAYER_PAGE],(int)MAKEINTRESOURCE(IDC_FRAMECAP_STATIC)),pos_text);
1175 // set the framecap var
1176 Multi_options_g.std_framecap = pos;
1179 // initialize the framerate cap slide control
1180 void std_multi_init_framecap_slider(HWND hwndDlg)
1185 // create the trackbar object
1186 Framecap_trackbar = CreateWindowEx(0,TRACKBAR_CLASS,NULL,WS_CHILD | WS_VISIBLE,
1187 10,10,300,30,hwndDlg,NULL,GetModuleHandle(NULL),NULL);
1189 // set the range of the framerate cap
1190 wp = (WPARAM)(BOOL)TRUE;
1191 lp = (LPARAM)MAKELONG(1, 100);
1192 SendMessage(Framecap_trackbar,TBM_SETRANGE,wp,lp);
1194 // set the default framerate cap the be the standalone default
1195 wp = (WPARAM)(BOOL)TRUE;
1196 lp = (LPARAM)(LONG)30;
1197 SendMessage(Framecap_trackbar,TBM_SETPOS,wp,lp);
1199 // call this to update the standalone framecap on this first run
1200 std_multi_handle_framecap_scroll(Framecap_trackbar);
1203 // initialize all the controls for this page
1204 void std_multi_init_multi_controls(HWND hwndDlg)
1209 // create the framecap slider
1210 std_multi_init_framecap_slider(hwndDlg);
1212 // create the framerate display text box
1213 Standalone_FPS = GetDlgItem(hwndDlg,(int)MAKEINTRESOURCE(IDC_STANDALONE_FPS));
1215 // create the missiontime text box
1216 Standalone_missiontime = GetDlgItem(hwndDlg,(int)MAKEINTRESOURCE(IDC_STANDALONE_MTIME));
1218 // create the mission name text box
1219 Standalone_mission_name = GetDlgItem(hwndDlg,(int)MAKEINTRESOURCE(IDC_MISSION_NAME));
1221 // create the netgame max players text box
1222 Std_ng_max_players = GetDlgItem(hwndDlg,(int)MAKEINTRESOURCE(IDC_NG_MAXPLAYERS));
1224 // create the netgame max observers text box
1225 Std_ng_max_observers = GetDlgItem(hwndDlg,(int)MAKEINTRESOURCE(IDC_NG_MAXOBSERVERS));
1227 // create the netgame security text box
1228 Std_ng_security = GetDlgItem(hwndDlg,(int)MAKEINTRESOURCE(IDC_NG_SECURITY));
1230 // create the netgame respawns # text box
1231 Std_ng_respawns = GetDlgItem(hwndDlg,(int)MAKEINTRESOURCE(IDC_NG_RESPAWNS));
1233 // load the goal tree-view bitmaps
1234 Goal_bitmaps = ImageList_Create(16,16,ILC_COLOR4 | ILC_MASK,5,0);
1237 ref = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_GOAL_ORD));
1238 ImageList_AddMasked(Goal_bitmaps,ref,mask);
1240 ref = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_GOAL_INC));
1242 ImageList_AddMasked(Goal_bitmaps,ref,mask);
1244 ref = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_GOAL_COMP));
1246 ImageList_AddMasked(Goal_bitmaps,ref,mask);
1248 ref = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_GOAL_NONE));
1250 ImageList_AddMasked(Goal_bitmaps,ref,mask);
1252 ref = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_GOAL_FAIL));
1254 ImageList_AddMasked(Goal_bitmaps,ref,mask);
1256 // create the tree view control and associate its image list
1257 Standalone_goals = CreateWindowEx(0, WC_TREEVIEW, XSTR("Tree View",921),
1258 WS_VISIBLE | WS_CHILD | WS_BORDER | TVS_HASLINES,
1259 GOALVIEW_X,GOALVIEW_Y,GOALVIEW_W,GOALVIEW_H,
1260 hwndDlg, NULL, GetModuleHandle(NULL), NULL);
1261 TreeView_SetImageList(Standalone_goals,Goal_bitmaps,TVSIL_NORMAL);
1264 // return the handle to the item matching the given parameters
1265 HTREEITEM std_multi_get_goal_item(char *goal_string,int type)
1267 HTREEITEM ret,moveup;
1270 char goal_name_text[NAME_LENGTH+1];
1272 // look under the correct root item
1273 lookup.mask = TVIF_TEXT;
1274 lookup.pszText = goal_name_text;
1275 lookup.cchTextMax = NAME_LENGTH;
1276 strcpy(lookup.pszText,goal_string);
1278 // search through all the items
1281 moveup = TreeView_GetChild(Standalone_goals,Goal_items[type]);
1282 while(!done && moveup!=NULL){
1283 lookup.hItem = moveup;
1284 TreeView_GetItem(Standalone_goals,&lookup);
1285 if(strcmp(lookup.pszText,goal_string)==0){
1290 moveup = TreeView_GetNextItem(Standalone_goals,moveup,TVGN_NEXT);
1296 // message handler for the multiplayer tab
1297 BOOL CALLBACK multi_proc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)
1300 // initialize the page
1302 // set the page handle
1303 Page_handles[MULTIPLAYER_PAGE] = hwndDlg;
1305 // initialize all the controls
1306 std_multi_init_multi_controls(hwndDlg);
1310 // a scroll message from the framerate cap trackbar
1312 std_multi_handle_framecap_scroll((HWND)lParam);
1316 // notification that this page has been set as active
1318 // setup our own internal vars
1319 if(((LPNMHDR)lParam)->code == PSN_SETACTIVE){
1320 Active_standalone_page = MULTIPLAYER_PAGE;
1321 } else if ( (((LPNMHDR)lParam)->code == PSN_APPLY) || (((LPNMHDR)lParam)->code == PSN_RESET) ) {
1322 // PostMessage( Psht, WM_DESTROY, 0, 0 );
1323 gameseq_post_event(GS_EVENT_QUIT_GAME);
1335 // ---------------------------------------------------------------------------------------
1336 // player info page/tab functions
1339 #define MAX_PLAYER_STAT_FIELDS 11 // the # of stats fields for a given set
1340 static HWND Player_name_list; // the listbox control with player callsigns in it
1341 static HWND Player_ship_type; // the current player's ship type
1342 static HWND Player_ping_time; // the current player's ping time
1343 static HWND Player_stats[MAX_PLAYER_STAT_FIELDS]; // text boxes for player alltime statistics info
1344 static HWND Player_mstats[MAX_PLAYER_STAT_FIELDS]; // text boxes for player mission statistics info
1346 // sprintf and set window text to the passed int
1347 #define STD_ADDSTRING(hwnd,val) { sprintf(txt,"%d",(int)val); SetWindowText(hwnd,txt); }
1349 // intialize all the controls in the player info tab
1350 void std_pinfo_init_player_info_controls(HWND hwndDlg);
1352 // returns true or false depending on whether the passed netplayer is the currently selected guy
1353 int std_pinfo_player_is_active(net_player *p);
1355 // start displaying info for the passed player on this page
1356 void std_pinfo_display_player_info(net_player *p)
1360 // set his ship type
1361 SetWindowText(Player_ship_type,Ship_info[p->p_info.ship_class].name);
1363 // display his ping time
1364 std_pinfo_update_ping(p);
1366 // his alltime stats
1367 scoring_struct *ptr = &p->player->stats;
1368 STD_ADDSTRING(Player_stats[0],ptr->p_shots_fired);
1369 STD_ADDSTRING(Player_stats[1],ptr->p_shots_hit);
1370 STD_ADDSTRING(Player_stats[2],ptr->p_bonehead_hits);
1371 STD_ADDSTRING(Player_stats[3],
1372 (int)((float)100.0*((float)ptr->p_shots_hit/(float)ptr->p_shots_fired)));
1373 STD_ADDSTRING(Player_stats[4],
1374 (int)((float)100.0*((float)ptr->p_bonehead_hits/(float)ptr->p_shots_fired)));
1375 STD_ADDSTRING(Player_stats[5],ptr->s_shots_fired);
1376 STD_ADDSTRING(Player_stats[6],ptr->s_shots_hit);
1377 STD_ADDSTRING(Player_stats[7],ptr->s_bonehead_hits);
1378 STD_ADDSTRING(Player_stats[8],
1379 (int)((float)100.0*((float)ptr->s_shots_hit/(float)ptr->s_shots_fired)));
1380 STD_ADDSTRING(Player_stats[9],
1381 (int)((float)100.0*((float)ptr->s_bonehead_hits/(float)ptr->s_shots_fired)));
1382 STD_ADDSTRING(Player_stats[10],ptr->assists);
1384 // his stats for the current mission
1385 STD_ADDSTRING(Player_mstats[0],ptr->mp_shots_fired);
1386 STD_ADDSTRING(Player_mstats[1],ptr->mp_shots_hit);
1387 STD_ADDSTRING(Player_mstats[2],ptr->mp_bonehead_hits);
1388 STD_ADDSTRING(Player_mstats[3],
1389 (int)((float)100.0*((float)ptr->mp_shots_hit/(float)ptr->mp_shots_fired)));
1390 STD_ADDSTRING(Player_mstats[4],
1391 (int)((float)100.0*((float)ptr->mp_bonehead_hits/(float)ptr->mp_shots_fired)));
1392 STD_ADDSTRING(Player_mstats[5],ptr->ms_shots_fired);
1393 STD_ADDSTRING(Player_mstats[6],ptr->ms_shots_hit);
1394 STD_ADDSTRING(Player_mstats[7],ptr->ms_bonehead_hits);
1395 STD_ADDSTRING(Player_mstats[8],
1396 (int)((float)100.0*((float)ptr->ms_shots_hit/(float)ptr->ms_shots_fired)));
1397 STD_ADDSTRING(Player_mstats[9],
1398 (int)((float)100.0*((float)ptr->ms_bonehead_hits/(float)ptr->ms_shots_fired)));
1399 STD_ADDSTRING(Player_mstats[10],ptr->m_assists);
1402 // check to see if this player is the one being displayed, and if so, then update the display info
1403 // return 1 if the player was updated
1404 int std_pinfo_maybe_update_player_info(net_player *p)
1406 // only update if this is the currently active player
1407 if(std_pinfo_player_is_active(p)){
1408 std_pinfo_display_player_info(p);
1414 // add a player to the list on the player info page
1415 void std_pinfo_add_player_list_item(net_player *p)
1418 SendMessage(Player_name_list,CB_ADDSTRING,(WPARAM)0,(LPARAM)(LPCTSTR)p->player->callsign);
1420 // if this is the first item on the list, then select it and display it
1421 if(SendMessage(Player_name_list,CB_GETCOUNT,(WPARAM)0,(LPARAM)0) == 1){
1423 SendMessage(Player_name_list,CB_SETCURSEL,(WPARAM)0,(LPARAM)0);
1425 // display this players info
1426 std_pinfo_display_player_info(p);
1430 // remove a player from the list on the player info page
1431 void std_pinfo_remove_player_list_item(net_player *p)
1435 // lookup thie player
1436 loc = SendMessage(Player_name_list,CB_FINDSTRINGEXACT,(WPARAM)-1,(LPARAM)(LPCTSTR)p->player->callsign);
1438 // if we found the entry, then delete it
1440 SendMessage(Player_name_list,CB_DELETESTRING,(WPARAM)loc,(LPARAM)0);
1444 // update the ping display for this player
1445 void std_pinfo_update_ping(net_player *p)
1449 // chop it off at pings greater than 1 second
1450 if(p->s_info.ping.ping_avg > 1000){
1451 strcpy(sml_ping,XSTR("> 1 sec",914));
1453 // use the ping itself
1455 sprintf(sml_ping,"%d",p->s_info.ping.ping_avg);
1456 strcat(sml_ping,XSTR(" ms",915));
1459 SetWindowText(Player_ping_time,sml_ping);
1462 // clear the player info page controls
1463 void std_pinfo_clear_controls()
1467 // clear the player selection list
1468 SendMessage(Player_name_list,CB_RESETCONTENT,(WPARAM)0,(LPARAM)0);
1470 // clear out misc items
1471 SetWindowText(Player_ship_type,"");
1472 SetWindowText(Player_ping_time,"");
1474 // clear out the player stats
1475 for(idx=0;idx<MAX_PLAYER_STAT_FIELDS;idx++){
1476 SetWindowText(Player_stats[idx],"");
1477 SetWindowText(Player_mstats[idx],"");
1481 // intialize all the controls in the player info tab
1482 void std_pinfo_init_player_info_controls(HWND hwndDlg)
1484 // create the player callsign listbox
1485 Player_name_list = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_PLAYER_LIST));
1487 // create the player ship type text box
1488 Player_ship_type = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_PSHIP_TYPE));
1490 // create the player ping time text box
1491 Player_ping_time = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_PING_TIME));
1493 // initialize the various and sundry statistics text controls (alltime)
1494 Player_stats[0] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_PSHOTS));
1495 Player_stats[1] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_PHITS));
1496 Player_stats[2] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_PBHHITS));
1497 Player_stats[3] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_PPCT));
1498 Player_stats[4] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_PBHPCT));
1499 Player_stats[5] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_SSHOTS));
1500 Player_stats[6] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_SECHITS));
1501 Player_stats[7] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_SBHHITS));
1502 Player_stats[8] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_SPCT));
1503 Player_stats[9] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_SBHPCT));
1504 Player_stats[10] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_ASSISTS));
1506 // initialize the various and sundry statistics text controls (this mission)
1507 Player_mstats[0] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MPSHOTS));
1508 Player_mstats[1] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MPHITS));
1509 Player_mstats[2] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MPBHHITS));
1510 Player_mstats[3] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MPPCT));
1511 Player_mstats[4] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MPBHPCT));
1512 Player_mstats[5] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MSSHOTS));
1513 Player_mstats[6] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MSECHITS));
1514 Player_mstats[7] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MSBHHITS));
1515 Player_mstats[8] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MSPCT));
1516 Player_mstats[9] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MSBHPCT));
1517 Player_mstats[10] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MASSISTS));
1520 // returns true or false depending on whether the passed netplayer is the currently selected guy
1521 int std_pinfo_player_is_active(net_player *p)
1526 // get the index of the currently selected item
1527 sel = SendMessage(Player_name_list,CB_GETCURSEL,(WPARAM)0,(LPARAM)0);
1529 // if we didn't find the item, return a 0 length string
1534 // otherwise, get the callsign of the given player
1535 SendMessage(Player_name_list,CB_GETLBTEXT,(WPARAM)sel,(LPARAM)player);
1537 // if there is a valid player selected and he's the guy we want
1538 return ((strlen(player) != 0) && (strcmp(p->player->callsign,player) == 0)) ? 1 : 0;
1541 // message handler for the player info tab
1542 BOOL CALLBACK player_info_proc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)
1548 // initialize the dialog
1550 // set the page handle
1551 Page_handles[PLAYER_INFO_PAGE] = hwndDlg;
1553 // intialize all the control
1554 std_pinfo_init_player_info_controls(hwndDlg);
1558 // a command message of some kind
1560 switch(HIWORD(wParam)){
1561 // a listbox selection change message
1562 case CBN_SELCHANGE :
1563 // get the newly selected item
1564 val = SendMessage(Player_name_list,CB_GETCURSEL,(WPARAM)0,(LPARAM)0);
1567 if(SendMessage(Player_name_list,CB_GETLBTEXT,(WPARAM)val,(LPARAM)callsign) != CB_ERR){
1568 // lookup the player
1569 player_num = multi_find_player_by_callsign(callsign);
1571 // if we found him then display his info
1572 if(player_num != -1){
1573 std_pinfo_display_player_info(&Net_players[player_num]);
1581 // a notification message
1583 // set our page to be the active one
1584 if(((LPNMHDR)lParam)->code == PSN_SETACTIVE){
1585 Active_standalone_page = PLAYER_INFO_PAGE;
1586 } else if ( (((LPNMHDR)lParam)->code == PSN_APPLY) || (((LPNMHDR)lParam)->code == PSN_RESET) ) {
1587 PostMessage( Psht, WM_DESTROY, 0, 0 );
1599 // ---------------------------------------------------------------------------------------
1600 // player god stuff page/tab functions
1603 #define GODSTUFF_MAX_ITEMS 19 // how many items we can fit on the chatbox at one time
1605 static HWND God_player_list; // the listbox of player callsigns
1606 static HWND Godstuff_fps; // the framerate text box
1607 static HWND Godstuff_broadcast_text; // the text input box for sending messages to players
1608 static HWND Godstuff_broadcast_button; // the button to send the text messages
1609 static HWND Godstuff_player_messages; // handle to the list box containing player chatter
1611 // initialize all the controls in the godstuff tab
1612 void std_gs_init_godstuff_controls(HWND hwndDlg);
1614 // add a player to the listbox on the godstuff page
1615 void std_gs_add_god_player(net_player *p)
1618 SendMessage(God_player_list,CB_ADDSTRING,(WPARAM)0,(LPARAM)(LPCTSTR)p->player->callsign);
1620 // if this is the first item on the list, then select it
1621 if(SendMessage(God_player_list,CB_GETCOUNT,(WPARAM)0,(LPARAM)0) == 1){
1623 SendMessage(God_player_list,CB_SETCURSEL,(WPARAM)0,(LPARAM)0);
1627 // remove a player from the listbox on the godstuff page
1628 void std_gs_remove_god_player(net_player *p)
1632 // lookup the player
1633 loc = SendMessage(God_player_list,CB_FINDSTRINGEXACT,(WPARAM)-1,(LPARAM)(LPCTSTR)p->player->callsign);
1635 // if we found him, them delete the item
1637 SendMessage(God_player_list,CB_DELETESTRING,(WPARAM)loc,(LPARAM)0);
1641 // send a message as if the standalone were a player
1642 void std_gs_send_godstuff_message()
1646 // get the text in the edit control
1649 SendMessage(Godstuff_broadcast_text,EM_GETLINE,(WPARAM)0,(LPARAM)&txt[0]);
1651 // if the string is not zero length
1652 if(strlen(txt) > 0){
1653 // send a game chat packet
1654 send_game_chat_packet(Net_player, txt, MULTI_MSG_ALL,NULL);
1656 // add the text to our own control
1657 std_add_chat_text(txt, MY_NET_PLAYER_NUM,1);
1659 // clear the text control
1660 SetWindowText(Godstuff_broadcast_text, "");
1664 // set the framerate text box for this page
1665 void std_gs_set_framerate(float f)
1669 // set the window text
1670 sprintf(fr,"%.1f",f);
1671 SetWindowText(Godstuff_fps,fr);
1674 // clear the godstuff page controlsv
1675 void std_gs_clear_controls()
1677 // clear the framerate area
1678 SetWindowText(Godstuff_fps, "0");
1680 // clear the text area
1681 SetWindowText(Godstuff_broadcast_text,"");
1683 // reset the combo box
1684 SendMessage(God_player_list, CB_RESETCONTENT, (WPARAM)0, (LPARAM)0);
1686 // clear the player chatter listbox
1687 SendMessage(Godstuff_player_messages, LB_RESETCONTENT, (WPARAM)0, (LPARAM)0);
1690 // initialize all the controls in the godstuff tab
1691 void std_gs_init_godstuff_controls(HWND hwndDlg)
1693 // initialize the player listbox control
1694 God_player_list = GetDlgItem(Page_handles[GODSTUFF_PAGE], (int)MAKEINTRESOURCE(IDC_PLAYER_GOD_LIST));
1696 // initialize the framerate text box
1697 Godstuff_fps = GetDlgItem(Page_handles[GODSTUFF_PAGE], (int)MAKEINTRESOURCE(IDC_GODSTUFF_FPS));
1699 // initialize the messaging edit control
1700 Godstuff_broadcast_text = GetDlgItem(Page_handles[GODSTUFF_PAGE], (int)MAKEINTRESOURCE(IDC_GODSTUFF_BROADCAST));
1701 SendMessage(Godstuff_broadcast_text, EM_SETLIMITTEXT, (WPARAM)CHATBOX_MAX_LEN, (LPARAM)0);
1702 SendMessage(Godstuff_broadcast_text, EM_FMTLINES, (WPARAM)TRUE, (LPARAM)0);
1704 // create the player chatter list box
1705 Godstuff_player_messages = GetDlgItem(Page_handles[GODSTUFF_PAGE], (int)MAKEINTRESOURCE(IDC_GOD_CHAT));
1707 // initialize the message broadcast button
1708 Godstuff_broadcast_button = GetDlgItem(Page_handles[GODSTUFF_PAGE], (int)MAKEINTRESOURCE(IDC_GODSTUFF_SENDMESS));
1709 // hide the button -- we can now process return key
1710 ShowWindow(Godstuff_broadcast_button, SW_HIDE);
1714 // message handler for the godstuff tab
1715 BOOL CALLBACK godstuff_proc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
1718 // initialize the dialog
1720 // setup the page handle
1721 Page_handles[GODSTUFF_PAGE] = hwndDlg;
1723 // initialize the controls for this page
1724 std_gs_init_godstuff_controls(hwndDlg);
1728 // a notification message
1730 // set this page to be the currently active one
1731 if(((LPNMHDR)lParam)->code == PSN_SETACTIVE){
1732 Active_standalone_page = GODSTUFF_PAGE;
1733 } else if ( (((LPNMHDR)lParam)->code == PSN_APPLY) || (((LPNMHDR)lParam)->code == PSN_RESET) ) {
1734 PostMessage( Psht, WM_DESTROY, 0, 0 );
1739 // a command message of some kind
1741 switch(HIWORD(wParam)){
1744 switch(LOWORD(wParam)){
1745 // send the message to the player
1746 case IDC_GODSTUFF_SENDMESS :
1747 std_gs_send_godstuff_message();
1763 // ---------------------------------------------------------------------------------------
1764 // debug page/tab functions
1767 static HWND Standalone_state_string; // the text control box
1769 // initialize the controls for the debug page
1770 void std_debug_init_debug_controls(HWND hwndDlg);
1772 // set the text on the standalones state indicator box
1773 void std_debug_set_standalone_state_string(char *str)
1776 SetWindowText(Standalone_state_string,str);
1779 // clear the debug page controls
1780 void std_debug_clear_controls()
1782 // set the current debug state
1783 std_debug_set_standalone_state_string("");
1786 // initialize the controls for the debug page
1787 void std_debug_init_debug_controls(HWND hwndDlg)
1789 // create the state string text box
1790 Standalone_state_string = GetDlgItem(hwndDlg,(int)MAKEINTRESOURCE(IDC_STANDALONE_STATE));
1792 // standalone state indicator
1793 SetWindowText(Standalone_state_string,"");
1796 // message handler for the godstuff tab
1797 BOOL CALLBACK debug_proc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)
1800 // initialize the dialog
1802 // setup the page handle
1803 Page_handles[DEBUG_PAGE] = hwndDlg;
1805 // intialize the controls for this page
1806 std_debug_init_debug_controls(hwndDlg);
1810 // a notification message
1812 // set the currently active page to this one
1813 if(((LPNMHDR)lParam)->code == PSN_SETACTIVE){
1814 Active_standalone_page = DEBUG_PAGE;
1815 } else if ( (((LPNMHDR)lParam)->code == PSN_APPLY) || (((LPNMHDR)lParam)->code == PSN_RESET) ) {
1816 PostMessage( Psht, WM_DESTROY, 0, 0 );
1828 // ---------------------------------------------------------------------------------------
1829 // general functions
1832 // add a player and take care of updating all gui/data details
1833 void std_add_player(net_player *p)
1837 // get his ip string and add it to the list
1838 psnet_addr_to_string(ip_string,&p->p_info.addr);
1839 std_connect_add_ip_string(ip_string);
1841 // add to the player info player list box, and update his info
1842 std_pinfo_add_player_list_item(p);
1843 std_pinfo_maybe_update_player_info(p);
1845 // add to the god stuff player list box
1846 std_gs_add_god_player(p);
1848 // check to see if this guy is the host.
1849 std_connect_set_host_connect_status();
1851 // set the connection count
1852 std_connect_set_connect_count();
1855 // remove a player and take care of updateing all gui/data details
1856 int std_remove_player(net_player *p)
1861 // determine his ip string and remove it from the list
1862 psnet_addr_to_string(ip_string,&p->p_info.addr);
1863 std_connect_remove_ip_string(ip_string);
1865 // remove from the player info player list box
1866 std_pinfo_remove_player_list_item(p);
1868 // remove from the godstuff list box
1869 std_gs_remove_god_player(p);
1871 // update the host connect count
1872 std_connect_set_host_connect_status();
1874 // update the currently connected players
1875 count = std_connect_set_connect_count();
1878 // multi_standalone_quit_game();
1879 multi_quit_game(PROMPT_NONE);
1886 // set any relevant controls which display the framerate of the standalone
1887 void std_set_standalone_fps(float fps)
1889 // set the framerate in the multiplayer dialog
1890 std_multi_set_framerate(fps);
1892 // set the framerate in the godstuff dialog
1893 std_gs_set_framerate(fps);
1896 // update any relveant controls which display the ping for the given player
1897 void std_update_player_ping(net_player *p)
1899 // update the ping on the connect page
1900 std_connect_update_ping(p);
1902 // update the ping on the player info page
1903 std_pinfo_update_ping(p);
1906 // reset everything in the standalone gui (all the controls)
1907 void std_reset_standalone_gui()
1909 // clear the connect page controls
1910 std_connect_clear_controls();
1912 // clear the multi page controls
1913 std_multi_clear_controls();
1915 // clear the player info page controls
1916 std_pinfo_clear_controls();
1918 // clear the godstuff page controls
1919 std_gs_clear_controls();
1921 // clear the debug page controls
1922 std_debug_clear_controls();
1924 // set all framerate displays to 0
1925 std_set_standalone_fps((float)0);
1927 // set the mission time
1928 std_multi_set_standalone_missiontime((float)0);
1930 // reset the stats update timestamp
1931 Standalone_stats_stamp = -1;
1933 // reset the netgame info timestamp
1934 Standalone_ng_stamp = -1;
1937 // do any gui related issues on the standalone (like periodically updating player stats, etc...)
1938 void std_do_gui_frame()
1942 // check to see if the timestamp for updating player selected stats has popped
1943 if((Standalone_stats_stamp == -1) || timestamp_elapsed(Standalone_stats_stamp)){
1944 // reset the timestamp
1945 Standalone_stats_stamp = timestamp(STD_STATS_UPDATE_TIME);
1947 // update any player currently selected
1948 // there's probably a nicer way to do this, but...
1949 for(idx=0;idx<MAX_PLAYERS;idx++){
1950 if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
1951 if(std_pinfo_maybe_update_player_info(&Net_players[idx])){
1958 // check to see if the timestamp for updating the netgame information controls has popped
1959 if((Standalone_ng_stamp == -1) || timestamp_elapsed(Standalone_ng_stamp)){
1960 // reset the timestamp
1961 Standalone_ng_stamp = timestamp(STD_NG_UPDATE_TIME);
1963 // update the controls
1964 std_multi_update_netgame_info_controls();
1968 // notify the user that the standalone has failed to login to the tracker on startup
1969 void std_notify_tracker_login_fail()
1971 MessageBox(Psht,XSTR("The standalone server has failed to log in to Parallax Online!",922),XSTR("VMT Warning!",923),MB_OK);
1974 // attempt to log the standalone into the tracker
1975 void std_tracker_login()
1979 // reset all stand gui timestamps
1980 void std_reset_timestamps()
1982 // reset the stats update stamp
1983 Standalone_stats_stamp = timestamp(STD_STATS_UPDATE_TIME);
1985 // reset the netgame controls update timestamp
1986 Standalone_ng_stamp = timestamp(STD_NG_UPDATE_TIME);
1989 // add a line of text chat to the standalone
1990 void std_add_chat_text(char *text,int player_index,int add_id)
1992 int num_items,ret_val;
1996 if(player_index == -1){
2000 // format the chat text nicely
2002 if(MULTI_STANDALONE(Net_players[player_index])){
2003 sprintf(format,XSTR("<SERVER> %s",924),text);
2005 sprintf(format,"%s: %s",Net_players[player_index].player->callsign,text);
2008 strcpy(format,text);
2011 // insert the text string into the godstuff chat box and scroll it down to the bottom
2012 SendMessage(Godstuff_player_messages,LB_INSERTSTRING,(WPARAM)-1,(LPARAM)format);
2013 num_items = SendMessage(Godstuff_player_messages,LB_GETCOUNT,(WPARAM)0,(LPARAM)0);
2015 ret_val = SendMessage(Godstuff_player_messages,LB_SETTOPINDEX,(WPARAM)num_items - GODSTUFF_MAX_ITEMS,(LPARAM)0);
2019 // if the standalone is host password protected
2020 int std_is_host_passwd()
2022 return (strlen(Multi_options_g.std_passwd) > 0) ? 1 : 0;
2025 // change the default property sheet interface into something more useful
2026 void std_mutate_sheet()
2028 HWND ok_button = NULL;
2029 HWND cancel_button = NULL;
2030 HWND apply_button = NULL;
2031 HWND help_button = NULL;
2034 // get the buttons on the property sheet itself
2035 HWND child = GetWindow(Psht,GW_CHILD);
2036 while(child != NULL){
2037 // get the text of the window
2038 memset(lookup,0,512);
2039 GetWindowText(child,lookup,511);
2041 // if its the OK button
2042 if(!stricmp(lookup,XSTR("ok",925))){
2046 // if its the cancel button
2047 if(!stricmp(lookup,XSTR("cancel",926))){
2048 cancel_button = child;
2051 // if its the apply button
2052 if(!stricmp(lookup,XSTR("&apply",927))){
2053 apply_button = child;
2056 // if its the help button
2057 if(!stricmp(lookup,XSTR("help",928))){
2058 help_button = child;
2061 child = GetWindow(child,GW_HWNDNEXT);
2065 if(apply_button != NULL){
2066 DestroyWindow(apply_button);
2069 // rename the shutdown button and move it over a bit
2070 if(ok_button != NULL){
2072 SetWindowText(ok_button,XSTR("Shutdown",929));
2075 SetWindowPos(ok_button,
2077 Std_shutdown_coords[gr_screen.res][0],
2078 Std_shutdown_coords[gr_screen.res][1],
2080 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOZORDER
2085 if(cancel_button != NULL){
2086 DestroyWindow(cancel_button);
2090 if(help_button != NULL){
2091 DestroyWindow(help_button);
2094 // now we want to mess with the titlebar controls
2097 // if the given callsign is banned from the server
2098 int std_player_is_banned(char *name)
2102 // go through the ban list
2103 for(idx=0;idx<Standalone_ban_count;idx++){
2104 if(!stricmp(name,Standalone_ban_list[idx])){
2113 // add a callsign to the ban list
2114 void std_add_ban(char *name)
2116 // if we've reached the max bans
2117 if(Standalone_ban_count >= STANDALONE_MAX_BAN){
2122 memset(Standalone_ban_list[Standalone_ban_count],0,CALLSIGN_LEN+1);
2123 strcpy(Standalone_ban_list[Standalone_ban_count++],name);
2127 // -------------------------------------------------------------------------------
2128 // property sheet/page creation and handling
2131 void std_init_property_pages()
2136 p = &Pages[CONNECT_PAGE];
2137 p->dwSize = sizeof(PROPSHEETPAGE);
2138 p->dwFlags = PSP_DEFAULT;
2139 p->hInstance = GetModuleHandle(NULL);
2140 p->pszTemplate = MAKEINTRESOURCE(IDD_CONNECT);
2142 p->pfnDlgProc = (DLGPROC)connect_proc;
2143 p->pszTitle = XSTR("Connections",930);
2145 p->pfnCallback = NULL;
2148 p = &Pages[MULTIPLAYER_PAGE];
2149 p->dwSize = sizeof(PROPSHEETPAGE);
2150 p->dwFlags = PSP_DEFAULT;
2151 p->hInstance = GetModuleHandle(NULL);
2152 p->pszTemplate = MAKEINTRESOURCE(IDD_MULTI);
2154 p->pfnDlgProc = (DLGPROC)multi_proc;
2155 p->pszTitle = XSTR("Multi-Player",931);
2157 p->pfnCallback = NULL;
2160 p = &Pages[PLAYER_INFO_PAGE];
2161 p->dwSize = sizeof(PROPSHEETPAGE);
2162 p->dwFlags = PSP_DEFAULT;
2163 p->hInstance = GetModuleHandle(NULL);
2164 p->pszTemplate = MAKEINTRESOURCE(IDD_PLAYER_DIALOG);
2166 p->pfnDlgProc = (DLGPROC)player_info_proc;
2167 p->pszTitle = XSTR("Player info",932);
2169 p->pfnCallback = NULL;
2172 p = &Pages[GODSTUFF_PAGE];
2173 p->dwSize = sizeof(PROPSHEETPAGE);
2174 p->dwFlags = PSP_DEFAULT;
2175 p->hInstance = GetModuleHandle(NULL);
2176 p->pszTemplate = MAKEINTRESOURCE(IDD_GODSTUFF);
2178 p->pfnDlgProc = (DLGPROC)godstuff_proc;
2179 p->pszTitle = XSTR("God Stuff",933);
2181 p->pfnCallback = NULL;
2184 p = &Pages[DEBUG_PAGE];
2185 p->dwSize = sizeof(PROPSHEETPAGE);
2186 p->dwFlags = PSP_DEFAULT;
2187 p->hInstance = GetModuleHandle(NULL);
2188 p->pszTemplate = MAKEINTRESOURCE(IDD_DEBUG_DIALOG);
2190 p->pfnDlgProc = (DLGPROC)debug_proc;
2191 p->pszTitle = XSTR("Debug",934);
2193 p->pfnCallback = NULL;
2196 // build a title string
2197 void std_build_title_string(char *str)
2203 // build the version #
2204 memset(part1, 0, 256);
2205 memset(cat, 0, 256);
2206 memset(temp, 0, 256);
2208 sprintf(part1, "%s %d.", XSTR("Freespace Standalone",935), FS_VERSION_MAJOR);
2209 if(FS_VERSION_MINOR < 10){
2211 strcat(cat, itoa(FS_VERSION_MINOR, temp, 10));
2213 sprintf(cat, "%d", FS_VERSION_MINOR);
2217 if(FS_VERSION_BUILD < 10){
2219 strcat(cat, itoa(FS_VERSION_BUILD, temp, 10));
2221 sprintf(cat, "%d", FS_VERSION_BUILD);
2228 #ifdef STANDALONE_ONLY_BUILD
2229 sprintf(cat, " %s %d", "Release", STANDALONE_ONLY_RELEASE_VERSION);
2234 // initialize the property sheet itself
2235 HWND std_init_property_sheet(HWND hwndDlg)
2239 // initialize the property pages
2240 std_init_property_pages();
2242 // create the property sheet
2243 Sheet.dwSize = sizeof(PROPSHEETHEADER);
2244 Sheet.dwFlags = PSH_PROPSHEETPAGE | PSH_MODELESS | PSH_NOAPPLYNOW;
2245 Sheet.hwndParent = hwndDlg;
2246 Sheet.hInstance = GetModuleHandle(NULL);
2247 Sheet.nPages = MAX_STANDALONE_PAGES;
2249 // set the title bar appropriately
2250 char title_str[512];
2251 memset(title_str, 0, 512);
2252 std_build_title_string(title_str);
2253 Sheet.pszCaption = title_str;
2255 Sheet.nStartPage = 0;
2256 Sheet.ppsp = &Pages[0];
2257 Sheet.pfnCallback = NULL;
2258 Psht = (HWND)PropertySheet(&Sheet);
2260 // set the window style to include a minimize button
2261 //styles = GetWindowLong(Psht, GWL_STYLE );
2262 //if ( styles != 0 ) {
2263 // SetWindowLong(Psht, GWL_STYLE, styles | WS_MINIMIZEBOX );
2266 styles = GetWindowLong(Psht, GWL_EXSTYLE );
2267 if ( styles != 0 ) {
2268 SetWindowLong( Psht, GWL_EXSTYLE, (styles & ~WS_EX_CONTEXTHELP) );
2271 memset(Multi_options_g.std_pname, 0, MAX_GAMENAME_LEN+1);
2273 // change the default property sheet interface into something more useful
2276 // return a handle to this property sheet
2280 extern int Lighting_flag;
2282 BOOL std_create_standalone_window()
2284 Standalone_hwnd = std_init_property_sheet(NULL);
2286 // this is kind of a big-ass hack. But here's what it does. Property sheets only
2287 // initialize their individual pages the first time (and ONLY the first time) they
2288 // are selected. So before any of this happens, their control handles are bogus. So,
2289 // by calling PropSheet_SetCurSel for all the pages, WM_INITDIALOG is sent to all of
2290 // them, and their controls become valid. However, its kind of silly because each
2291 // page will blink into existence for a second. I can't see another way arount this
2294 for(idx=MAX_STANDALONE_PAGES-1;idx>=0;idx--){
2295 PropSheet_SetCurSel(Psht,(HPROPSHEETPAGE)&Pages[idx],idx);
2298 // main_window_inited = 1;
2300 // turn off lighting effects
2303 // turn off all sound and music
2304 Cmdline_freespace_no_sound = 1;
2305 Cmdline_freespace_no_music = 1;
2307 // reset all standalone gui items
2308 std_reset_standalone_gui();
2310 // initialize the debug outwindow
2318 // just like the osapi version for the nonstandalone mode of Freespace
2319 DWORD standalone_process(WORD lparam)
2323 if ( !std_create_standalone_window() )
2328 if(PropSheet_GetCurrentPageHwnd(Psht)==NULL){
2329 mprintf(("prop sheet is destroyed -- exiting\n"));
2330 DestroyWindow(Psht);
2333 std_deinit_standalone();
2337 if (WaitMessage()) {
2338 while(PeekMessage(&msg,0,0,0,PM_REMOVE)) {
2340 // if the dialog should be destroyed, then exit.
2341 if ( msg.message == WM_DESTROY ) {
2342 DestroyWindow(Psht);
2344 gameseq_post_event(GS_EVENT_QUIT_GAME);
2348 // see if the message is destined for the edit control, and what the message is.
2349 // intercept if a return
2350 if ( msg.hwnd == Godstuff_broadcast_text ) {
2353 virt_key = (int)msg.wParam;
2354 if ( (msg.message == WM_KEYDOWN) && (virt_key == VK_RETURN) ) {
2355 std_gs_send_godstuff_message();
2360 TranslateMessage(&msg);
2361 DispatchMessage(&msg);
2368 // called when freespace initialized
2369 void std_init_standalone()
2371 // start the main thread
2372 Standalone_thread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)standalone_process, NULL, 0, &Standalone_thread_id );
2374 os_init_registry_stuff(Osreg_company_name, Osreg_app_name,NULL);
2376 // set the close functions
2377 atexit(std_deinit_standalone);
2380 // called when freespace closes
2381 void std_deinit_standalone()
2383 if (Standalone_thread) {
2384 CloseHandle(Standalone_thread);
2385 Standalone_thread = NULL;