-
Notifications
You must be signed in to change notification settings - Fork 0
/
NetDlg.cpp
3454 lines (3025 loc) · 107 KB
/
NetDlg.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 RWS Inc, All Rights Reserved
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of version 2 of the GNU General Public License as published by
// the Free Software Foundation
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
// NetDlg.CPP
// Project: Nostril (aka Postal)
//
// History:
// 04/08/97 JMI Started.
//
// 05/20/97 JMI Now ms_pguiOK and ms_pguiCancel use SAFE_REF() so the
// current GUI can, optionally, not have one or both GUI
// items.
//
// 05/25/97 JMI Integrated newest TCP/IP CNetServer/Client interface.
// Still need to detect when the game is starting.
// GUI could still use a little cleaning up.
//
// 05/26/97 JMI Removed case for NetMsg::DuplicateName in reason
// for JoinDeny message (it no longer exists).
//
// 05/26/97 JMI Added sending and receiving of START_REALM.
// Removed psNumPlayers and psMyPlayerNum parameters.
//
// 05/27/97 JMI Added sending and receiving of LOAD_REALM before
// START_REALM.
// Fixed bug in OnLoginMsg() which was telling the client
// the wrong net ID.
// Upgraded to utilize new functions RSocket::SetPort() and
// CNet::OpenPeerData().
//
// 05/27/97 JMI OnJoinedMsg() now only adds the players' names to the
// listbox of players.
//
// 05/28/97 JMI Integrated new dialog.
//
// 05/28/97 JMI Changed so the LOAD_REALM message motivates the leaving
// of the dialog interface (was START_REALM that did it
// before).
//
// 06/11/97 JMI Removed unnecessary code in OnLoadRealmMsg().
// Now uses Play_GetNextLevel to get realm names.
//
// 06/11/97 JMI Now centers client/server dialogs on screen.
//
// 06/13/97 MJR Restructed lots of stuff to consolidate client and
// server code into a single function.
// Implimented new version of START_GAME message.
// Added code to get/release resources for new deluxe
// dialog box.
//
// 06/15/97 JMI Now deactivates client items in listbox as they are
// added.
// Also, now, instead of simply squashing the dialog to
// exclude server controls in client mode, we simply hide
// the server controls and center the remaining controls
// in the dialog without altering its size.
//
// 06/16/97 JMI Now uses g_fontSmall for dialogs.
//
// MJR Added use of watchdog timer for network blocking callbacks.
//
// JMI Changed use of g_fontSmall to g_fontBig.
//
// 06/17/97 JMI Now only allows the server to process a DLG_OK.
//
// 06/30/97 MJR Switched over to new GuiItem.h-supplied macros.
//
// 07/14/97 BRH Changed call to Play_GetRealmInfo to include the
// new challenge mode parameter.
//
// 08/02/97 JMI Added an icon to watchdog timer for network blocking
// callbacks and made it generally callable.
//
// 08/04/97 BRH Added protocol parameter to net calls.
//
// 08/11/97 JMI Changed a little of the structure of SetUpDlg() to allow
// for more than just two types of dialogs.
// Also, changed UpdateDialog() to use an RProcessGui which
// simplifies that down to nearly nothing. #if 0'd out old
// stuff for now.
// Checking in so Mike can compile so we can check his stuff
// in so I can check this out again.
//
// MJR Modified to use new browsing functions and moved all
// the find-the-host code into a separate function.
//
// JMI Now adds the items from the browse list to the dialog
// (and drops them too (theoretically) ).
//
// 08/12/97 JMI Dropped hosts were not setting the repaginate flag in
// UpdateListBox(). Fixed.
// DoNetGameDialog() now loops nearly all logic while
// browsing and no errors.
//
// 08/13/97 JMI Cleaned up some more stuff.
// MJR Fixed bugs that kept us in a browsing loop.
//
// 08/14/97 JMI Added global difficulty parameter to Play_GetRealmInfo().
// I imagine it's not actually used for multiplayer levels
// until we have options to play cooperative.
//
// 08/19/97 JMI Added some unfinished usage of the multiplayer options
// updating. Needs to be updated to the correct spot,
// either the game settings or the message. Probably the
// game settings which then get copied to the message.
//
// 08/19/97 JMI Now uses the g_GameSettings for the multiplayer options.
// Tinkered with chat messages that I thought weren't
// working but then realized they were being ignored b/c
// the UpdateDialog() function was being called by the
// net blocking callback so hopefully I didn't ruin anything
// in that process... .
// Genericized SetupDlg() to use UploadLinks().
//
// 08/19/97 JMI Added a flag to UpdateDialog() indicating that it should
// not clear any GUIs. This is useful for when
// UpdateDialog() is called via callback (so we don't loose
// any of the pressages processed via the callback).
//
// 08/20/97 JMI Up/DownloadLinkInteger() are now hardwired to assume
// 'signed' type for String links b/c bool had a warning
// for the trickery I was using to determine if the type
// was signed.
//
// 08/20/97 JMI Now chat history is a listbox.
// Clicking the 'Send Chat' button moves focus back to the
// edit field for better feedback.
// Limits chats to 20.
// Now updates client's view of host's multiplay options.
// Now the server can select a player (for disconnection)
// from the players list.
// Implemented host option to disconnect a player.
// Newest player is EnsureVisible()d in player list now.
// Newest chat is EnsureVisible()d in chat list now.
// Now sets number of connected players on two GUIs so
// there can be a 3D effect.
// Sends and responds to SETUP_GAME message.
// Sets options in START_GAME message from dialog settings
// now.
// Updates settings even if dialog aborted for consistency.
//
// 08/21/97 JMI Temporarily hardwired 'Rejuvenate' to ON and disallowed
// user modifications of the checkbox.
//
// 08/21/97 JMI Changed call to Update() to UpdateSystem() and occurrences
// of rspUpdateDisplay() to UpdateDisplay().
//
// 08/23/97 MJR Lots of changes in how errors are handled and other such
// stuff.
//
// 08/23/97 JMI Now list box items appear with a barely perceptible
// shadow that makes them alot easier to read.
// Player colors now displayed as color descriptions.
//
// 08/25/97 JMI Now the chat text edit field limits the text to the
// message's capacity for text.
// Also, got rid of some '***'s.
//
// 08/25/97 JMI Now removes areas on chat items in chat box to make
// for the border lines we hide to get more space.
//
// 08/27/97 JMI Changed NetProbIcons functions to NetProbGui functions.
// Also, instead of a DrawNetProbGui() there's a
// GetNetProbGui() so you can draw it, move it, change the
// text, etc.
//
// 09/01/97 MJR Nearing the end of a huge overhaul of networking.
//
// 09/02/97 MJR It appears to work well after much testing, tuning, and
// debugging.
//
// 09/03/97 MJR Fixed a problem that made browsing for yourself fail
// once in a while (the timeout timer was too short).
//
// 09/06/97 JMI Now sets the Client's Game Options text field to use
// the text shadow. Also, selects the first item in the
// level browser box in the Server's dialog.
// Also, combined the status field and the chat box into
// one 'Net Console'.
//
// 09/06/97 JMI Now filters out the high word of ie.lKey when checking
// for enter. This filters out the the key flags (i.e.,
// shift, control, alt, system).
//
// 09/07/97 JMI Now BrowseForHosts() updates the display before
// displaying the browse dialog.
//
// 09/08/97 MJR Fixed bug where net prob gui was showing up
// immediately instead of after the watchdog expired.
// Also cleaned up the erasing of the net prob gui.
//
// 09/09/97 JMI Now initializes ms_pguiRetry to NULL in DlgBeGone().
//
// 09/09/97 MJR Now detects protocol-not-supported and dispalys a
// specific msg box describing the problem.
//
// 09/11/97 MJR Now client checks to see whether the level that was
// specified in the SETUP_GAME message is available, and
// automatically sends a chat message that complains if it
// isn't, in the hope that the host player will change it.
//
// Now the host will send the realm name if only a single
// realm is available, which tells everyone to only play
// that realm.
//
// Changed the dropped message, which was incorrectly using
// the error message as the player's name.
//
// 09/11/97 JMI Now only adds the SPECIFIC_MP_REALM_TEXT choice to the
// host's level browser if ENABLE_PLAY_SPECIFIC_REALMS_ONLY
// is defined. Otherwise, it chooses the first item in the
// listbox.
//
// 09/12/97 MJR Reversed the #if for which method to use for filling
// hood listbox.
//
// Added hardwired realm stuff to SetupGame() when we're
// in the specific realm mode.
//
// 09/18/97 JMI There were some /"s instead of \"s. If someone had
// their syntax coloring on useful colors, they would've
// seen this blaringly obvious color collage. :)
//
// 09/24/97 JMI Fixed OnSetupGameMsg() to handle checking to see if the
// local machine has the required realm using the title
// that is passed in the SetupGame msg (was originally
// intended to use filenames but got hosed).
//
// 09/26/97 JMI Now '-' is blocked at the UpdateDialog() level and never
// reaches the GUIs so that the time limit and kill limit
// edit fields cannot have a negative number enter in them
// (of course you could enter the letter 'a' which looks
// wrong too but I know one cares about that (you'd have to
// be STUPID to do that but even smart people enter negative
// numbers for time and kill limits) ).
// Also, this keeps players from using '-' in their chat
// strings.
//
// 11/20/97 JMI Added cooperative flags and associated checkboxes. Now
// displays info on client side regarding cooperative mode
// and carries all the necessary flagage around between
// messages regarding cooperative mode as well. Also, now
// the level browse listbox can show either deathmatch or
// cooperative levels (controlled by the user's cooperative
// checkbox setting).
// Also, the user can choose operate checkbox deciding
// whether to allow cooperative play mode (which is missiles
// and bullets pass through fellow players).
//
// 11/25/97 JMI Added platform conflict message and more informative
// version conflict messages (also added version conflict
// message for server -- previous the error did not propagate
// to this level).
//
// 11/25/97 JMI Changed the server dialog .GUI to be loaded from the HD
// instead of from the VD so we can guarantee the new asset
// gets loaded (since they'll use their old Postal disc, we
// cannot load the .GUI from the CD).
//
//////////////////////////////////////////////////////////////////////////////
//
// Deals with networking dialogs. There is an interface for the server,
// client, and browser dialogs that deal heavily with user input, and GUI
// output. The client/server messages are now handled by the black-box-like
// lower level.
//
//////////////////////////////////////////////////////////////////////////////
#include "RSPiX.h"
#include "CompileOptions.h"
#include "GameSettings.h"
#include "game.h"
#include "play.h"
#include "update.h"
#include "NetDlg.h"
#include "netbrowse.h"
//////////////////////////////////////////////////////////////////////////////
// Module specific macros.
//////////////////////////////////////////////////////////////////////////////
// Common.
#define GUI_ID_OK 1001
#define GUI_ID_CANCEL 1002
// Common Client/Server dialog.
#define GUI_ID_PLAYERS_LISTBOX 1010
#define GUI_ID_CHAT_TEXT 1013
#define GUI_ID_CHAT_SEND 1015
#define GUI_ID_NET_CONSOLE 1016
#define GUI_ID_PLAYERS_STATIC1 7000
#define GUI_ID_PLAYERS_STATIC2 7001
// Client dialog.
#define GUI_ID_OPTIONS_STATIC 2000
#define GUI_ID_RETRY 9000
// Server dialog.
#define GUI_ID_DISCONNECT_PLAYER 6000
//#define GUI_ID_RESPAWN_PLAYERS 3000
#define GUI_ID_ENABLE_TIME_LIMIT 4000
#define GUI_ID_EDIT_TIME_LIMIT 4001
#define GUI_ID_ENABLE_KILL_LIMIT 5000
#define GUI_ID_EDIT_KILL_LIMIT 5001
#define GUI_ID_LEVEL_LISTBOX 1020
#define GUI_ID_SHOW_COOP_LEVELS 8000
#define GUI_ID_ENABLE_COOP_MODE 9000
// Browser dialog.
#define GUI_ID_HOST_LISTBOX 1010
#define SERVER_GUI "res/shell/Server.gui"
#define CLIENT_GUI "res/shell/Client.gui"
#define BROWSER_GUI "res/shell/Browser.gui"
#define GUI_DIR "menu/"
// Note that this is evaluated at compile time, so even
// if the ptr is NULL, it will work.
#define MAX_STATUS_STR GUI_MAX_STR
// Maximum number of chat strings in the box.
#define MAX_CHAT_STRINGS 20
// Time between game setup net sends.
#define OPTIONS_SEND_FREQUENCY 2000
// Amount of time that must elapse after the first "Cancel" before an
// addition "Cancel" wil be recognized.
#define CANCEL_DELAY_TIME 1500
// If status hasn't been updated for this long, then we will display the default message
#define STATUS_MAX_DISPLAY_TIME 2000
// NOTE: If we add anymore icons, we might as well just spend the extra few
// minutes making a separate file for them.
// Net problems icon file.
#define NET_PROB_GUI_FILE "menu/netprob.gui"
// Initial location for net problems icon on screen.
#define NET_PROB_GUI_X 10
#define NET_PROB_GUI_Y 40
#define NET_PROB_TEXT_SHADOW_COLOR_INDEX 4
#define TERMINATING_GUI_ID 0x80000000
// Note that the following color indices are from the 'Artie Zone' of colors
// in the menu palette and, therefore, should not change.
#define LIST_ITEM_TEXT_SHADOW_COLOR_INDEX 220
// This has been remapped to a Win32 color to make it stand out more
#define NET_STATUS_MSG_COLOR_INDEX 247
//////////////////////////////////////////////////////////////////////////////
// THIS ENTIRE SECTION OF STRINGS SHOULD BE MOVED TO LOCALIZE.CPP!!!
//////////////////////////////////////////////////////////////////////////////
// Client-specific messages displayed in client dialog's status area
char* g_pszClientStat_NameTooLongForChat = "Name too long, can't chat";
char* g_pszClientStat_YouWereDropped = "Connection was lost";
char* g_pszClientStat_SomeoneDropped_s = "\"%s\" is no longer connected";
char* g_pszClientStat_ServerAborted = "Game aborted";
char* g_pszClientStat_ServerStarted = "Starting game";
char* g_pszClientStat_Opened = "Opened connection";
char* g_pszClientStat_Connected = "Connected";
char* g_pszClientStat_JoinDenyTooMany = "Can't join -- too many players";
char* g_pszClientStat_JoinDenyLowBandwidth = "Can't join -- your bandwidth is too low";
char* g_pszClientStat_JoinDenyCantDropIn = "Can't join -- game has already started";
char* g_pszClientStat_JoinDenyUnknown = "Can't join -- don't know why";
char* g_pszClientStat_JoinAccepted = "Joined";
char* g_pszClientStat_LoginAccepted_hd = "Logged in (ID = %hd)";
char* g_pszClientStat_Startup = "Trying to connect...";
char* g_pszClientStat_Default = "Ready";
char* g_pszClientStat_Error_s = "Network error (%s) -- aborting";
char* g_pszClientStat_Retrying = "Retry...";
// Server-specific messages displayed in server dialog's status area
char* g_pszServerStat_InvalidDropReq_hd = "Ignored invalid drop request (ID = %hd)";
char* g_pszServerStat_AcceptedClient = "\"%s\" has joined";
char* g_pszServerStat_CantAcceptJoinReq = "Can't grant join request (too many players)";
char* g_pszServerStat_InvalidChangeReq_hd = "Ignored invalid change request (ID = %hd)";
char* g_pszServerStat_LoginAccepted_hd = "Login accepted (id = %hd)";
char* g_pszServerStat_LoginDeniedVersion_ld = "Login denied (obsolete client version %ld)";
char* g_pszServerStat_LoginDeniedMagic = "Login denied (invalid signature)";
char* g_pszServerStat_Startup = "Setting up connection...";
char* g_pszServerStat_Default = "Ready";
char* g_pszServerStat_CantDropSelf = "You can't drop yourself";
char* g_pszServerStat_PlayerErr = "Player was dropped (bad connection)";
// General messages displayed in client or server dialog's status area
char* g_pszNetStat_Aborting = "Aborting...";
char* g_pszNetStat_Starting = "Starting game...";
char* g_pszNetStat_AttemptToDrop_s = "Attempting to drop \"%s\"";
char* g_pszNetStat_UnhandledMsg = "Ignoring extraneous message";
char* g_pszNetStat_NoError = "No errors";
char* g_pszNetStat_ReceiveError = "Network error (can't receive data)";
char* g_pszNetStat_InQFullError = "Network error (input buffer is full)";
char* g_pszNetStat_OutQFullError = "Network error (output buffer is full)";
char* g_pszNetStat_SendError = "Network error (can't send data)";
char* g_pszNetStat_InQReadError = "Network error (can't read data)";
char* g_pszNetStat_OutQWriteError = "Network error (couldn't write data)";
char* g_pszNetStat_ConnectionError = "Network error (bad connection)";
char* g_pszNetStat_TimeoutError = "Network error (time-out)";
char* g_pszNetStat_ListenError = "Network error (can't listen)";
char* g_pszNetStat_ConnectError = "Network error (can't connect)";
char* g_pszNetStat_ConnectTimeoutError = "Network error (connection attempt timed-out)";
char* g_pszNetStat_ClientVersionMismatchError_lu_lu = "Version mismatch--dropping (Host ver is %lu -- Our ver is %lu)";
char* g_pszNetStat_ServerVersionMismatchError_lu_lu = "Version mismatch--dropping client (Client ver is %lu -- Our ver is %lu)";
char* g_pszNetStat_CantOpenPeerSocketError = "Network error (couldn't connect to other players)";
char* g_pszNetStat_LoginDeniedError = "Login failed";
char* g_pszNetStat_JoinDeniedError = "Host refused join request";
char* g_pszNetStat_UnknownError = "Network error (general failure)";
char* g_pszNetStat_ProgramError = "Network error (generic failure)";
#if defined(WIN32)
char* g_pszNetStat_ClientPlatformMismatchError = "Cannot login to host because it is a Mac";
char* g_pszNetStat_ServerPlatformMismatchError = "Cannot allow client to connect because it is a Mac";
#else
char* g_pszNetStat_ClientPlatformMismatchError = "Cannot login to host because it is a PC";
char* g_pszNetStat_ServerPlatformMismatchError = "Cannot allow client to connect because it is a PC";
#endif
// This is what we say when the user has chosen a protocol that is not supported.
// There are two variations: one for if the user only has one choice (because we
// only support that one) and the other for if the user can try another choice.
char* g_pszNetOnlyProtocolUnsupported_s =
"Your system does not support \"%s\", which is the required network protocol.\n"
"\n"
"This protocol must be added to your system before multiplayer mode can be used.";
char* g_pszNetProtocolUnsupported_s =
"Your system does not support \"%s\", which is the currently selected network protocol.\n"
"\n"
"Either add this protocol to your system or choose a different protocol from the "
"multiplayer options menu.";
// Text which is used to dynamically update one of the text fields on the client or server dialog
char* g_pszNetDlg_ConnectedPlayers_d = "Connected Players: %d";
// Text which is used for the net problems GUI.
// WARNING: This is an EXTERN and is used by other modules!
char* g_pszNetProb_General =
"Network not responding.\nYou can wait or\npress " NET_PROB_GUI_ABORT_KEY_TEXT" to abort";
// Text to prefix net status messages, if any.
char* g_pszNetStatusMsgPrefix = "> ";
//////////////////////////////////////////////////////////////////////////////
// Module specific typedefs.
//////////////////////////////////////////////////////////////////////////////
// Dialog actions
typedef enum
{
DLG_NOTHING,
DLG_OK,
DLG_CANCEL,
DLG_CHAT,
DLG_DISCONNECT_PLAYER,
DLG_OPTIONS_UPDATED,
DLG_RETRY
} DLG_ACTION;
// Dialog types.
typedef enum
{
DLG_SERVER,
DLG_CLIENT,
DLG_BROWSER
} DLG_TYPE;
// GUI/Var Link
typedef struct
{
typedef enum
{
Long,
ULong,
Short,
UShort,
Char,
UChar,
String,
Bool,
Gui
} Type;
long lId; // ID of GUI to link to.
Type type;
#if 1
union
{
void* pvLink;
long* pl;
ULONG* pul;
short* ps;
USHORT* pus;
char* pc;
UCHAR* puc;
char* psz;
bool* pb;
RGuiItem** ppgui;
};
#else
void* pvLink;
#endif
} GuiLink;
//////////////////////////////////////////////////////////////////////////////
// Module specific (static) variables / Instantiate class statics.
//////////////////////////////////////////////////////////////////////////////
// Common.
static RGuiItem* ms_pguiRoot = NULL; // Root of GUI tree for network interface.
static RGuiItem* ms_pguiOk = NULL; // GUI that, once 'clicked', indicates acceptance.
static RGuiItem* ms_pguiCancel = NULL; // GUI that, once 'clicked', indicates rejection.
// Client/Server common.
static RListBox* ms_plbPlayers = NULL; // Listbox used by both types of net dialogs.
static RListBox* ms_plbNetConsole = NULL; // List of net console (chat and status) strings.
static RGuiItem* ms_pguiChatText = NULL; // Chat text.
static RGuiItem* ms_pguiChatSend = NULL; // Chat send button.
// Server.
static RListBox* ms_plbLevelBrowse = NULL; // Level browse listbox.
static RGuiItem* ms_pguiDisconnectPlayer = NULL; // Disconnect a player button.
static RMultiBtn* ms_pmbCoopLevels = NULL; // Coop levels checkbox.
static RMultiBtn* ms_pmbCoopMode = NULL; // Coop mode checkbox.
// Client.
static RGuiItem* ms_pguiOptions = NULL; // Options shown on client dialog.
static RGuiItem* ms_pguiRetry = NULL; // Retry button on client dialog shown when needed.
// Browser.
static RListBox* ms_plbHostBrowse = NULL; // Browse for host listbox.
// Other static vars.
static long ms_lWatchdogTime = 0; // Watchdog timer
static bool ms_bNetBlockingAbort = false; // Net blocking abort flag
static long ms_lNumConsoleEntries = 0; // Track number of chat items.
static bool ms_bGotSetupMsg = false;
static short ms_sSetupRealmNum = 0;
static char ms_szSetupRealmFile[Net::MaxRealmNameSize];
static long ms_lSetupLastChatComplaint = 0;
static long ms_lNextOptionsUpdateTime; // Next time to send an options update.
static RTxt* ms_ptxtNetProb = NULL; // Net problem GUI.
static bool m_bNetWatchdogExpired = false; // Whether net blocking expired
static bool ms_bCoopLevels = false; // true, to use cooperative levels.
// This is used by UpdateDialog() to perform GUI processing.
static RProcessGui ms_pgDoGui;
// Linkable vars.
static bool ms_bTimeLimit = false; // Enable Time Limit if true.
static bool ms_bKillLimit = false; // Enable Kill Limit if true.
static bool ms_bCoopMode = false; // true, for cooperative mode (false for deathmatch).
static GuiLink ms_aglServerLinkage[] =
{
{ GUI_ID_DISCONNECT_PLAYER, GuiLink::Gui, &ms_pguiDisconnectPlayer, },
// { GUI_ID_RESPAWN_PLAYERS, GuiLink::Short, &g_GameSettings.m_sHostRejuvenate, },
{ GUI_ID_ENABLE_TIME_LIMIT, GuiLink::Bool, &ms_bTimeLimit, },
{ GUI_ID_EDIT_TIME_LIMIT, GuiLink::Short, &g_GameSettings.m_sHostTimeLimit, },
{ GUI_ID_ENABLE_KILL_LIMIT, GuiLink::Bool, &ms_bKillLimit, },
{ GUI_ID_EDIT_KILL_LIMIT, GuiLink::Short, &g_GameSettings.m_sHostKillLimit, },
{ GUI_ID_LEVEL_LISTBOX, GuiLink::Gui, &ms_plbLevelBrowse, },
{ GUI_ID_SHOW_COOP_LEVELS, GuiLink::Gui, &ms_pmbCoopLevels, },
{ GUI_ID_ENABLE_COOP_MODE, GuiLink::Gui, &ms_pmbCoopMode, },
{ GUI_ID_ENABLE_COOP_MODE, GuiLink::Bool, &ms_bCoopMode, },
{ static_cast<long>(TERMINATING_GUI_ID), }, // Terminator.
};
static GuiLink ms_aglClientLinkage[] =
{
{ GUI_ID_OPTIONS_STATIC, GuiLink::Gui, &ms_pguiOptions, },
{ GUI_ID_RETRY, GuiLink::Gui, &ms_pguiRetry, },
{ static_cast<long>(TERMINATING_GUI_ID), }, // Terminator.
};
static GuiLink ms_aglClientServerLinkage[] =
{
{ GUI_ID_PLAYERS_LISTBOX, GuiLink::Gui, &ms_plbPlayers, },
{ GUI_ID_CHAT_TEXT, GuiLink::Gui, &ms_pguiChatText, },
{ GUI_ID_CHAT_SEND, GuiLink::Gui, &ms_pguiChatSend, },
{ GUI_ID_NET_CONSOLE, GuiLink::Gui, &ms_plbNetConsole, },
{ GUI_ID_OK, GuiLink::Gui, &ms_pguiOk, },
{ GUI_ID_CANCEL, GuiLink::Gui, &ms_pguiCancel, },
{ static_cast<long>(TERMINATING_GUI_ID), }, // Terminator.
};
static GuiLink ms_aglBrowserLinkage[] =
{
{ GUI_ID_HOST_LISTBOX, GuiLink::Gui, &ms_plbHostBrowse, },
{ GUI_ID_OK, GuiLink::Gui, &ms_pguiOk, },
{ GUI_ID_CANCEL, GuiLink::Gui, &ms_pguiCancel, },
{ static_cast<long>(TERMINATING_GUI_ID), }, // Terminator.
};
//////////////////////////////////////////////////////////////////////////////
// Module specific (static) protos.
//////////////////////////////////////////////////////////////////////////////
static void AddConsoleMsg( // Returns nothing.
bool bChat, // In: true for a chat message, or false for others (like net status).
const char* pszFrmt, // In: sprintf style formatting.
...); // In: Optional arguments based on context of pszFrmt.
// Get dialog resource
short DlgGetRes( // Returns 0 if successfull, non-zero otherwise
RGuiItem* pgui); // I/O: Pointer to gui item
// Release dialog resource
void DlgReleaseRes( // Returns 0 if successfull, non-zero otherwise
RGuiItem* pgui); // I/O: Pointer to gui item
// Net blocking callback
static short NetBlockingCallback(void); // Returns 0 to continue normally, 1 to abort
static short BrowseForHost(
CNetServer* pserver, // I/O: Server interface or NULL if none
RSocket::Address* paddress); // Out: Address returned here (if successfull)
static short FindSpecificSystem(
RSocket::Address* paddress); // Out: Address returned here (if successfull)
static short BrowseForSelf(
CNetServer* pserver, // I/O: Server interface
RSocket::Address* paddress); // Out: Address returned here (if successfull)
//////////////////////////////////////////////////////////////////////////////
// Helper for UploadLinks() to handle all integer vars.
//////////////////////////////////////////////////////////////////////////////
template <class Int> // Templated input type (can be unsigned).
void UploadLinkInteger( // Returns nothing.
RGuiItem* pgui, // In: GUI to upload to.
Int i) // In: Input val to upload to GUI.
{
ASSERT(pgui);
switch (pgui->m_type)
{
case RGuiItem::MultiBtn:
{
RMultiBtn* pmb = (RMultiBtn*)pgui;
if (i)
{
pmb->m_sState = 1;
}
else
{
pmb->m_sState = 2;
}
break;
}
case RGuiItem::PushBtn:
{
RPushBtn* ppushbtn = (RPushBtn*)pgui;
if (i)
{
ppushbtn->m_state = RPushBtn::On;
}
else
{
ppushbtn->m_state = RPushBtn::Off;
}
break;
}
default:
#if 0
// Determine if signed (this is wierd but may work) . . .
if ((Int)-1 < 0)
{
// Signed.
pgui->SetText("%ld", (long)i);
}
else
{
// Unsigned.
pgui->SetText("%lu", (ULONG)i);
}
#else
// Hardwire to signed b/c bool was displaying a warning regarding the
// above comparison to determine the [un]signed nature of the templated
// type.
pgui->SetText("%ld", (long)i);
#endif
break;
}
pgui->Compose();
}
//////////////////////////////////////////////////////////////////////////////
// Helper for DownloadLinks() to handle all integer vars.
//////////////////////////////////////////////////////////////////////////////
template <class Int> // Templated output type (can be unsigned).
void DownloadLinkInteger( // Returns nothing.
RGuiItem* pgui, // In: GUI to download from.
Int* pi) // Out: Input val to download into from GUI.
{
ASSERT(pgui);
switch (pgui->m_type)
{
case RGuiItem::MultiBtn:
{
RMultiBtn* pmb = (RMultiBtn*)pgui;
*pi = (pmb->m_sState == 1) ? 1 : 0;
break;
}
case RGuiItem::PushBtn:
{
RPushBtn* ppushbtn = (RPushBtn*)pgui;
*pi = (ppushbtn->m_state == RPushBtn::On) ? 1 : 0;
break;
}
default:
#if 0
// Determine if signed (this is wierd but may work) . . .
if ((Int)-1 < 0)
{
// Signed.
*pi = pgui->GetVal();
}
else
{
// Unsigned.
*pi = strtoul(pgui->m_szText, NULL, 0);
}
#else
// Hardwire to signed b/c bool was displaying a warning regarding the
// above comparison to determine the [un]signed nature of the templated
// type.
*pi = pgui->GetVal();
#endif
break;
}
pgui->Compose();
}
//////////////////////////////////////////////////////////////////////////////
//
// Upload variables to their GUI links.
//
//////////////////////////////////////////////////////////////////////////////
static void UploadLinks( // Returns nothing.
GuiLink* pagl, // In: Links to upload.
RGuiItem* pguiRoot) // In: GUI to upload to.
{
ASSERT(pguiRoot);
while (pagl->lId != TERMINATING_GUI_ID)
{
// Get item.
RGuiItem* pgui = pguiRoot->GetItemFromId(pagl->lId);
if (pgui)
{
switch (pagl->type)
{
case GuiLink::Long:
UploadLinkInteger(pgui, *pagl->pl);
break;
case GuiLink::ULong:
UploadLinkInteger(pgui, *pagl->pul);
break;
case GuiLink::Short:
UploadLinkInteger(pgui, *pagl->ps);
break;
case GuiLink::UShort:
UploadLinkInteger(pgui, *pagl->pus);
break;
case GuiLink::Char:
UploadLinkInteger(pgui, *pagl->pc);
break;
case GuiLink::UChar:
UploadLinkInteger(pgui, *pagl->puc);
break;
case GuiLink::Bool:
UploadLinkInteger(pgui, *pagl->pb);
break;
case GuiLink::String:
pgui->SetText("%s", pagl->psz );
break;
// This may seem backward but it's more convenient.
case GuiLink::Gui:
*pagl->ppgui = pgui;
break;
default:
TRACE("UploadLinks(): Type %d not supported.\n",
pagl->type);
break;
}
}
else
{
TRACE("UploadLinks(): GUI ID %d does not exist.\n", pagl->lId);
}
// Next.
pagl++;
}
}
//////////////////////////////////////////////////////////////////////////////
//
// Download variables to their GUI links.
//
//////////////////////////////////////////////////////////////////////////////
static void DownloadLinks( // Returns nothing.
GuiLink* pagl, // In: Links to upload.
RGuiItem* pguiRoot) // In: GUI to upload to.
{
ASSERT(pguiRoot);
while (pagl->lId != TERMINATING_GUI_ID)
{
// Get item.
RGuiItem* pgui = pguiRoot->GetItemFromId(pagl->lId);
if (pgui)
{
switch (pagl->type)
{
case GuiLink::Long:
DownloadLinkInteger(pgui, pagl->pl);
break;
case GuiLink::ULong:
DownloadLinkInteger(pgui, pagl->pul);
break;
case GuiLink::Short:
DownloadLinkInteger(pgui, pagl->ps);
break;
case GuiLink::UShort:
DownloadLinkInteger(pgui, pagl->pus);
break;
case GuiLink::Char:
DownloadLinkInteger(pgui, pagl->pc);
break;
case GuiLink::UChar:
DownloadLinkInteger(pgui, pagl->puc);
break;
case GuiLink::Bool:
DownloadLinkInteger(pgui, pagl->pb);
break;
case GuiLink::String:
strcpy( pagl->psz, pgui->m_szText );
break;
case GuiLink::Gui:
break;
default:
TRACE("DownloadLinks(): Type %d not yet supported.\n",
pagl->type);
break;
}
}
else
{
TRACE("DownloadLinks(): GUI ID %d does not exist.\n", pagl->lId);
}
// Next.
pagl++;
}
}
//////////////////////////////////////////////////////////////////////////////
//
// Macro to activate certain parms to make our list item GUI's look nice and
// readable.
//
//////////////////////////////////////////////////////////////////////////////
inline void MakeMoreReadable( // Returns nothing.
RGuiItem* pgui) // In: GUI to shadowify using global values.
{
ASSERT(pgui);
if (pgui)
{
pgui->m_sTextEffects = RGuiItem::Shadow;
pgui->m_u32TextShadowColor = LIST_ITEM_TEXT_SHADOW_COLOR_INDEX;
pgui->m_sShowFocus = FALSE;
}
}
//////////////////////////////////////////////////////////////////////////////
//
// [Re]compose Options GUI with word wrap preserving original word wrap status.
//
//////////////////////////////////////////////////////////////////////////////
inline void ComposeOptions(void)
{
// Most likely someone has already checked this before calling this but
// it doesn't hurt to be safe.
if (ms_pguiOptions)
{
// Store old word wrap status so we can restore it when done.
short sWordWrapWas = (ms_pguiOptions->m_pprint->m_eModes & RPrint::WORD_WRAP) ? TRUE : FALSE;
// Enable word wrap (not accessible from GUI editor currently).
ms_pguiOptions->m_pprint->SetWordWrap(TRUE);
ms_pguiOptions->Compose();
// Reset word wrap.
ms_pguiOptions->m_pprint->SetWordWrap(sWordWrapWas);
}
}
//////////////////////////////////////////////////////////////////////////////
//
// Clean/Reset Client dialog to defaults.
//
//////////////////////////////////////////////////////////////////////////////
static void CleanClientDlg(
CNetClient* pnet,
bool bRetryButton)
{
if (ms_pguiOptions)
{
// Set no-connection text for options GUI.
ms_pguiOptions->SetText("Not currently connected to a host.");
// Repaginate now!
ComposeOptions();
}
if (ms_plbPlayers)
{
// Empty players listbox.
ms_plbPlayers->RemoveAll();
}
int iNumPlayers = (pnet) ? pnet->GetNumPlayers() : 0;
// This cheese updates the number of players displayed. I cannot remember why we did not simply
// make this one text shadowed GUI.
RGuiItem* pguiConnected = ms_pguiRoot->GetItemFromId(GUI_ID_PLAYERS_STATIC1);
RSP_SAFE_GUI_REF_VOID(pguiConnected, SetText(g_pszNetDlg_ConnectedPlayers_d, iNumPlayers));
RSP_SAFE_GUI_REF_VOID(pguiConnected, Compose());
pguiConnected = ms_pguiRoot->GetItemFromId(GUI_ID_PLAYERS_STATIC2);
RSP_SAFE_GUI_REF_VOID(pguiConnected, SetText(g_pszNetDlg_ConnectedPlayers_d, iNumPlayers));
RSP_SAFE_GUI_REF_VOID(pguiConnected, Compose());
if (ms_pguiRetry)
{
// Show as specified by caller.
ms_pguiRetry->SetVisible(bRetryButton ? TRUE : FALSE);
}
}
//////////////////////////////////////////////////////////////////////////////