mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-09 04:49:39 -10:00
2388 lines
69 KiB
C++
2388 lines
69 KiB
C++
/*
|
|
* Copyright (C) Volition, Inc. 1999. All rights reserved.
|
|
*
|
|
* All source code herein is the property of Volition, Inc. You may not sell
|
|
* or otherwise commercially exploit the source or things you created based on the
|
|
* source.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* $Logfile: /Freespace2/code/Network/stand_gui.cpp $
|
|
* $Revision: 2.3 $
|
|
* $Date: 2002-08-04 05:13:00 $
|
|
* $Author: penguin $
|
|
*
|
|
* $Log: not supported by cvs2svn $
|
|
* Revision 2.2 2002/08/01 01:41:08 penguin
|
|
* The big include file move
|
|
*
|
|
* Revision 2.1 2002/07/22 01:22:26 penguin
|
|
* Linux port -- added NO_STANDALONE ifdefs
|
|
*
|
|
* Revision 2.0 2002/06/03 04:02:27 penguin
|
|
* Warpcore CVS sync
|
|
*
|
|
* Revision 1.1 2002/05/02 18:03:11 mharris
|
|
* Initial checkin - converted filenames and includes to lower case
|
|
*
|
|
*
|
|
* 16 8/16/99 4:06p Dave
|
|
* Big honking checkin.
|
|
*
|
|
* 15 8/11/99 5:54p Dave
|
|
* Fixed collision problem. Fixed standalone ghost problem.
|
|
*
|
|
* 14 8/04/99 5:45p Dave
|
|
* Upped default standalone server framerate to 60.
|
|
*
|
|
* 13 5/22/99 5:35p Dave
|
|
* Debrief and chatbox screens. Fixed small hi-res HUD bug.
|
|
*
|
|
* 12 5/19/99 4:07p Dave
|
|
* Moved versioning code into a nice isolated common place. Fixed up
|
|
* updating code on the pxo screen. Fixed several stub problems.
|
|
*
|
|
* 11 4/25/99 7:43p Dave
|
|
* Misc small bug fixes. Made sun draw properly.
|
|
*
|
|
* 10 2/24/99 2:25p Dave
|
|
* Fixed up chatbox bugs. Made squad war reporting better. Fixed a respawn
|
|
* bug for dogfight more.
|
|
*
|
|
* 9 2/18/99 11:46a Neilk
|
|
* hires interface coord support
|
|
*
|
|
* 8 2/12/99 6:16p Dave
|
|
* Pre-mission Squad War code is 95% done.
|
|
*
|
|
* 7 11/19/98 4:19p Dave
|
|
* Put IPX sockets back in psnet. Consolidated all multiplayer config
|
|
* files into one.
|
|
*
|
|
* 6 11/17/98 11:12a Dave
|
|
* Removed player identification by address. Now assign explicit id #'s.
|
|
*
|
|
* 5 11/05/98 5:55p Dave
|
|
* Big pass at reducing #includes
|
|
*
|
|
* 4 10/09/98 2:57p Dave
|
|
* Starting splitting up OS stuff.
|
|
*
|
|
* 3 10/08/98 4:29p Dave
|
|
* Removed reference to osdefs.h
|
|
*
|
|
* 2 10/07/98 10:53a Dave
|
|
* Initial checkin.
|
|
*
|
|
* 1 10/07/98 10:50a Dave
|
|
*
|
|
* 63 9/17/98 11:56a Allender
|
|
* allow use of return key in edit box
|
|
*
|
|
* 62 9/04/98 3:52p Dave
|
|
* Put in validated mission updating and application during stats
|
|
* updating.
|
|
*
|
|
* 61 7/24/98 9:27a Dave
|
|
* Tidied up endgame sequencing by removing several old flags and
|
|
* standardizing _all_ endgame stuff with a single function call.
|
|
*
|
|
* 60 7/10/98 5:04p Dave
|
|
* Fix connection speed bug on standalone server.
|
|
*
|
|
* 59 6/18/98 4:46p Allender
|
|
* removed test code that I previously forgot to remove
|
|
*
|
|
* 58 6/18/98 3:52p Allender
|
|
* make close button actually close down property sheet
|
|
*
|
|
* 57 6/13/98 6:02p Hoffoss
|
|
* Externalized all new (or forgot to be added) strings to all the code.
|
|
*
|
|
* 56 6/13/98 3:19p Hoffoss
|
|
* NOX()ed out a bunch of strings that shouldn't be translated.
|
|
*
|
|
* 55 6/10/98 2:56p Dave
|
|
* Substantial changes to reduce bandwidth and latency problems.
|
|
*
|
|
* 54 5/24/98 3:45a Dave
|
|
* Minor object update fixes. Justify channel information on PXO. Add a
|
|
* bunch of configuration stuff for the standalone.
|
|
*
|
|
* 53 5/22/98 9:35p Dave
|
|
* Put in channel based support for PXO. Put in "shutdown" button for
|
|
* standalone. UI tweaks for TvT
|
|
*
|
|
* 52 5/21/98 9:45p Dave
|
|
* Lengthened tracker polling times. Put in initial support for PXO
|
|
* servers with channel filters. Fixed several small UI bugs.
|
|
*
|
|
* 51 5/18/98 9:15p Dave
|
|
* Put in network config file support.
|
|
*
|
|
* 50 5/15/98 5:16p Dave
|
|
* Fix a standalone resetting bug.Tweaked PXO interface. Display captaincy
|
|
* status for team vs. team. Put in asserts to check for invalid team vs.
|
|
* team situations.
|
|
*
|
|
* 49 5/15/98 3:36p John
|
|
* Fixed bug with new graphics window code and standalone server. Made
|
|
* hwndApp not be a global anymore.
|
|
*
|
|
* 48 5/10/98 7:06p Dave
|
|
* Fix endgame sequencing ESC key. Changed how host options warning popups
|
|
* are done. Fixed pause/message scrollback/options screen problems in mp.
|
|
* Make sure observer HUD doesn't try to lock weapons.
|
|
*
|
|
* 47 5/09/98 7:16p Dave
|
|
* Put in CD checking. Put in standalone host password. Made pilot into
|
|
* popup scrollable.
|
|
*
|
|
* 46 5/08/98 7:09p Dave
|
|
* Lots of UI tweaking.
|
|
*
|
|
* 45 5/08/98 5:05p Dave
|
|
* Go to the join game screen when quitting multiplayer. Fixed mission
|
|
* text chat bugs. Put mission type symbols on the create game list.
|
|
* Started updating standalone gui controls.
|
|
*
|
|
* 44 5/04/98 1:44p Dave
|
|
* Fixed up a standalone resetting problem. Fixed multiplayer stats
|
|
* collection for clients. Make sure all multiplayer ui screens have the
|
|
* correct palette at all times.
|
|
*
|
|
* 43 5/02/98 5:38p Dave
|
|
* Put in new tracker API code. Put in ship information on mp team select
|
|
* screen. Make standalone server name permanent. Fixed standalone server
|
|
* text messages.
|
|
*
|
|
* 42 5/02/98 1:45a Dave
|
|
* Make standalone goal tree not flicker.
|
|
*
|
|
* 41 5/01/98 10:57a Jim
|
|
* from Dave: fixed mission goal problems
|
|
*
|
|
* 40 4/29/98 12:11a Dave
|
|
* Put in first rev of full API support for new master tracker.
|
|
*
|
|
* 39 4/28/98 5:11p Dave
|
|
* Fixed multi_quit_game() client side sequencing problem. Turn off
|
|
* afterburners when ending multiplayer mission. Begin integration of mt
|
|
* API from Kevin Bentley.
|
|
*
|
|
* 38 4/25/98 2:02p Dave
|
|
* Put in multiplayer context help screens. Reworked ingame join ship
|
|
* select screen. Fixed places where network timestamps get hosed.
|
|
*
|
|
* 37 4/06/98 6:37p Dave
|
|
* Put in max_observers netgame server option. Make sure host is always
|
|
* defaulted to alpha 1 or zeta 1. Changed create game so that MAX_PLAYERS
|
|
* can always join but need to be kicked before commit can happen. Put in
|
|
* support for server ending a game and notifying clients of a special
|
|
* condition.
|
|
*
|
|
* 36 3/31/98 5:18p John
|
|
* Removed demo/save/restore. Made NDEBUG defined compile. Removed a
|
|
* bunch of debug stuff out of player file. Made model code be able to
|
|
* unload models and malloc out only however many models are needed.
|
|
*
|
|
*
|
|
* 35 3/24/98 5:00p Dave
|
|
* Fixed several ui bugs. Put in pre and post voice stream playback sound
|
|
* fx. Put in error specific popups for clients getting dropped from games
|
|
* through actions other than their own.
|
|
*
|
|
* 34 3/19/98 5:05p Dave
|
|
* Put in support for targeted multiplayer text and voice messaging (all,
|
|
* friendly, hostile, individual).
|
|
*
|
|
* 33 3/17/98 5:29p Dave
|
|
* Minor bug fixes in player select menu. Solidified mp joining process.
|
|
* Made furball mode support ingame joiners and dropped players correctly.
|
|
*
|
|
* 32 3/15/98 4:17p Dave
|
|
* Fixed oberver hud problems. Put in handy netplayer macros. Reduced size
|
|
* of network orientation matrices.
|
|
*
|
|
* 31 3/03/98 5:12p Dave
|
|
* 50% done with team vs. team interface issues. Added statskeeping to
|
|
* secondary weapon blasts. Numerous multiplayer ui bug fixes.
|
|
*
|
|
* 30 2/12/98 4:41p Dave
|
|
* Seperated multiplayer kick functionality into its own module. Ui
|
|
* tweaking
|
|
*
|
|
* 29 2/05/98 10:24a Hoffoss
|
|
* Changed "goal" text to "objective", which is the correct term nowadays.
|
|
*
|
|
* 28 1/31/98 4:32p Dave
|
|
* Put in new support for VMT player validation, game logging in, and game
|
|
* logging out. Need to finish stats transfer.
|
|
*
|
|
* 27 1/28/98 6:24p Dave
|
|
* Made standalone use ~8 megs less memory. Fixed multiplayer submenu
|
|
* sequencing problem.
|
|
*
|
|
* 26 1/24/98 3:39p Dave
|
|
* Fixed numerous multiplayer bugs (last frame quit problem, weapon bank
|
|
* changing, deny packets). Add several controls to standalone server.
|
|
*
|
|
* 25 1/20/98 2:23p Dave
|
|
* Removed optimized build warnings. 99% done with ingame join fixes.
|
|
*
|
|
* 24 1/17/98 2:46a Dave
|
|
* Reworked multiplayer join/accept process. Ingame join still needs to be
|
|
* integrated.
|
|
*
|
|
* 23 1/16/98 2:34p Dave
|
|
* Made pause screen work properly (multiplayer). Changed how chat packets
|
|
* work.
|
|
*
|
|
* 22 1/13/98 5:37p Dave
|
|
* Reworked a lot of standalone interface code. Put in single and
|
|
* multiplayer popups for death sequence. Solidified multiplayer kick
|
|
* code.
|
|
*
|
|
* 21 1/11/98 10:03p Allender
|
|
* removed <winsock.h> from headers which included it. Made psnet_socket
|
|
* type which is defined just as SOCKET type is.
|
|
*
|
|
* 20 1/05/98 5:07p Dave
|
|
* Fixed a chat packet bug. Fixed a few state save/restore bugs. Updated a
|
|
* few things for multiplayer server transfer.
|
|
*
|
|
* 19 12/10/97 4:46p Dave
|
|
* Added in more detailed support for multiplayer packet lag/loss. Fixed
|
|
* some multiplayer stuff. Added some controls to the standalone.
|
|
*
|
|
* 18 12/03/97 11:50p Dave
|
|
* Fixed a bunch of multiplayer bugs (standalone and non)
|
|
*
|
|
* 17 12/03/97 11:59a Dave
|
|
* Dependant merge checkin
|
|
*
|
|
* 16 12/02/97 10:05p Dave
|
|
* Began some large-scale multiplayer debugging work (mostly standalone)
|
|
*
|
|
* 15 11/15/97 2:37p Dave
|
|
* More multiplayer campaign support.
|
|
*
|
|
* 14 10/29/97 5:18p Dave
|
|
* More debugging of server transfer. Put in debrief/brief
|
|
* transition for multiplayer (w/standalone)
|
|
*
|
|
* 13 10/25/97 7:23p Dave
|
|
* Moved back to single set stats storing. Put in better respawning
|
|
* locations system.
|
|
*
|
|
* 12 10/24/97 6:19p Dave
|
|
* More standalone testing/fixing. Added reliable endgame sequencing.
|
|
* Added reliable ingame joining. Added reliable stats transfer (endgame).
|
|
* Added support for dropping players in debriefing. Removed a lot of old
|
|
* unused code.
|
|
*
|
|
* 11 10/21/97 5:21p Dave
|
|
* Fixed pregame mission load/file verify debacle. Added single vs.
|
|
* multiplayer stats system.
|
|
*
|
|
* 10 10/14/97 5:38p Dave
|
|
* Player respawns 99.9% done. Only need to check cases for server/host
|
|
* getting killed.
|
|
*
|
|
* 9 10/03/97 4:57p Dave
|
|
* Added functions for new text controls. Added some more reset controls.
|
|
* Put in checks for all-players-gone.
|
|
*
|
|
* 8 9/17/97 9:09a Dave
|
|
* Observer mode works, put in standalone controls. Fixed up some stuff for
|
|
* ingame join broken by recent code checkins.
|
|
*
|
|
* 7 8/29/97 5:03p Dave
|
|
* Added a ton of new gui controls/features.
|
|
*
|
|
* 6 8/26/97 5:03p Dave
|
|
* Added bunch of informational controls. Standardized some functions for
|
|
* external use. Put in godview mode (conditionaled out though).
|
|
*
|
|
* 5 8/23/97 11:31a Dave
|
|
* Put in new gui calls. Added a bunch of display controls.
|
|
*
|
|
* 4 8/20/97 4:19p Dave
|
|
* Moved some functions around. Added the standalone state text box.
|
|
*
|
|
* 3 8/18/97 11:46a Dave
|
|
* Moved definition of STANDALONE_FRAME_CAP tp multi.h
|
|
*
|
|
* 2 8/11/97 4:52p Dave
|
|
* Spliced out standalone GUI stuff from OsApi and WinMain.cpp to its own
|
|
* module.
|
|
*
|
|
* 1 8/11/97 4:21p Dave
|
|
*
|
|
* $NoKeywords: $
|
|
*/
|
|
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include <commctrl.h>
|
|
#include <io.h>
|
|
#endif
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <stdarg.h>
|
|
|
|
#include "math/vecmat.h"
|
|
#include "graphics/tmapper.h"
|
|
#include "graphics/2d.h"
|
|
#include "render/3d.h"
|
|
#include "model/model.h"
|
|
#include "bmpman/bmpman.h"
|
|
#include "lighting/lighting.h"
|
|
#include "globalincs/linklist.h"
|
|
#include "freespace2/freespace.h"
|
|
|
|
#include "network/stand_gui.h"
|
|
#include "globalincs/pstypes.h"
|
|
#include "osapi/osapi.h"
|
|
#include "io/key.h"
|
|
#include "palman/palman.h"
|
|
#include "io/mouse.h"
|
|
#include "osapi/outwnd.h"
|
|
#include "graphics/2d.h"
|
|
#include "cfile/cfile.h"
|
|
#include "sound/sound.h"
|
|
#include "freespace2/freespaceresource.h"
|
|
#include "network/multi.h"
|
|
#include "network/multimsgs.h"
|
|
#include "network/multiutil.h"
|
|
#include "mission/missiongoals.h"
|
|
#include "globalincs/systemvars.h"
|
|
#include "cmdline/cmdline.h"
|
|
#include "network/multi_kick.h"
|
|
#include "network/multi_pmsg.h"
|
|
#include "missionui/chatbox.h"
|
|
#include "network/multi_endgame.h"
|
|
#include "gamesequence/gamesequence.h"
|
|
#include "osapi/osregistry.h"
|
|
#include "io/timer.h"
|
|
#include "globalincs/version.h"
|
|
|
|
HANDLE Standalone_thread;
|
|
DWORD Standalone_thread_id;
|
|
static HWND Standalone_hwnd = NULL;
|
|
|
|
// -----------------------------------------------------------------------------------------
|
|
// standalone global defs
|
|
|
|
#define MAX_STANDALONE_PAGES 5
|
|
|
|
#define STD_STATS_UPDATE_TIME 500 // ms between updating player stats on the visible controls
|
|
#define STD_NG_UPDATE_TIME 100 // ms between updating netgame information are controls
|
|
|
|
// coords for the "shutdown" button (client window coords)
|
|
static int Std_shutdown_coords[GR_NUM_RESOLUTIONS][2] = {
|
|
{ 130, 450 }, // GR_640
|
|
{ 130, 450 } // GR_640
|
|
};
|
|
|
|
// you should reference Page_handles and Pages with these defines from now on
|
|
#define CONNECT_PAGE 0
|
|
#define MULTIPLAYER_PAGE 1
|
|
#define PLAYER_INFO_PAGE 2
|
|
#define GODSTUFF_PAGE 3
|
|
#define DEBUG_PAGE 4
|
|
|
|
// standalone gui property sheet stuff
|
|
static HWND Psht;
|
|
static HWND Page_handles[MAX_STANDALONE_PAGES];
|
|
static PROPSHEETPAGE Pages[MAX_STANDALONE_PAGES];
|
|
static PROPSHEETHEADER Sheet;
|
|
|
|
// index into Page_handles[] representing the currently selected page
|
|
static int Active_standalone_page;
|
|
|
|
// timestamp for updating currently selected player stats on the player info page
|
|
int Standalone_stats_stamp;
|
|
|
|
// timestamp for updating the netgame information are text controls
|
|
int Standalone_ng_stamp;
|
|
|
|
// banned player callsigns
|
|
#define STANDALONE_MAX_BAN 50
|
|
char Standalone_ban_list[STANDALONE_MAX_BAN][CALLSIGN_LEN+1];
|
|
int Standalone_ban_count = 0;
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// mission validation dialog
|
|
//
|
|
|
|
static HWND Multi_gen_dialog = NULL; // the dialog itself
|
|
|
|
// dialog proc for this dialog
|
|
BOOL CALLBACK std_gen_dialog_proc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch(uMsg){
|
|
case WM_INITDIALOG:
|
|
return TRUE;
|
|
|
|
// destory command
|
|
case WM_DESTROY:
|
|
Multi_gen_dialog = NULL;
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// create the validate dialog
|
|
void std_create_gen_dialog(char *title)
|
|
{
|
|
// if the dialog is already active, do nothing
|
|
if(Multi_gen_dialog != NULL){
|
|
return;
|
|
}
|
|
|
|
// otherwise create the dialog
|
|
Multi_gen_dialog = CreateDialog(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_GEN), Psht, (DLGPROC)std_gen_dialog_proc);
|
|
if(Multi_gen_dialog != NULL){
|
|
SetWindowText(Multi_gen_dialog, title);
|
|
}
|
|
}
|
|
|
|
// kill the validate dialog();
|
|
void std_destroy_gen_dialog()
|
|
{
|
|
// if the dialog is not active, do nothing
|
|
if(Multi_gen_dialog == NULL){
|
|
return;
|
|
}
|
|
|
|
// kill it
|
|
DestroyWindow(Multi_gen_dialog);
|
|
Multi_gen_dialog = NULL;
|
|
}
|
|
|
|
// set the text in the filename of the validate dialog
|
|
// valid values for field_num == 0 .. 2
|
|
void std_gen_set_text(char *str, int field_num)
|
|
{
|
|
HWND ctrl;
|
|
|
|
// if the dialog is not active
|
|
if((Multi_gen_dialog == NULL) || (str == NULL) || (field_num < 0) || (field_num > 2)){
|
|
return;
|
|
}
|
|
|
|
// otherwise set the text
|
|
ctrl = GetDlgItem(Multi_gen_dialog, (int)MAKEINTRESOURCE(IDC_FIELD1));
|
|
switch(field_num){
|
|
case 0:
|
|
ctrl = GetDlgItem(Multi_gen_dialog,(int)MAKEINTRESOURCE(IDC_FIELD1));
|
|
break;
|
|
case 1:
|
|
ctrl = GetDlgItem(Multi_gen_dialog,(int)MAKEINTRESOURCE(IDC_FIELD2));
|
|
break;
|
|
case 2:
|
|
ctrl = GetDlgItem(Multi_gen_dialog,(int)MAKEINTRESOURCE(IDC_FIELD3));
|
|
break;
|
|
}
|
|
SetWindowText(ctrl, str);
|
|
}
|
|
|
|
// is the validate dialog active
|
|
int std_gen_is_active()
|
|
{
|
|
return Multi_gen_dialog != NULL;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// connection page/tab functions
|
|
//
|
|
static HWND Multi_std_name; // standalone name text edit control
|
|
HWND Multi_std_host_passwd; // host password text control
|
|
int Multi_std_namechange_force;
|
|
|
|
// convert the index of an item in the list box into an index into the net players array
|
|
int std_connect_lindex_to_npindex(int index);
|
|
|
|
// set the text box indicating how many players are connected, returning the determined count
|
|
int std_connect_set_connect_count()
|
|
{
|
|
HWND ctrl;
|
|
char str[40];
|
|
char val[10];
|
|
int idx,count;
|
|
|
|
// setup the text string
|
|
strcpy(str,XSTR("# Connections : ",911));
|
|
|
|
// determine how many players are actually connected
|
|
count = 0;
|
|
for(idx=0;idx<MAX_PLAYERS;idx++){
|
|
if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
|
|
count++;
|
|
}
|
|
}
|
|
|
|
// tack on the player count to the end of the string
|
|
sprintf(val,"%d",count);
|
|
strcat(str,val);
|
|
|
|
// set the text itself
|
|
ctrl = GetDlgItem(Page_handles[CONNECT_PAGE],(int)MAKEINTRESOURCE(IDC_CON_COUNT));
|
|
SetWindowText(ctrl,str);
|
|
|
|
// return the num of players found
|
|
return count;
|
|
}
|
|
|
|
// set the connect status (connected or not) of the game host
|
|
void std_connect_set_host_connect_status()
|
|
{
|
|
int idx,found;
|
|
HWND ctrl;
|
|
|
|
// first try and find the host
|
|
found = 0;
|
|
for(idx=0;idx<MAX_PLAYERS;idx++){
|
|
if(MULTI_CONNECTED(Net_players[idx]) && MULTI_HOST(Net_players[idx])){
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// get the control and set the status
|
|
ctrl = GetDlgItem(Page_handles[CONNECT_PAGE],(int)MAKEINTRESOURCE(IDC_HOST_IS));
|
|
if(found){
|
|
SetWindowText(ctrl, XSTR("Host connected ? Yes",912));
|
|
} else {
|
|
SetWindowText(ctrl, XSTR("Host connected ? No",913));
|
|
}
|
|
}
|
|
|
|
// add an ip string to the connect page listbox
|
|
void std_connect_add_ip_string(char *string)
|
|
{
|
|
HWND ctrl;
|
|
|
|
// add the item
|
|
ctrl = GetDlgItem(Page_handles[CONNECT_PAGE], (int)MAKEINTRESOURCE(IDC_CONPING));
|
|
SendMessage(ctrl, LB_ADDSTRING, (WPARAM)0, (LPARAM)(LPCTSTR)string);
|
|
}
|
|
|
|
// remove an ip string from the connect page listbox
|
|
void std_connect_remove_ip_string(char *string)
|
|
{
|
|
HWND ctrl;
|
|
int loc;
|
|
|
|
// get the control handle
|
|
ctrl = GetDlgItem(Page_handles[CONNECT_PAGE], (int)MAKEINTRESOURCE(IDC_CONPING));
|
|
|
|
// NOTE the use of FINDSTRING and _not_ FINDSTRINGEXACT !!
|
|
// since we've appended the ping to the end of the string, we can only check the
|
|
// "prefix" which is the net_players name
|
|
loc = SendMessage(ctrl, LB_FINDSTRING, (WPARAM)-1, (LPARAM)(LPCTSTR)string);
|
|
|
|
if(loc!=LB_ERR){
|
|
SendMessage(ctrl, LB_DELETESTRING, (WPARAM)loc, (LPARAM)0);
|
|
}
|
|
}
|
|
|
|
// set an ip string on the connect page listbox
|
|
void std_connect_set_ip_string(char *lookup,char *string)
|
|
{
|
|
HWND ctrl;
|
|
int loc;
|
|
|
|
// get the control handle
|
|
ctrl = GetDlgItem(Page_handles[CONNECT_PAGE],(int)MAKEINTRESOURCE(IDC_CONPING));
|
|
|
|
// NOTE the use of FINDSTRING and _not_ FINDSTRINGEXACT !!
|
|
// since we've appended the ping to the end of the string, we can only check the
|
|
// "prefix" which is the net_players name
|
|
loc = SendMessage(ctrl,LB_FINDSTRING,(WPARAM)-1,(LPARAM)(LPCTSTR)lookup);
|
|
|
|
if(loc!=LB_ERR){
|
|
SendMessage(ctrl,LB_DELETESTRING,(WPARAM)loc,(LPARAM)0);
|
|
SendMessage(ctrl,LB_INSERTSTRING,(WPARAM)loc,(LPARAM)string);
|
|
}
|
|
}
|
|
|
|
void std_connect_kick_player()
|
|
{
|
|
int player_num,sel;
|
|
HWND ctrl;
|
|
|
|
// get the control handle
|
|
ctrl = GetDlgItem(Page_handles[CONNECT_PAGE],(int)MAKEINTRESOURCE(IDC_CONPING));
|
|
|
|
sel = SendMessage(ctrl,LB_GETCURSEL,(WPARAM)0,(LPARAM)0);
|
|
// attempt to get the player index
|
|
if(sel != CB_ERR){
|
|
player_num = std_connect_lindex_to_npindex(sel);
|
|
|
|
// if we found him, then kick the bastard
|
|
if(player_num != -1){
|
|
multi_kick_player(player_num,0);
|
|
}
|
|
}
|
|
}
|
|
|
|
// update the ping for this particular player
|
|
void std_connect_update_ping(net_player *p)
|
|
{
|
|
char str[40],ping[10],sml_ping[10],lookup[50];
|
|
|
|
// as long as his ping is not -1, do an update
|
|
if(p->s_info.ping.ping_avg > -1){
|
|
// get the lookup string
|
|
psnet_addr_to_string(lookup,&p->p_info.addr);
|
|
|
|
// build the string to replace the ping with
|
|
strcpy(str,lookup);
|
|
strcat(str,", ");
|
|
|
|
// chop it off at pings greater than 1 second
|
|
if(p->s_info.ping.ping_avg > 1000){
|
|
strcat(str,XSTR("> 1 sec",914));
|
|
strcpy(sml_ping,XSTR("> 1 sec",914));
|
|
}
|
|
else {
|
|
sprintf(ping,"%d",p->s_info.ping.ping_avg);
|
|
strcat(str,ping);
|
|
strcat(str,XSTR(" ms",915));
|
|
strcpy(sml_ping,ping); strcat(sml_ping,XSTR(" ms",915));
|
|
}
|
|
|
|
// set the string
|
|
std_connect_set_ip_string(lookup,str);
|
|
}
|
|
}
|
|
|
|
// clear all the controls for this page
|
|
void std_connect_clear_controls()
|
|
{
|
|
HWND handle;
|
|
|
|
// set various connect counts
|
|
std_connect_set_connect_count();
|
|
std_connect_set_host_connect_status();
|
|
|
|
// reset the list of players and pings
|
|
handle = GetDlgItem(Page_handles[CONNECT_PAGE],(int)MAKEINTRESOURCE(IDC_CONPING));
|
|
SendMessage(handle,LB_RESETCONTENT,(WPARAM)0,(LPARAM)0);
|
|
}
|
|
|
|
// set the game name for the standalone. passing NULL uses the default
|
|
void std_connect_set_gamename(char *name)
|
|
{
|
|
char buf[MAX_GAMENAME_LEN+1];
|
|
|
|
// use the default name for now
|
|
if(name == NULL){
|
|
// if a permanent name exists, use that instead of the default
|
|
if(strlen(Multi_options_g.std_pname)){
|
|
strcpy(Netgame.name, Multi_options_g.std_pname);
|
|
} else {
|
|
strcpy(Netgame.name,XSTR("Standalone Server",916));
|
|
}
|
|
} else {
|
|
strcpy(Netgame.name,name);
|
|
}
|
|
|
|
// update the text control
|
|
strcpy(buf,Netgame.name);
|
|
Multi_std_namechange_force = 0;
|
|
SetWindowText(Multi_std_name,buf);
|
|
Multi_std_namechange_force = 1;
|
|
}
|
|
|
|
// the user has changed the text in the server name text box. handle this
|
|
void std_connect_handle_name_change()
|
|
{
|
|
char buf[MAX_GAMENAME_LEN+2];
|
|
int max_len = MAX_GAMENAME_LEN+2;
|
|
|
|
if(Multi_std_namechange_force){
|
|
memset(buf,0,MAX_GAMENAME_LEN+2);
|
|
memcpy(&buf[0],&max_len,sizeof(int));
|
|
|
|
// get the new text
|
|
SendMessage(Multi_std_name,EM_GETLINE,(WPARAM)0,(LPARAM)(LPCSTR)buf);
|
|
|
|
// just copy it over for now. we may want to process this more later on
|
|
strcpy(Netgame.name,buf);
|
|
|
|
// copy it to the permanent name
|
|
strcpy(Multi_options_g.std_pname, buf);
|
|
}
|
|
}
|
|
|
|
// the user has changed the text in the host password text box
|
|
void std_connect_handle_passwd_change()
|
|
{
|
|
char buf[STD_PASSWD_LEN+2];
|
|
int max_len = STD_PASSWD_LEN+2;
|
|
|
|
memset(buf,0,STD_PASSWD_LEN+2);
|
|
memcpy(&buf[0],&max_len,sizeof(int));
|
|
|
|
// get the new text
|
|
SendMessage(Multi_std_host_passwd,EM_GETLINE,(WPARAM)0,(LPARAM)(LPCSTR)buf);
|
|
|
|
// just copy it over for now. we may want to process this more later on
|
|
strcpy(Multi_options_g.std_passwd, buf);
|
|
}
|
|
|
|
// convert the index of an item in the list box into an index into the net players array
|
|
int std_connect_lindex_to_npindex(int index)
|
|
{
|
|
HWND ctrl;
|
|
char list_text[40];
|
|
char addr_text[40];
|
|
int ret,idx;
|
|
|
|
// get the control handle
|
|
ctrl = GetDlgItem(Page_handles[CONNECT_PAGE],(int)MAKEINTRESOURCE(IDC_CONPING));
|
|
|
|
// get the string contained at a given index
|
|
SendMessage(ctrl,LB_GETTEXT,(WPARAM)index,(LPARAM)(LPSTR)list_text);
|
|
|
|
// look through the net players array and compare address strings (yuck)
|
|
ret = -1;
|
|
for(idx=0;idx<MAX_PLAYERS;idx++){
|
|
// only look at connected players
|
|
if(MULTI_CONNECTED(Net_players[idx])){
|
|
strcpy(addr_text,"");
|
|
psnet_addr_to_string(addr_text,&Net_players[idx].p_info.addr);
|
|
|
|
// if we found the match
|
|
if((strlen(addr_text) != 0) && (strstr(list_text,addr_text) != NULL)){
|
|
ret = idx;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// message handler for the connect tab
|
|
BOOL CALLBACK connect_proc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)
|
|
{
|
|
switch(uMsg){
|
|
// initialize the dialog
|
|
case WM_INITDIALOG:
|
|
// setup the page handle array for this page
|
|
Page_handles[CONNECT_PAGE] = hwndDlg;
|
|
|
|
// create the standalone name text box and limit its text length
|
|
Multi_std_name = GetDlgItem(hwndDlg, (int)MAKEINTRESOURCE(IDC_STD_NAME));
|
|
SendMessage(Multi_std_name, EM_SETLIMITTEXT, (WPARAM)MAX_GAMENAME_LEN-1, (LPARAM)0);
|
|
Multi_std_namechange_force = 1;
|
|
|
|
// create the standalone host password input box
|
|
Multi_std_host_passwd = GetDlgItem(hwndDlg, (int)MAKEINTRESOURCE(IDC_STD_HOST_PASSWD));
|
|
SendMessage(Multi_std_host_passwd, EM_SETLIMITTEXT, (WPARAM)STD_PASSWD_LEN, (LPARAM)0);
|
|
memset(Multi_options_g.std_passwd, 0, STD_PASSWD_LEN+1);
|
|
|
|
return 1;
|
|
|
|
// process a command of some kind (usually button presses)
|
|
case WM_COMMAND:
|
|
switch(HIWORD(wParam)){
|
|
// a button press
|
|
case BN_CLICKED :
|
|
switch(LOWORD(wParam)){
|
|
// the reset standalone button
|
|
case IDC_RESET_MULTI :
|
|
// multi_standalone_quit_game();
|
|
multi_quit_game(PROMPT_NONE);
|
|
break;
|
|
|
|
// kick the currently selected player
|
|
case IDC_KICK_BUTTON :
|
|
std_connect_kick_player();
|
|
break;
|
|
|
|
// refresh file list (PXO)
|
|
case IDC_PXO_REFRESH:
|
|
if(MULTI_IS_TRACKER_GAME){
|
|
// delete mvalid.cfg if it exists
|
|
cf_delete(MULTI_VALID_MISSION_FILE, CF_TYPE_DATA);
|
|
|
|
// refresh missions
|
|
multi_update_valid_missions();
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
// an edit control text has been changed
|
|
case EN_UPDATE :
|
|
if((HWND)lParam == Multi_std_name){
|
|
// update the standalone name field in Netgame.name
|
|
std_connect_handle_name_change();
|
|
} else if((HWND)lParam == Multi_std_host_passwd){
|
|
// update the standalone host passwd
|
|
std_connect_handle_passwd_change();
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
// a notification message
|
|
case WM_NOTIFY :
|
|
// notification that this is the current selected page. set our own internal data vars
|
|
if(((LPNMHDR)lParam)->code == PSN_SETACTIVE){
|
|
Active_standalone_page = CONNECT_PAGE;
|
|
} else if ( (((LPNMHDR)lParam)->code == PSN_APPLY) || (((LPNMHDR)lParam)->code == PSN_RESET) ) {
|
|
PostMessage( Psht, WM_DESTROY, 0, 0 );
|
|
}
|
|
break;
|
|
|
|
default :
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// multiplayer page/tab functions
|
|
//
|
|
|
|
static HWND Framecap_trackbar; // trackbar for capping framerate
|
|
static HWND Standalone_FPS; // text control for displaying framerate
|
|
static HWND Standalone_mission_name; // text control for showing the current mission name
|
|
static HWND Standalone_missiontime; // text control for showing current mission time
|
|
static HIMAGELIST Goal_bitmaps; // bitmaps array for the goal tree control
|
|
static HWND Standalone_goals; // goal tree control handle
|
|
static HTREEITEM Goal_items[3]; // primary, secondary, and bonus goal items
|
|
static HWND Std_ng_max_players; // max players display text control
|
|
static HWND Std_ng_max_observers; // max observers display text control
|
|
static HWND Std_ng_security; // netgame security display text control
|
|
static HWND Std_ng_respawns; // netgame # respawns display text control
|
|
|
|
#define GOALVIEW_X 5 // goal view control extents
|
|
#define GOALVIEW_Y 242 //
|
|
#define GOALVIEW_W 160 //
|
|
#define GOALVIEW_H 168 //
|
|
|
|
// handle the user sliding the framerate cap scrollbar around
|
|
void std_multi_handle_framecap_scroll(HWND ctrl);
|
|
|
|
// initialize the framerate cap slide control
|
|
void std_multi_init_framecap_slider(HWND hwndDlg);
|
|
|
|
// initialize all the controls for this page
|
|
void std_multi_init_multi_controls(HWND hwndDlg);
|
|
|
|
// return the handle to the item matching the given parameters
|
|
HTREEITEM std_multi_get_goal_item(char *goal_string,int type);
|
|
|
|
// set the mission time in seconds
|
|
void std_multi_set_standalone_missiontime(float mission_time)
|
|
{
|
|
char txt[20];
|
|
char time_txt[30];
|
|
fix m_time = fl2f(mission_time);
|
|
|
|
// format the time string and set the text
|
|
game_format_time(m_time,time_txt);
|
|
sprintf(txt," : %.1f", mission_time);
|
|
strcat(time_txt,txt);
|
|
SetWindowText(Standalone_missiontime,time_txt);
|
|
}
|
|
|
|
// set the mission name
|
|
void std_multi_set_standalone_mission_name(char *mission_name)
|
|
{
|
|
// set the text
|
|
SetWindowText(Standalone_mission_name,mission_name);
|
|
}
|
|
|
|
// initialize the goal tree for this mission
|
|
void std_multi_setup_goal_tree()
|
|
{
|
|
TV_ITEM new_item;
|
|
TV_INSERTSTRUCT tree_insert;
|
|
char goal_name[NAME_LENGTH+1];
|
|
|
|
// clear out the tree control
|
|
TreeView_DeleteAllItems(Standalone_goals);
|
|
|
|
// add the primary goal tag
|
|
new_item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
|
|
new_item.pszText = goal_name;
|
|
strcpy(new_item.pszText,XSTR("Primary Objectives",917));
|
|
new_item.iImage = 0;
|
|
new_item.iSelectedImage = 0;
|
|
tree_insert.hParent = NULL;
|
|
tree_insert.hInsertAfter = TVI_FIRST;
|
|
tree_insert.item = new_item;
|
|
Goal_items[0] = TreeView_InsertItem(Standalone_goals,&tree_insert);
|
|
|
|
// add the secondary goal tag
|
|
new_item.pszText = goal_name;
|
|
strcpy(new_item.pszText,XSTR("Secondary Objectives",918));
|
|
new_item.iImage = 0;
|
|
new_item.iSelectedImage = 0;
|
|
tree_insert.hInsertAfter = TVI_LAST;
|
|
tree_insert.item = new_item;
|
|
Goal_items[1] = TreeView_InsertItem(Standalone_goals,&tree_insert);
|
|
|
|
// add the bonus goal tag
|
|
new_item.pszText = goal_name;
|
|
strcpy(new_item.pszText,XSTR("Bonus Objectives",919));
|
|
new_item.iImage = 0;
|
|
new_item.iSelectedImage = 0;
|
|
tree_insert.item = new_item;
|
|
Goal_items[2] = TreeView_InsertItem(Standalone_goals,&tree_insert);
|
|
}
|
|
|
|
// add all the goals from the current mission to the tree control
|
|
void std_multi_add_goals()
|
|
{
|
|
TV_ITEM new_item;
|
|
TV_INSERTSTRUCT tree_insert;
|
|
int idx,goal_flags,perm_goal_flags;
|
|
char goal_name[NAME_LENGTH+1];
|
|
|
|
// setup data common for every item
|
|
new_item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
|
|
tree_insert.hInsertAfter = TVI_LAST;
|
|
|
|
perm_goal_flags = 0;
|
|
for(idx=0;idx<Num_goals;idx++){
|
|
// reset the goal flags
|
|
goal_flags = 0;
|
|
|
|
switch(Mission_goals[idx].type & GOAL_TYPE_MASK){
|
|
// primary goal
|
|
case PRIMARY_GOAL :
|
|
goal_flags |= (1<<1); // (image index == 1, primary goal)
|
|
perm_goal_flags |= (1<<1);
|
|
break;
|
|
|
|
// a secondary goal
|
|
case SECONDARY_GOAL :
|
|
goal_flags |= (1<<2); // (image index == 1, secondary goal)
|
|
perm_goal_flags |= (1<<2);
|
|
break;
|
|
|
|
// a bonus goal
|
|
case BONUS_GOAL :
|
|
goal_flags |= (1<<3); // (image index == 1, bonus goal)
|
|
perm_goal_flags |= (1<<3);
|
|
break;
|
|
|
|
default :
|
|
goal_flags |= (1<<0); // (image index == 3, no goal)
|
|
break;
|
|
}
|
|
|
|
// first select whether to insert under primary, secondary, or bonus tree roots
|
|
tree_insert.hParent = Goal_items[Mission_goals[idx].type & GOAL_TYPE_MASK];
|
|
|
|
// set the goal name
|
|
new_item.pszText = goal_name;
|
|
strcpy(new_item.pszText,Mission_goals[idx].name);
|
|
|
|
// set the correct image indices
|
|
new_item.iImage = (goal_flags & (1<<0)) ? 3 : 0;
|
|
new_item.iSelectedImage = (goal_flags & (1<<0)) ? 3 : 0;
|
|
|
|
// insert the item
|
|
tree_insert.item = new_item;
|
|
TreeView_InsertItem(Standalone_goals,&tree_insert);
|
|
}
|
|
|
|
// check to see if there are any of the three types of mission goals. If not, then
|
|
// insert "none"
|
|
if(!(perm_goal_flags & (1<<1))){
|
|
// insert the "none" item
|
|
tree_insert.hParent = Goal_items[0];
|
|
new_item.pszText = goal_name;
|
|
strcpy(new_item.pszText,XSTR("none",920));
|
|
new_item.iImage = 3;
|
|
new_item.iSelectedImage = 3;
|
|
tree_insert.item = new_item;
|
|
TreeView_InsertItem(Standalone_goals,&tree_insert);
|
|
}
|
|
if(!(perm_goal_flags & (1<<2))){
|
|
// insert the "none" item
|
|
tree_insert.hParent = Goal_items[1];
|
|
new_item.pszText = goal_name;
|
|
strcpy(new_item.pszText,XSTR("none",920));
|
|
new_item.iImage = 3;
|
|
new_item.iSelectedImage = 3;
|
|
tree_insert.item = new_item;
|
|
TreeView_InsertItem(Standalone_goals,&tree_insert);
|
|
}
|
|
if(!(perm_goal_flags & (1<<3))){
|
|
// insert the "none" item
|
|
tree_insert.hParent = Goal_items[1];
|
|
new_item.pszText = goal_name;
|
|
strcpy(new_item.pszText,XSTR("none",920));
|
|
new_item.iImage = 3;
|
|
new_item.iSelectedImage = 3;
|
|
tree_insert.item = new_item;
|
|
TreeView_InsertItem(Standalone_goals,&tree_insert);
|
|
}
|
|
|
|
// expand out all the tree roots so all goals are shown
|
|
for(idx=0;idx<3;idx++){
|
|
TreeView_Expand(Standalone_goals,Goal_items[idx],TVE_EXPAND);
|
|
}
|
|
}
|
|
|
|
// update all the goals in the goal tree based upon the mission status
|
|
void std_multi_update_goals()
|
|
{
|
|
HTREEITEM update_item;
|
|
TV_ITEM setting,lookup;
|
|
int idx,should_update;
|
|
|
|
setting.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
|
|
|
|
// go through all the goals
|
|
for(idx=0;idx<Num_goals;idx++){
|
|
// get a handle to the tree item
|
|
update_item = NULL;
|
|
update_item = std_multi_get_goal_item(Mission_goals[idx].name,Mission_goals[idx].type & GOAL_TYPE_MASK);
|
|
|
|
// continue if we didn't get a valid item
|
|
if(update_item == NULL){
|
|
continue;
|
|
}
|
|
|
|
// get the tree item itself (as it currently stands)
|
|
lookup.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
|
|
lookup.hItem = update_item;
|
|
if(!TreeView_GetItem(Standalone_goals,&lookup)){
|
|
continue;
|
|
}
|
|
|
|
should_update = 0;
|
|
// determine what image to set for each one (failed, satisfied, incomplete, etc)
|
|
switch(Mission_goals[idx].satisfied){
|
|
case GOAL_FAILED :
|
|
// determine if we should update the item
|
|
if((lookup.iImage != 4) && (lookup.iSelectedImage != 4)){
|
|
setting.iImage = 4;
|
|
setting.iSelectedImage = 4;
|
|
|
|
should_update = 1;
|
|
}
|
|
break;
|
|
case GOAL_COMPLETE :
|
|
// determine if we should update the item
|
|
if((lookup.iImage != 2) && (lookup.iSelectedImage != 2)){
|
|
setting.iImage = 2;
|
|
setting.iSelectedImage = 2;
|
|
|
|
should_update = 1;
|
|
}
|
|
break;
|
|
|
|
case GOAL_INCOMPLETE :
|
|
// determine if we should update the item
|
|
if((lookup.iImage != 1) && (lookup.iSelectedImage != 1)){
|
|
setting.iImage = 1;
|
|
setting.iSelectedImage = 1;
|
|
|
|
should_update = 1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// set the actual image
|
|
if(should_update){
|
|
setting.hItem = update_item;
|
|
TreeView_SetItem(Standalone_goals,&setting);
|
|
}
|
|
}
|
|
}
|
|
|
|
// set the framerate text box for this page
|
|
void std_multi_set_framerate(float f)
|
|
{
|
|
char fr[10];
|
|
|
|
// set the window text
|
|
sprintf(fr,"%.1f",f);
|
|
SetWindowText(Standalone_FPS,fr);
|
|
}
|
|
|
|
// clear all the controls for this page
|
|
void std_multi_clear_controls()
|
|
{
|
|
// clear out the mission name text static
|
|
SetWindowText(Standalone_mission_name,"");
|
|
|
|
// clear out the framerate text box
|
|
SetWindowText(Standalone_FPS,"");
|
|
|
|
// clear out the misison time text box
|
|
SetWindowText(Standalone_missiontime,"");
|
|
|
|
// clear out the netgame max players text box
|
|
SetWindowText(Std_ng_max_players,"");
|
|
|
|
// clear out the netgame max observer text box
|
|
SetWindowText(Std_ng_max_observers,"");
|
|
|
|
// clear out the netgame security text box
|
|
SetWindowText(Std_ng_security,"");
|
|
|
|
// clear out the netgame respawns # text box
|
|
SetWindowText(Std_ng_respawns,"");
|
|
|
|
// clear the goal tree control
|
|
std_multi_setup_goal_tree();
|
|
}
|
|
|
|
// update the netgame information area controls with the current Netgame settings
|
|
void std_multi_update_netgame_info_controls()
|
|
{
|
|
char buf[40];
|
|
|
|
// update the
|
|
|
|
// update the max players control
|
|
sprintf(buf,"%d",Netgame.max_players);
|
|
SetWindowText(Std_ng_max_players,buf);
|
|
|
|
// update the max observers control
|
|
sprintf(buf,"%d",Netgame.options.max_observers);
|
|
SetWindowText(Std_ng_max_observers,buf);
|
|
|
|
// update the netgame security control
|
|
sprintf(buf,"%d",Netgame.security);
|
|
SetWindowText(Std_ng_security,buf);
|
|
|
|
// update the netgame respawns # control
|
|
sprintf(buf,"%d",Netgame.respawn);
|
|
SetWindowText(Std_ng_respawns,buf);
|
|
}
|
|
|
|
// handle the user sliding the framerate cap scrollbar around
|
|
void std_multi_handle_framecap_scroll(HWND ctrl)
|
|
{
|
|
int pos;
|
|
char pos_text[10];
|
|
|
|
// determine where the slider now is
|
|
pos = SendMessage(ctrl,TBM_GETPOS,(WPARAM)0,(LPARAM)0);
|
|
|
|
// update the text display
|
|
sprintf(pos_text,"%d",pos);
|
|
SetWindowText(GetDlgItem(Page_handles[MULTIPLAYER_PAGE],(int)MAKEINTRESOURCE(IDC_FRAMECAP_STATIC)),pos_text);
|
|
|
|
// set the framecap var
|
|
Multi_options_g.std_framecap = pos;
|
|
}
|
|
|
|
// initialize the framerate cap slide control
|
|
void std_multi_init_framecap_slider(HWND hwndDlg)
|
|
{
|
|
WPARAM wp;
|
|
LPARAM lp;
|
|
|
|
// create the trackbar object
|
|
Framecap_trackbar = CreateWindowEx(0,TRACKBAR_CLASS,NULL,WS_CHILD | WS_VISIBLE,
|
|
10,10,300,30,hwndDlg,NULL,GetModuleHandle(NULL),NULL);
|
|
|
|
// set the range of the framerate cap
|
|
wp = (WPARAM)(BOOL)TRUE;
|
|
lp = (LPARAM)MAKELONG(1, 100);
|
|
SendMessage(Framecap_trackbar,TBM_SETRANGE,wp,lp);
|
|
|
|
// set the default framerate cap the be the standalone default
|
|
wp = (WPARAM)(BOOL)TRUE;
|
|
lp = (LPARAM)(LONG)30;
|
|
SendMessage(Framecap_trackbar,TBM_SETPOS,wp,lp);
|
|
|
|
// call this to update the standalone framecap on this first run
|
|
std_multi_handle_framecap_scroll(Framecap_trackbar);
|
|
}
|
|
|
|
// initialize all the controls for this page
|
|
void std_multi_init_multi_controls(HWND hwndDlg)
|
|
{
|
|
HBITMAP ref;
|
|
COLORREF mask;
|
|
|
|
// create the framecap slider
|
|
std_multi_init_framecap_slider(hwndDlg);
|
|
|
|
// create the framerate display text box
|
|
Standalone_FPS = GetDlgItem(hwndDlg,(int)MAKEINTRESOURCE(IDC_STANDALONE_FPS));
|
|
|
|
// create the missiontime text box
|
|
Standalone_missiontime = GetDlgItem(hwndDlg,(int)MAKEINTRESOURCE(IDC_STANDALONE_MTIME));
|
|
|
|
// create the mission name text box
|
|
Standalone_mission_name = GetDlgItem(hwndDlg,(int)MAKEINTRESOURCE(IDC_MISSION_NAME));
|
|
|
|
// create the netgame max players text box
|
|
Std_ng_max_players = GetDlgItem(hwndDlg,(int)MAKEINTRESOURCE(IDC_NG_MAXPLAYERS));
|
|
|
|
// create the netgame max observers text box
|
|
Std_ng_max_observers = GetDlgItem(hwndDlg,(int)MAKEINTRESOURCE(IDC_NG_MAXOBSERVERS));
|
|
|
|
// create the netgame security text box
|
|
Std_ng_security = GetDlgItem(hwndDlg,(int)MAKEINTRESOURCE(IDC_NG_SECURITY));
|
|
|
|
// create the netgame respawns # text box
|
|
Std_ng_respawns = GetDlgItem(hwndDlg,(int)MAKEINTRESOURCE(IDC_NG_RESPAWNS));
|
|
|
|
// load the goal tree-view bitmaps
|
|
Goal_bitmaps = ImageList_Create(16,16,ILC_COLOR4 | ILC_MASK,5,0);
|
|
|
|
mask = 0x00ff00ff;
|
|
ref = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_GOAL_ORD));
|
|
ImageList_AddMasked(Goal_bitmaps,ref,mask);
|
|
|
|
ref = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_GOAL_INC));
|
|
mask = 0x00ffffff;
|
|
ImageList_AddMasked(Goal_bitmaps,ref,mask);
|
|
|
|
ref = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_GOAL_COMP));
|
|
mask = 0x00ffffff;
|
|
ImageList_AddMasked(Goal_bitmaps,ref,mask);
|
|
|
|
ref = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_GOAL_NONE));
|
|
mask = 0x00ffffff;
|
|
ImageList_AddMasked(Goal_bitmaps,ref,mask);
|
|
|
|
ref = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_GOAL_FAIL));
|
|
mask = 0x00ffffff;
|
|
ImageList_AddMasked(Goal_bitmaps,ref,mask);
|
|
|
|
// create the tree view control and associate its image list
|
|
Standalone_goals = CreateWindowEx(0, WC_TREEVIEW, XSTR("Tree View",921),
|
|
WS_VISIBLE | WS_CHILD | WS_BORDER | TVS_HASLINES,
|
|
GOALVIEW_X,GOALVIEW_Y,GOALVIEW_W,GOALVIEW_H,
|
|
hwndDlg, NULL, GetModuleHandle(NULL), NULL);
|
|
TreeView_SetImageList(Standalone_goals,Goal_bitmaps,TVSIL_NORMAL);
|
|
}
|
|
|
|
// return the handle to the item matching the given parameters
|
|
HTREEITEM std_multi_get_goal_item(char *goal_string,int type)
|
|
{
|
|
HTREEITEM ret,moveup;
|
|
TV_ITEM lookup;
|
|
int done;
|
|
char goal_name_text[NAME_LENGTH+1];
|
|
|
|
// look under the correct root item
|
|
lookup.mask = TVIF_TEXT;
|
|
lookup.pszText = goal_name_text;
|
|
lookup.cchTextMax = NAME_LENGTH;
|
|
strcpy(lookup.pszText,goal_string);
|
|
|
|
// search through all the items
|
|
done=0;
|
|
ret=NULL;
|
|
moveup = TreeView_GetChild(Standalone_goals,Goal_items[type]);
|
|
while(!done && moveup!=NULL){
|
|
lookup.hItem = moveup;
|
|
TreeView_GetItem(Standalone_goals,&lookup);
|
|
if(strcmp(lookup.pszText,goal_string)==0){
|
|
ret = moveup;
|
|
done=1;
|
|
}
|
|
if(!done){
|
|
moveup = TreeView_GetNextItem(Standalone_goals,moveup,TVGN_NEXT);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// message handler for the multiplayer tab
|
|
BOOL CALLBACK multi_proc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)
|
|
{
|
|
switch(uMsg){
|
|
// initialize the page
|
|
case WM_INITDIALOG:
|
|
// set the page handle
|
|
Page_handles[MULTIPLAYER_PAGE] = hwndDlg;
|
|
|
|
// initialize all the controls
|
|
std_multi_init_multi_controls(hwndDlg);
|
|
return 1;
|
|
break;
|
|
|
|
// a scroll message from the framerate cap trackbar
|
|
case WM_HSCROLL:
|
|
std_multi_handle_framecap_scroll((HWND)lParam);
|
|
return 1;
|
|
break;
|
|
|
|
// notification that this page has been set as active
|
|
case WM_NOTIFY :
|
|
// setup our own internal vars
|
|
if(((LPNMHDR)lParam)->code == PSN_SETACTIVE){
|
|
Active_standalone_page = MULTIPLAYER_PAGE;
|
|
} else if ( (((LPNMHDR)lParam)->code == PSN_APPLY) || (((LPNMHDR)lParam)->code == PSN_RESET) ) {
|
|
// PostMessage( Psht, WM_DESTROY, 0, 0 );
|
|
gameseq_post_event(GS_EVENT_QUIT_GAME);
|
|
}
|
|
break;
|
|
|
|
default :
|
|
return 0;
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------
|
|
// player info page/tab functions
|
|
//
|
|
|
|
#define MAX_PLAYER_STAT_FIELDS 11 // the # of stats fields for a given set
|
|
static HWND Player_name_list; // the listbox control with player callsigns in it
|
|
static HWND Player_ship_type; // the current player's ship type
|
|
static HWND Player_ping_time; // the current player's ping time
|
|
static HWND Player_stats[MAX_PLAYER_STAT_FIELDS]; // text boxes for player alltime statistics info
|
|
static HWND Player_mstats[MAX_PLAYER_STAT_FIELDS]; // text boxes for player mission statistics info
|
|
|
|
// sprintf and set window text to the passed int
|
|
#define STD_ADDSTRING(hwnd,val) { sprintf(txt,"%d",(int)val); SetWindowText(hwnd,txt); }
|
|
|
|
// intialize all the controls in the player info tab
|
|
void std_pinfo_init_player_info_controls(HWND hwndDlg);
|
|
|
|
// returns true or false depending on whether the passed netplayer is the currently selected guy
|
|
int std_pinfo_player_is_active(net_player *p);
|
|
|
|
// start displaying info for the passed player on this page
|
|
void std_pinfo_display_player_info(net_player *p)
|
|
{
|
|
char txt[40];
|
|
|
|
// set his ship type
|
|
SetWindowText(Player_ship_type,Ship_info[p->p_info.ship_class].name);
|
|
|
|
// display his ping time
|
|
std_pinfo_update_ping(p);
|
|
|
|
// his alltime stats
|
|
scoring_struct *ptr = &p->player->stats;
|
|
STD_ADDSTRING(Player_stats[0],ptr->p_shots_fired);
|
|
STD_ADDSTRING(Player_stats[1],ptr->p_shots_hit);
|
|
STD_ADDSTRING(Player_stats[2],ptr->p_bonehead_hits);
|
|
STD_ADDSTRING(Player_stats[3],
|
|
(int)((float)100.0*((float)ptr->p_shots_hit/(float)ptr->p_shots_fired)));
|
|
STD_ADDSTRING(Player_stats[4],
|
|
(int)((float)100.0*((float)ptr->p_bonehead_hits/(float)ptr->p_shots_fired)));
|
|
STD_ADDSTRING(Player_stats[5],ptr->s_shots_fired);
|
|
STD_ADDSTRING(Player_stats[6],ptr->s_shots_hit);
|
|
STD_ADDSTRING(Player_stats[7],ptr->s_bonehead_hits);
|
|
STD_ADDSTRING(Player_stats[8],
|
|
(int)((float)100.0*((float)ptr->s_shots_hit/(float)ptr->s_shots_fired)));
|
|
STD_ADDSTRING(Player_stats[9],
|
|
(int)((float)100.0*((float)ptr->s_bonehead_hits/(float)ptr->s_shots_fired)));
|
|
STD_ADDSTRING(Player_stats[10],ptr->assists);
|
|
|
|
// his stats for the current mission
|
|
STD_ADDSTRING(Player_mstats[0],ptr->mp_shots_fired);
|
|
STD_ADDSTRING(Player_mstats[1],ptr->mp_shots_hit);
|
|
STD_ADDSTRING(Player_mstats[2],ptr->mp_bonehead_hits);
|
|
STD_ADDSTRING(Player_mstats[3],
|
|
(int)((float)100.0*((float)ptr->mp_shots_hit/(float)ptr->mp_shots_fired)));
|
|
STD_ADDSTRING(Player_mstats[4],
|
|
(int)((float)100.0*((float)ptr->mp_bonehead_hits/(float)ptr->mp_shots_fired)));
|
|
STD_ADDSTRING(Player_mstats[5],ptr->ms_shots_fired);
|
|
STD_ADDSTRING(Player_mstats[6],ptr->ms_shots_hit);
|
|
STD_ADDSTRING(Player_mstats[7],ptr->ms_bonehead_hits);
|
|
STD_ADDSTRING(Player_mstats[8],
|
|
(int)((float)100.0*((float)ptr->ms_shots_hit/(float)ptr->ms_shots_fired)));
|
|
STD_ADDSTRING(Player_mstats[9],
|
|
(int)((float)100.0*((float)ptr->ms_bonehead_hits/(float)ptr->ms_shots_fired)));
|
|
STD_ADDSTRING(Player_mstats[10],ptr->m_assists);
|
|
}
|
|
|
|
// check to see if this player is the one being displayed, and if so, then update the display info
|
|
// return 1 if the player was updated
|
|
int std_pinfo_maybe_update_player_info(net_player *p)
|
|
{
|
|
// only update if this is the currently active player
|
|
if(std_pinfo_player_is_active(p)){
|
|
std_pinfo_display_player_info(p);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// add a player to the list on the player info page
|
|
void std_pinfo_add_player_list_item(net_player *p)
|
|
{
|
|
// add the item
|
|
SendMessage(Player_name_list,CB_ADDSTRING,(WPARAM)0,(LPARAM)(LPCTSTR)p->player->callsign);
|
|
|
|
// if this is the first item on the list, then select it and display it
|
|
if(SendMessage(Player_name_list,CB_GETCOUNT,(WPARAM)0,(LPARAM)0) == 1){
|
|
// select the item
|
|
SendMessage(Player_name_list,CB_SETCURSEL,(WPARAM)0,(LPARAM)0);
|
|
|
|
// display this players info
|
|
std_pinfo_display_player_info(p);
|
|
}
|
|
}
|
|
|
|
// remove a player from the list on the player info page
|
|
void std_pinfo_remove_player_list_item(net_player *p)
|
|
{
|
|
int loc;
|
|
|
|
// lookup thie player
|
|
loc = SendMessage(Player_name_list,CB_FINDSTRINGEXACT,(WPARAM)-1,(LPARAM)(LPCTSTR)p->player->callsign);
|
|
|
|
// if we found the entry, then delete it
|
|
if(loc!=CB_ERR){
|
|
SendMessage(Player_name_list,CB_DELETESTRING,(WPARAM)loc,(LPARAM)0);
|
|
}
|
|
}
|
|
|
|
// update the ping display for this player
|
|
void std_pinfo_update_ping(net_player *p)
|
|
{
|
|
char sml_ping[30];
|
|
|
|
// chop it off at pings greater than 1 second
|
|
if(p->s_info.ping.ping_avg > 1000){
|
|
strcpy(sml_ping,XSTR("> 1 sec",914));
|
|
}
|
|
// use the ping itself
|
|
else {
|
|
sprintf(sml_ping,"%d",p->s_info.ping.ping_avg);
|
|
strcat(sml_ping,XSTR(" ms",915));
|
|
}
|
|
|
|
SetWindowText(Player_ping_time,sml_ping);
|
|
}
|
|
|
|
// clear the player info page controls
|
|
void std_pinfo_clear_controls()
|
|
{
|
|
int idx;
|
|
|
|
// clear the player selection list
|
|
SendMessage(Player_name_list,CB_RESETCONTENT,(WPARAM)0,(LPARAM)0);
|
|
|
|
// clear out misc items
|
|
SetWindowText(Player_ship_type,"");
|
|
SetWindowText(Player_ping_time,"");
|
|
|
|
// clear out the player stats
|
|
for(idx=0;idx<MAX_PLAYER_STAT_FIELDS;idx++){
|
|
SetWindowText(Player_stats[idx],"");
|
|
SetWindowText(Player_mstats[idx],"");
|
|
}
|
|
}
|
|
|
|
// intialize all the controls in the player info tab
|
|
void std_pinfo_init_player_info_controls(HWND hwndDlg)
|
|
{
|
|
// create the player callsign listbox
|
|
Player_name_list = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_PLAYER_LIST));
|
|
|
|
// create the player ship type text box
|
|
Player_ship_type = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_PSHIP_TYPE));
|
|
|
|
// create the player ping time text box
|
|
Player_ping_time = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_PING_TIME));
|
|
|
|
// initialize the various and sundry statistics text controls (alltime)
|
|
Player_stats[0] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_PSHOTS));
|
|
Player_stats[1] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_PHITS));
|
|
Player_stats[2] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_PBHHITS));
|
|
Player_stats[3] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_PPCT));
|
|
Player_stats[4] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_PBHPCT));
|
|
Player_stats[5] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_SSHOTS));
|
|
Player_stats[6] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_SECHITS));
|
|
Player_stats[7] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_SBHHITS));
|
|
Player_stats[8] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_SPCT));
|
|
Player_stats[9] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_SBHPCT));
|
|
Player_stats[10] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_ASSISTS));
|
|
|
|
// initialize the various and sundry statistics text controls (this mission)
|
|
Player_mstats[0] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MPSHOTS));
|
|
Player_mstats[1] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MPHITS));
|
|
Player_mstats[2] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MPBHHITS));
|
|
Player_mstats[3] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MPPCT));
|
|
Player_mstats[4] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MPBHPCT));
|
|
Player_mstats[5] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MSSHOTS));
|
|
Player_mstats[6] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MSECHITS));
|
|
Player_mstats[7] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MSBHHITS));
|
|
Player_mstats[8] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MSPCT));
|
|
Player_mstats[9] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MSBHPCT));
|
|
Player_mstats[10] = GetDlgItem(Page_handles[PLAYER_INFO_PAGE],(int)MAKEINTRESOURCE(IDC_MASSISTS));
|
|
}
|
|
|
|
// returns true or false depending on whether the passed netplayer is the currently selected guy
|
|
int std_pinfo_player_is_active(net_player *p)
|
|
{
|
|
int sel;
|
|
char player[40];
|
|
|
|
// get the index of the currently selected item
|
|
sel = SendMessage(Player_name_list,CB_GETCURSEL,(WPARAM)0,(LPARAM)0);
|
|
|
|
// if we didn't find the item, return a 0 length string
|
|
if(sel == LB_ERR){
|
|
return 0;
|
|
}
|
|
|
|
// otherwise, get the callsign of the given player
|
|
SendMessage(Player_name_list,CB_GETLBTEXT,(WPARAM)sel,(LPARAM)player);
|
|
|
|
// if there is a valid player selected and he's the guy we want
|
|
return ((strlen(player) != 0) && (strcmp(p->player->callsign,player) == 0)) ? 1 : 0;
|
|
}
|
|
|
|
// message handler for the player info tab
|
|
BOOL CALLBACK player_info_proc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)
|
|
{
|
|
int val,player_num;
|
|
char callsign[40];
|
|
|
|
switch(uMsg){
|
|
// initialize the dialog
|
|
case WM_INITDIALOG:
|
|
// set the page handle
|
|
Page_handles[PLAYER_INFO_PAGE] = hwndDlg;
|
|
|
|
// intialize all the control
|
|
std_pinfo_init_player_info_controls(hwndDlg);
|
|
return 1;
|
|
break;
|
|
|
|
// a command message of some kind
|
|
case WM_COMMAND:
|
|
switch(HIWORD(wParam)){
|
|
// a listbox selection change message
|
|
case CBN_SELCHANGE :
|
|
// get the newly selected item
|
|
val = SendMessage(Player_name_list,CB_GETCURSEL,(WPARAM)0,(LPARAM)0);
|
|
if(val!=CB_ERR){
|
|
// get the callsign
|
|
if(SendMessage(Player_name_list,CB_GETLBTEXT,(WPARAM)val,(LPARAM)callsign) != CB_ERR){
|
|
// lookup the player
|
|
player_num = multi_find_player_by_callsign(callsign);
|
|
|
|
// if we found him then display his info
|
|
if(player_num != -1){
|
|
std_pinfo_display_player_info(&Net_players[player_num]);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
// a notification message
|
|
case WM_NOTIFY :
|
|
// set our page to be the active one
|
|
if(((LPNMHDR)lParam)->code == PSN_SETACTIVE){
|
|
Active_standalone_page = PLAYER_INFO_PAGE;
|
|
} else if ( (((LPNMHDR)lParam)->code == PSN_APPLY) || (((LPNMHDR)lParam)->code == PSN_RESET) ) {
|
|
PostMessage( Psht, WM_DESTROY, 0, 0 );
|
|
}
|
|
break;
|
|
|
|
default :
|
|
return 0;
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------
|
|
// player god stuff page/tab functions
|
|
//
|
|
|
|
#define GODSTUFF_MAX_ITEMS 19 // how many items we can fit on the chatbox at one time
|
|
|
|
static HWND God_player_list; // the listbox of player callsigns
|
|
static HWND Godstuff_fps; // the framerate text box
|
|
static HWND Godstuff_broadcast_text; // the text input box for sending messages to players
|
|
static HWND Godstuff_broadcast_button; // the button to send the text messages
|
|
static HWND Godstuff_player_messages; // handle to the list box containing player chatter
|
|
|
|
// initialize all the controls in the godstuff tab
|
|
void std_gs_init_godstuff_controls(HWND hwndDlg);
|
|
|
|
// add a player to the listbox on the godstuff page
|
|
void std_gs_add_god_player(net_player *p)
|
|
{
|
|
// add the item
|
|
SendMessage(God_player_list,CB_ADDSTRING,(WPARAM)0,(LPARAM)(LPCTSTR)p->player->callsign);
|
|
|
|
// if this is the first item on the list, then select it
|
|
if(SendMessage(God_player_list,CB_GETCOUNT,(WPARAM)0,(LPARAM)0) == 1){
|
|
// select the item
|
|
SendMessage(God_player_list,CB_SETCURSEL,(WPARAM)0,(LPARAM)0);
|
|
}
|
|
}
|
|
|
|
// remove a player from the listbox on the godstuff page
|
|
void std_gs_remove_god_player(net_player *p)
|
|
{
|
|
int loc;
|
|
|
|
// lookup the player
|
|
loc = SendMessage(God_player_list,CB_FINDSTRINGEXACT,(WPARAM)-1,(LPARAM)(LPCTSTR)p->player->callsign);
|
|
|
|
// if we found him, them delete the item
|
|
if(loc!=CB_ERR){
|
|
SendMessage(God_player_list,CB_DELETESTRING,(WPARAM)loc,(LPARAM)0);
|
|
}
|
|
}
|
|
|
|
// send a message as if the standalone were a player
|
|
void std_gs_send_godstuff_message()
|
|
{
|
|
char txt[256];
|
|
|
|
// get the text in the edit control
|
|
memset(txt,0,256);
|
|
txt[0]=120;
|
|
SendMessage(Godstuff_broadcast_text,EM_GETLINE,(WPARAM)0,(LPARAM)&txt[0]);
|
|
|
|
// if the string is not zero length
|
|
if(strlen(txt) > 0){
|
|
// send a game chat packet
|
|
send_game_chat_packet(Net_player, txt, MULTI_MSG_ALL,NULL);
|
|
|
|
// add the text to our own control
|
|
std_add_chat_text(txt, MY_NET_PLAYER_NUM,1);
|
|
|
|
// clear the text control
|
|
SetWindowText(Godstuff_broadcast_text, "");
|
|
}
|
|
}
|
|
|
|
// set the framerate text box for this page
|
|
void std_gs_set_framerate(float f)
|
|
{
|
|
char fr[10];
|
|
|
|
// set the window text
|
|
sprintf(fr,"%.1f",f);
|
|
SetWindowText(Godstuff_fps,fr);
|
|
}
|
|
|
|
// clear the godstuff page controlsv
|
|
void std_gs_clear_controls()
|
|
{
|
|
// clear the framerate area
|
|
SetWindowText(Godstuff_fps, "0");
|
|
|
|
// clear the text area
|
|
SetWindowText(Godstuff_broadcast_text,"");
|
|
|
|
// reset the combo box
|
|
SendMessage(God_player_list, CB_RESETCONTENT, (WPARAM)0, (LPARAM)0);
|
|
|
|
// clear the player chatter listbox
|
|
SendMessage(Godstuff_player_messages, LB_RESETCONTENT, (WPARAM)0, (LPARAM)0);
|
|
}
|
|
|
|
// initialize all the controls in the godstuff tab
|
|
void std_gs_init_godstuff_controls(HWND hwndDlg)
|
|
{
|
|
// initialize the player listbox control
|
|
God_player_list = GetDlgItem(Page_handles[GODSTUFF_PAGE], (int)MAKEINTRESOURCE(IDC_PLAYER_GOD_LIST));
|
|
|
|
// initialize the framerate text box
|
|
Godstuff_fps = GetDlgItem(Page_handles[GODSTUFF_PAGE], (int)MAKEINTRESOURCE(IDC_GODSTUFF_FPS));
|
|
|
|
// initialize the messaging edit control
|
|
Godstuff_broadcast_text = GetDlgItem(Page_handles[GODSTUFF_PAGE], (int)MAKEINTRESOURCE(IDC_GODSTUFF_BROADCAST));
|
|
SendMessage(Godstuff_broadcast_text, EM_SETLIMITTEXT, (WPARAM)CHATBOX_MAX_LEN, (LPARAM)0);
|
|
SendMessage(Godstuff_broadcast_text, EM_FMTLINES, (WPARAM)TRUE, (LPARAM)0);
|
|
|
|
// create the player chatter list box
|
|
Godstuff_player_messages = GetDlgItem(Page_handles[GODSTUFF_PAGE], (int)MAKEINTRESOURCE(IDC_GOD_CHAT));
|
|
|
|
// initialize the message broadcast button
|
|
Godstuff_broadcast_button = GetDlgItem(Page_handles[GODSTUFF_PAGE], (int)MAKEINTRESOURCE(IDC_GODSTUFF_SENDMESS));
|
|
// hide the button -- we can now process return key
|
|
ShowWindow(Godstuff_broadcast_button, SW_HIDE);
|
|
|
|
}
|
|
|
|
// message handler for the godstuff tab
|
|
BOOL CALLBACK godstuff_proc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch(uMsg){
|
|
// initialize the dialog
|
|
case WM_INITDIALOG:
|
|
// setup the page handle
|
|
Page_handles[GODSTUFF_PAGE] = hwndDlg;
|
|
|
|
// initialize the controls for this page
|
|
std_gs_init_godstuff_controls(hwndDlg);
|
|
return 1;
|
|
break;
|
|
|
|
// a notification message
|
|
case WM_NOTIFY :
|
|
// set this page to be the currently active one
|
|
if(((LPNMHDR)lParam)->code == PSN_SETACTIVE){
|
|
Active_standalone_page = GODSTUFF_PAGE;
|
|
} else if ( (((LPNMHDR)lParam)->code == PSN_APPLY) || (((LPNMHDR)lParam)->code == PSN_RESET) ) {
|
|
PostMessage( Psht, WM_DESTROY, 0, 0 );
|
|
}
|
|
break;
|
|
|
|
|
|
// a command message of some kind
|
|
case WM_COMMAND:
|
|
switch(HIWORD(wParam)){
|
|
// a button click
|
|
case BN_CLICKED :
|
|
switch(LOWORD(wParam)){
|
|
// send the message to the player
|
|
case IDC_GODSTUFF_SENDMESS :
|
|
std_gs_send_godstuff_message();
|
|
break;
|
|
}
|
|
break;
|
|
|
|
}
|
|
break;
|
|
|
|
default :
|
|
return 0;
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------
|
|
// debug page/tab functions
|
|
//
|
|
|
|
static HWND Standalone_state_string; // the text control box
|
|
|
|
// initialize the controls for the debug page
|
|
void std_debug_init_debug_controls(HWND hwndDlg);
|
|
|
|
// set the text on the standalones state indicator box
|
|
void std_debug_set_standalone_state_string(char *str)
|
|
{
|
|
// set the text
|
|
SetWindowText(Standalone_state_string,str);
|
|
}
|
|
|
|
// clear the debug page controls
|
|
void std_debug_clear_controls()
|
|
{
|
|
// set the current debug state
|
|
std_debug_set_standalone_state_string("");
|
|
}
|
|
|
|
// initialize the controls for the debug page
|
|
void std_debug_init_debug_controls(HWND hwndDlg)
|
|
{
|
|
// create the state string text box
|
|
Standalone_state_string = GetDlgItem(hwndDlg,(int)MAKEINTRESOURCE(IDC_STANDALONE_STATE));
|
|
|
|
// standalone state indicator
|
|
SetWindowText(Standalone_state_string,"");
|
|
}
|
|
|
|
// message handler for the godstuff tab
|
|
BOOL CALLBACK debug_proc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)
|
|
{
|
|
switch(uMsg){
|
|
// initialize the dialog
|
|
case WM_INITDIALOG:
|
|
// setup the page handle
|
|
Page_handles[DEBUG_PAGE] = hwndDlg;
|
|
|
|
// intialize the controls for this page
|
|
std_debug_init_debug_controls(hwndDlg);
|
|
return 1;
|
|
break;
|
|
|
|
// a notification message
|
|
case WM_NOTIFY :
|
|
// set the currently active page to this one
|
|
if(((LPNMHDR)lParam)->code == PSN_SETACTIVE){
|
|
Active_standalone_page = DEBUG_PAGE;
|
|
} else if ( (((LPNMHDR)lParam)->code == PSN_APPLY) || (((LPNMHDR)lParam)->code == PSN_RESET) ) {
|
|
PostMessage( Psht, WM_DESTROY, 0, 0 );
|
|
}
|
|
break;
|
|
|
|
default :
|
|
return 0;
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------
|
|
// general functions
|
|
//
|
|
|
|
// add a player and take care of updating all gui/data details
|
|
void std_add_player(net_player *p)
|
|
{
|
|
char ip_string[60];
|
|
|
|
// get his ip string and add it to the list
|
|
psnet_addr_to_string(ip_string,&p->p_info.addr);
|
|
std_connect_add_ip_string(ip_string);
|
|
|
|
// add to the player info player list box, and update his info
|
|
std_pinfo_add_player_list_item(p);
|
|
std_pinfo_maybe_update_player_info(p);
|
|
|
|
// add to the god stuff player list box
|
|
std_gs_add_god_player(p);
|
|
|
|
// check to see if this guy is the host.
|
|
std_connect_set_host_connect_status();
|
|
|
|
// set the connection count
|
|
std_connect_set_connect_count();
|
|
}
|
|
|
|
// remove a player and take care of updateing all gui/data details
|
|
int std_remove_player(net_player *p)
|
|
{
|
|
int count;
|
|
char ip_string[60];
|
|
|
|
// determine his ip string and remove it from the list
|
|
psnet_addr_to_string(ip_string,&p->p_info.addr);
|
|
std_connect_remove_ip_string(ip_string);
|
|
|
|
// remove from the player info player list box
|
|
std_pinfo_remove_player_list_item(p);
|
|
|
|
// remove from the godstuff list box
|
|
std_gs_remove_god_player(p);
|
|
|
|
// update the host connect count
|
|
std_connect_set_host_connect_status();
|
|
|
|
// update the currently connected players
|
|
count = std_connect_set_connect_count();
|
|
|
|
if(count == 0){
|
|
// multi_standalone_quit_game();
|
|
multi_quit_game(PROMPT_NONE);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// set any relevant controls which display the framerate of the standalone
|
|
void std_set_standalone_fps(float fps)
|
|
{
|
|
// set the framerate in the multiplayer dialog
|
|
std_multi_set_framerate(fps);
|
|
|
|
// set the framerate in the godstuff dialog
|
|
std_gs_set_framerate(fps);
|
|
}
|
|
|
|
// update any relveant controls which display the ping for the given player
|
|
void std_update_player_ping(net_player *p)
|
|
{
|
|
// update the ping on the connect page
|
|
std_connect_update_ping(p);
|
|
|
|
// update the ping on the player info page
|
|
std_pinfo_update_ping(p);
|
|
}
|
|
|
|
// reset everything in the standalone gui (all the controls)
|
|
void std_reset_standalone_gui()
|
|
{
|
|
// clear the connect page controls
|
|
std_connect_clear_controls();
|
|
|
|
// clear the multi page controls
|
|
std_multi_clear_controls();
|
|
|
|
// clear the player info page controls
|
|
std_pinfo_clear_controls();
|
|
|
|
// clear the godstuff page controls
|
|
std_gs_clear_controls();
|
|
|
|
// clear the debug page controls
|
|
std_debug_clear_controls();
|
|
|
|
// set all framerate displays to 0
|
|
std_set_standalone_fps((float)0);
|
|
|
|
// set the mission time
|
|
std_multi_set_standalone_missiontime((float)0);
|
|
|
|
// reset the stats update timestamp
|
|
Standalone_stats_stamp = -1;
|
|
|
|
// reset the netgame info timestamp
|
|
Standalone_ng_stamp = -1;
|
|
}
|
|
|
|
// do any gui related issues on the standalone (like periodically updating player stats, etc...)
|
|
void std_do_gui_frame()
|
|
{
|
|
int idx;
|
|
|
|
// check to see if the timestamp for updating player selected stats has popped
|
|
if((Standalone_stats_stamp == -1) || timestamp_elapsed(Standalone_stats_stamp)){
|
|
// reset the timestamp
|
|
Standalone_stats_stamp = timestamp(STD_STATS_UPDATE_TIME);
|
|
|
|
// update any player currently selected
|
|
// there's probably a nicer way to do this, but...
|
|
for(idx=0;idx<MAX_PLAYERS;idx++){
|
|
if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
|
|
if(std_pinfo_maybe_update_player_info(&Net_players[idx])){
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// check to see if the timestamp for updating the netgame information controls has popped
|
|
if((Standalone_ng_stamp == -1) || timestamp_elapsed(Standalone_ng_stamp)){
|
|
// reset the timestamp
|
|
Standalone_ng_stamp = timestamp(STD_NG_UPDATE_TIME);
|
|
|
|
// update the controls
|
|
std_multi_update_netgame_info_controls();
|
|
}
|
|
}
|
|
|
|
// notify the user that the standalone has failed to login to the tracker on startup
|
|
void std_notify_tracker_login_fail()
|
|
{
|
|
MessageBox(Psht,XSTR("The standalone server has failed to log in to Parallax Online!",922),XSTR("VMT Warning!",923),MB_OK);
|
|
}
|
|
|
|
// attempt to log the standalone into the tracker
|
|
void std_tracker_login()
|
|
{
|
|
}
|
|
|
|
// reset all stand gui timestamps
|
|
void std_reset_timestamps()
|
|
{
|
|
// reset the stats update stamp
|
|
Standalone_stats_stamp = timestamp(STD_STATS_UPDATE_TIME);
|
|
|
|
// reset the netgame controls update timestamp
|
|
Standalone_ng_stamp = timestamp(STD_NG_UPDATE_TIME);
|
|
}
|
|
|
|
// add a line of text chat to the standalone
|
|
void std_add_chat_text(char *text,int player_index,int add_id)
|
|
{
|
|
int num_items,ret_val;
|
|
char format[512];
|
|
|
|
// invalid player ?
|
|
if(player_index == -1){
|
|
return;
|
|
}
|
|
|
|
// format the chat text nicely
|
|
if(add_id){
|
|
if(MULTI_STANDALONE(Net_players[player_index])){
|
|
sprintf(format,XSTR("<SERVER> %s",924),text);
|
|
} else {
|
|
sprintf(format,"%s: %s",Net_players[player_index].player->callsign,text);
|
|
}
|
|
} else {
|
|
strcpy(format,text);
|
|
}
|
|
|
|
// insert the text string into the godstuff chat box and scroll it down to the bottom
|
|
SendMessage(Godstuff_player_messages,LB_INSERTSTRING,(WPARAM)-1,(LPARAM)format);
|
|
num_items = SendMessage(Godstuff_player_messages,LB_GETCOUNT,(WPARAM)0,(LPARAM)0);
|
|
if(num_items > 19){
|
|
ret_val = SendMessage(Godstuff_player_messages,LB_SETTOPINDEX,(WPARAM)num_items - GODSTUFF_MAX_ITEMS,(LPARAM)0);
|
|
}
|
|
}
|
|
|
|
// if the standalone is host password protected
|
|
int std_is_host_passwd()
|
|
{
|
|
return (strlen(Multi_options_g.std_passwd) > 0) ? 1 : 0;
|
|
}
|
|
|
|
// change the default property sheet interface into something more useful
|
|
void std_mutate_sheet()
|
|
{
|
|
HWND ok_button = NULL;
|
|
HWND cancel_button = NULL;
|
|
HWND apply_button = NULL;
|
|
HWND help_button = NULL;
|
|
char lookup[512];
|
|
|
|
// get the buttons on the property sheet itself
|
|
HWND child = GetWindow(Psht,GW_CHILD);
|
|
while(child != NULL){
|
|
// get the text of the window
|
|
memset(lookup,0,512);
|
|
GetWindowText(child,lookup,511);
|
|
|
|
// if its the OK button
|
|
if(!stricmp(lookup,XSTR("ok",925))){
|
|
ok_button = child;
|
|
}
|
|
|
|
// if its the cancel button
|
|
if(!stricmp(lookup,XSTR("cancel",926))){
|
|
cancel_button = child;
|
|
}
|
|
|
|
// if its the apply button
|
|
if(!stricmp(lookup,XSTR("&apply",927))){
|
|
apply_button = child;
|
|
}
|
|
|
|
// if its the help button
|
|
if(!stricmp(lookup,XSTR("help",928))){
|
|
help_button = child;
|
|
}
|
|
|
|
child = GetWindow(child,GW_HWNDNEXT);
|
|
}
|
|
|
|
// kill em all
|
|
if(apply_button != NULL){
|
|
DestroyWindow(apply_button);
|
|
}
|
|
|
|
// rename the shutdown button and move it over a bit
|
|
if(ok_button != NULL){
|
|
// set the text
|
|
SetWindowText(ok_button,XSTR("Shutdown",929));
|
|
|
|
// move it
|
|
SetWindowPos(ok_button,
|
|
HWND_TOP,
|
|
Std_shutdown_coords[gr_screen.res][0],
|
|
Std_shutdown_coords[gr_screen.res][1],
|
|
0,0,
|
|
SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOZORDER
|
|
);
|
|
}
|
|
|
|
// kill em all
|
|
if(cancel_button != NULL){
|
|
DestroyWindow(cancel_button);
|
|
}
|
|
|
|
// kill em all
|
|
if(help_button != NULL){
|
|
DestroyWindow(help_button);
|
|
}
|
|
|
|
// now we want to mess with the titlebar controls
|
|
}
|
|
|
|
// if the given callsign is banned from the server
|
|
int std_player_is_banned(char *name)
|
|
{
|
|
int idx;
|
|
|
|
// go through the ban list
|
|
for(idx=0;idx<Standalone_ban_count;idx++){
|
|
if(!stricmp(name,Standalone_ban_list[idx])){
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// not banned
|
|
return 0;
|
|
}
|
|
|
|
// add a callsign to the ban list
|
|
void std_add_ban(char *name)
|
|
{
|
|
// if we've reached the max bans
|
|
if(Standalone_ban_count >= STANDALONE_MAX_BAN){
|
|
return;
|
|
}
|
|
|
|
// otherwise add it
|
|
memset(Standalone_ban_list[Standalone_ban_count],0,CALLSIGN_LEN+1);
|
|
strcpy(Standalone_ban_list[Standalone_ban_count++],name);
|
|
}
|
|
|
|
|
|
// -------------------------------------------------------------------------------
|
|
// property sheet/page creation and handling
|
|
//
|
|
|
|
void std_init_property_pages()
|
|
{
|
|
PROPSHEETPAGE *p;
|
|
|
|
// connect tab
|
|
p = &Pages[CONNECT_PAGE];
|
|
p->dwSize = sizeof(PROPSHEETPAGE);
|
|
p->dwFlags = PSP_DEFAULT;
|
|
p->hInstance = GetModuleHandle(NULL);
|
|
p->pszTemplate = MAKEINTRESOURCE(IDD_CONNECT);
|
|
p->pszIcon = NULL;
|
|
p->pfnDlgProc = (DLGPROC)connect_proc;
|
|
p->pszTitle = XSTR("Connections",930);
|
|
p->lParam = 0;
|
|
p->pfnCallback = NULL;
|
|
|
|
// multiplayer tab
|
|
p = &Pages[MULTIPLAYER_PAGE];
|
|
p->dwSize = sizeof(PROPSHEETPAGE);
|
|
p->dwFlags = PSP_DEFAULT;
|
|
p->hInstance = GetModuleHandle(NULL);
|
|
p->pszTemplate = MAKEINTRESOURCE(IDD_MULTI);
|
|
p->pszIcon = NULL;
|
|
p->pfnDlgProc = (DLGPROC)multi_proc;
|
|
p->pszTitle = XSTR("Multi-Player",931);
|
|
p->lParam = 0;
|
|
p->pfnCallback = NULL;
|
|
|
|
// player tab
|
|
p = &Pages[PLAYER_INFO_PAGE];
|
|
p->dwSize = sizeof(PROPSHEETPAGE);
|
|
p->dwFlags = PSP_DEFAULT;
|
|
p->hInstance = GetModuleHandle(NULL);
|
|
p->pszTemplate = MAKEINTRESOURCE(IDD_PLAYER_DIALOG);
|
|
p->pszIcon = NULL;
|
|
p->pfnDlgProc = (DLGPROC)player_info_proc;
|
|
p->pszTitle = XSTR("Player info",932);
|
|
p->lParam = 0;
|
|
p->pfnCallback = NULL;
|
|
|
|
// godstuff tab
|
|
p = &Pages[GODSTUFF_PAGE];
|
|
p->dwSize = sizeof(PROPSHEETPAGE);
|
|
p->dwFlags = PSP_DEFAULT;
|
|
p->hInstance = GetModuleHandle(NULL);
|
|
p->pszTemplate = MAKEINTRESOURCE(IDD_GODSTUFF);
|
|
p->pszIcon = NULL;
|
|
p->pfnDlgProc = (DLGPROC)godstuff_proc;
|
|
p->pszTitle = XSTR("God Stuff",933);
|
|
p->lParam = 0;
|
|
p->pfnCallback = NULL;
|
|
|
|
// debug tab
|
|
p = &Pages[DEBUG_PAGE];
|
|
p->dwSize = sizeof(PROPSHEETPAGE);
|
|
p->dwFlags = PSP_DEFAULT;
|
|
p->hInstance = GetModuleHandle(NULL);
|
|
p->pszTemplate = MAKEINTRESOURCE(IDD_DEBUG_DIALOG);
|
|
p->pszIcon = NULL;
|
|
p->pfnDlgProc = (DLGPROC)debug_proc;
|
|
p->pszTitle = XSTR("Debug",934);
|
|
p->lParam = 0;
|
|
p->pfnCallback = NULL;
|
|
}
|
|
|
|
// build a title string
|
|
void std_build_title_string(char *str)
|
|
{
|
|
char part1[256];
|
|
char cat[256];
|
|
char temp[256];
|
|
|
|
// build the version #
|
|
memset(part1, 0, 256);
|
|
memset(cat, 0, 256);
|
|
memset(temp, 0, 256);
|
|
|
|
sprintf(part1, "%s %d.", XSTR("Freespace Standalone",935), FS_VERSION_MAJOR);
|
|
sprintf(cat, "%d", FS_VERSION_MINOR);
|
|
strcat(part1, cat);
|
|
strcat(part1, ".");
|
|
sprintf(cat, "%d", FS_VERSION_BUILD);
|
|
strcat(part1, cat);
|
|
|
|
// first part
|
|
strcpy(str, part1);
|
|
|
|
#ifdef STANDALONE_ONLY_BUILD
|
|
sprintf(cat, " %s %d", "Release", STANDALONE_ONLY_RELEASE_VERSION);
|
|
strcat(str, cat);
|
|
#endif
|
|
}
|
|
|
|
// initialize the property sheet itself
|
|
HWND std_init_property_sheet(HWND hwndDlg)
|
|
{
|
|
LONG styles;
|
|
|
|
// initialize the property pages
|
|
std_init_property_pages();
|
|
|
|
// create the property sheet
|
|
Sheet.dwSize = sizeof(PROPSHEETHEADER);
|
|
Sheet.dwFlags = PSH_PROPSHEETPAGE | PSH_MODELESS | PSH_NOAPPLYNOW;
|
|
Sheet.hwndParent = hwndDlg;
|
|
Sheet.hInstance = GetModuleHandle(NULL);
|
|
Sheet.nPages = MAX_STANDALONE_PAGES;
|
|
|
|
// set the title bar appropriately
|
|
char title_str[512];
|
|
memset(title_str, 0, 512);
|
|
std_build_title_string(title_str);
|
|
Sheet.pszCaption = title_str;
|
|
|
|
Sheet.nStartPage = 0;
|
|
Sheet.ppsp = &Pages[0];
|
|
Sheet.pfnCallback = NULL;
|
|
Psht = (HWND)PropertySheet(&Sheet);
|
|
|
|
// set the window style to include a minimize button
|
|
//styles = GetWindowLong(Psht, GWL_STYLE );
|
|
//if ( styles != 0 ) {
|
|
// SetWindowLong(Psht, GWL_STYLE, styles | WS_MINIMIZEBOX );
|
|
//}
|
|
|
|
styles = GetWindowLong(Psht, GWL_EXSTYLE );
|
|
if ( styles != 0 ) {
|
|
SetWindowLong( Psht, GWL_EXSTYLE, (styles & ~WS_EX_CONTEXTHELP) );
|
|
}
|
|
|
|
memset(Multi_options_g.std_pname, 0, MAX_GAMENAME_LEN+1);
|
|
|
|
// change the default property sheet interface into something more useful
|
|
std_mutate_sheet();
|
|
|
|
// return a handle to this property sheet
|
|
return Psht;
|
|
}
|
|
|
|
extern int Lighting_flag;
|
|
|
|
BOOL std_create_standalone_window()
|
|
{
|
|
Standalone_hwnd = std_init_property_sheet(NULL);
|
|
|
|
// this is kind of a big-ass hack. But here's what it does. Property sheets only
|
|
// initialize their individual pages the first time (and ONLY the first time) they
|
|
// are selected. So before any of this happens, their control handles are bogus. So,
|
|
// by calling PropSheet_SetCurSel for all the pages, WM_INITDIALOG is sent to all of
|
|
// them, and their controls become valid. However, its kind of silly because each
|
|
// page will blink into existence for a second. I can't see another way arount this
|
|
// problem.
|
|
int idx;
|
|
for(idx=MAX_STANDALONE_PAGES-1;idx>=0;idx--){
|
|
PropSheet_SetCurSel(Psht,(HPROPSHEETPAGE)&Pages[idx],idx);
|
|
}
|
|
|
|
// main_window_inited = 1;
|
|
|
|
// turn off lighting effects
|
|
Lighting_flag = 0;
|
|
|
|
// turn off all sound and music
|
|
Cmdline_freespace_no_sound = 1;
|
|
Cmdline_freespace_no_music = 1;
|
|
|
|
// reset all standalone gui items
|
|
std_reset_standalone_gui();
|
|
|
|
// initialize the debug outwindow
|
|
#ifndef NDEBUG
|
|
outwnd_init();
|
|
#endif
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// just like the osapi version for the nonstandalone mode of Freespace
|
|
DWORD standalone_process(WORD lparam)
|
|
{
|
|
MSG msg;
|
|
|
|
if ( !std_create_standalone_window() )
|
|
return 0;
|
|
|
|
while (1) {
|
|
#if 0
|
|
if(PropSheet_GetCurrentPageHwnd(Psht)==NULL){
|
|
mprintf(("prop sheet is destroyed -- exiting\n"));
|
|
DestroyWindow(Psht);
|
|
PostQuitMessage(0);
|
|
os_close();
|
|
std_deinit_standalone();
|
|
break;
|
|
}
|
|
#endif
|
|
if (WaitMessage()) {
|
|
while(PeekMessage(&msg,0,0,0,PM_REMOVE)) {
|
|
|
|
// if the dialog should be destroyed, then exit.
|
|
if ( msg.message == WM_DESTROY ) {
|
|
DestroyWindow(Psht);
|
|
PostQuitMessage(0);
|
|
gameseq_post_event(GS_EVENT_QUIT_GAME);
|
|
return 0;
|
|
}
|
|
|
|
// see if the message is destined for the edit control, and what the message is.
|
|
// intercept if a return
|
|
if ( msg.hwnd == Godstuff_broadcast_text ) {
|
|
int virt_key;
|
|
|
|
virt_key = (int)msg.wParam;
|
|
if ( (msg.message == WM_KEYDOWN) && (virt_key == VK_RETURN) ) {
|
|
std_gs_send_godstuff_message();
|
|
continue;
|
|
}
|
|
}
|
|
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// called when freespace initialized
|
|
void std_init_standalone()
|
|
{
|
|
// start the main thread
|
|
Standalone_thread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)standalone_process, NULL, 0, &Standalone_thread_id );
|
|
|
|
os_init_registry_stuff(Osreg_company_name, Osreg_app_name,NULL);
|
|
|
|
// set the close functions
|
|
atexit(std_deinit_standalone);
|
|
}
|
|
|
|
// called when freespace closes
|
|
void std_deinit_standalone()
|
|
{
|
|
if (Standalone_thread) {
|
|
CloseHandle(Standalone_thread);
|
|
Standalone_thread = NULL;
|
|
}
|
|
}
|
|
|