File: score.cpp

package info (click to toggle)
postal1 2015.git20250526%2Bds-2
  • links: PTS, VCS
  • area: contrib
  • in suites: forky, sid
  • size: 14,024 kB
  • sloc: cpp: 130,877; ansic: 38,942; python: 874; makefile: 351; sh: 61
file content (1501 lines) | stat: -rw-r--r-- 47,224 bytes parent folder | download
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
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
////////////////////////////////////////////////////////////////////////////////
//
// 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
//
// Score.cpp
// Project: Postal
//
//	Description:
//		This module will be used to collect and display the scoring for the
//		game.  Characters that die will call a function to register the kill
//		giving their ID and the ID of the character that killed them.  Play
//		will call a function to update the display for the score and depending
//		on the mode of scoring, this module will draw the score into the given
//		image.  The first scoring mode will be for multiplayer where all 8
//		players will have the number of kills displayed with their names.  
//		Single player score may show something like Number of victims and
//		number of enemies.  A timed challenge level may show the kills and the
//		time remaining.  
// 
// History:
//		
//		06/11/97 BRH	Started this module for scoring of different types.  
//
//		06/12/97 BRH	Added Scoring display for multiplayer and moved the 
//							single player score from Realm to the same display
//							function here in score.
//
//		06/13/97 BRH	Fixed the formatting for multiplayer mode.
//
//		06/15/97 BRH	Took out temporary code that forced it into multiplayer
//							display for testing.  Put back the normal code to 
//							work for either single or multiplayer mode.
//
//		06/16/97 BRH	Added a reset function to reset the scores and 
//							display time.
//
//		06/17/97 BRH	Fixed the display area for the score.
//
//		06/26/97 BRH	Changed the score so that the population number goes
//							down when someone is killed.
//
//		06/29/97 BRH	Separated the score and status lines so that the mission
//							goal can be displayed for a short period of time while
//							the score displays constantly.
//
//		07/04/97 BRH	Added scoring displays for some of the other types
//							of games, timed, goal, capture the flag, etc.
//
//		07/06/97 BRH	Added scoring displays and staus lines for the challenge
//							levels.
//
//		07/07/97	JMI	Now ScoreUpdateDisplay() returns true if it drew into
//							the passed in buffer and false otherwise.
//
//		07/08/97 BRH	Changed the check for scoring mode from the scoreboard
//							to the realm's enumerated type.
//
//		07/14/97 BRH	Fixed clock format to use %2.2d to correctly display
//							2 digits for seconds.
//
//		07/22/97 BRH	Added ScoreDisplayHighScores function which is called
//							from Play.cpp after the goal level has been met.  This
//							will check the player's score against the top 5 stored
//							scores for the level and if they place, it will allow
//							them to enter their name.  The initial version of this
//							will just skip the dialog for now, but will soon
//							do a switch statement for each scoring mode.
//
//		07/26/97 BRH	Added loading and saving of high scores in a prefs type
//							file.  Now the only thing that needs to be changed is
//							to use the function that returns the realm name or
//							descriptive string which will be used as the section
//							name to find the scores particular to this realm.
//
//		07/27/97 BRH	Made use of the new realm variable m_lScoreIntialTime 
//							to calculate the elapsed time for two of the scoring
//							modes.
//
//		07/30/97 BRH	Used the realm's string to identify the current realm
//							being played so that the high scores for this realm
//							can be loaded and saved.
//
//		08/10/97	JRD	Modified ScoreUpdateDisplay to accept a hood pointer so
//							it could create a graphical back drop.
//
//		09/10/97	JRD	Added color matching and shadow drop to the upper score bar.
//
//		08/14/97 BRH	Changed location of gui for high scores, moved from 
//							/game/ to /shell directory so that the textures used
//							for it could be shared easier with the other shell gui's
//
//		08/17/97 MJR	Now uses g_resmgrShell to load gui's.  Also now frees
//							the resources (ooooohhh Bill!)
//
//		08/19/97 BRH	Fixed the problem with checkpoint scoring, probably 
//							some typo that Mike put in by accident.
//
//		08/19/97	JMI	There was a missing '}' ala Mike via Bill.
//
//		08/20/97 BRH	No thanks to Mike or Jon, I had to fix the multiplayer
//							score displays so that new time information would
//							fit on a third line.
//
//		08/25/97	JMI	Moved gsStatus* to toolbar.h.
//
//		08/28/97	JMI	Added GetRes/ReleaseRes callbacks to dialogs, PalTrans,
//							Postal Font, and sound to name edit field.
//
//		08/29/97 BRH	Changed challenge modes to use Population numbers
//							rather than just hostile numbers so that the victims
//							count also.
//
//		08/29/97	JMI	Now ScoreDisplayHighScores() quits immediately for
//							scoring modes that don't track high scores (currently,
//							only standard).
//
//		08/30/97	JMI	Now uses population deaths instead of hostile deaths
//							for timed challenge scoring.
//							Also, sets the palette every time the dialog is shown.
//
//		09/01/97	JMI	Now your high score is entered in the high score dialog
//							itself.  Also, now uses a listbox for high scores so
//							that we could edit merely one high score item and fill
//							the listbox with instances of that same item.
//
//		09/01/97	JMI	Now displays new highscore in different color.
//
//		09/02/97	JMI	Now ScoreDisplayHighScores() makes sure you're not playing
//							a demo before displaying the highscores.
//
//		09/02/97	JMI	Now has separate cases for determing scoring for every
//							mode in ScoreDisplayHighScores().
//
//		09/04/97 BRH	Fixed font size for the MPFrag scoring mode.
//
//		09/07/97	JMI	Added ability to display high scores for multiplayer.
//							Also, added optional high score display timeout.
//
//		09/07/97 BRH	Fixed problem with long multi player names wrapping
//							to the next line.
//
//		09/07/97	JMI	Now colors this player's score in MP mode.  Also, dialog
//							is much smaller so name length is restricted more.  But
//							does allow up to 16 scores now.
//
//		09/08/97 BRH	Fixed Goal and TimedGoal to display the Remaining: as
//							the number remaining in the goal, not the number of
//							people remaining in the realm.
//
//		09/08/97 BRH	Adjusted the posiiton of the MP mission goals since
//							the font size is smaller, they weren't centered properly.
//
//		09/08/97	JMI	Changed "Congratulations! Please enter your name for your 
//							score." to "Please enter your name, Asshole." but the end
//							clips off (just kidding).
//
//		09/08/97	JMI	Now sorts multiplayer names by score.
//
//		06/04/98	JMI	Strings used for storage and sorting of multiplayer names
//							were sized at MAX_PLAYER_NAME_LEN (to fit the high score
//							GUI without overlapping the score) but Postal's net 
//							client (from which the names are querried) allows longer
//							names (specifically Net::MaxPlayerNameSize).  Now only
//							copies first MAX_PLAYER_NAME_LEN chars from the player's
//							name.
//
//////////////////////////////////////////////////////////////////////////////

#define SCORE_CPP

//////////////////////////////////////////////////////////////////////////////
// C Headers
//////////////////////////////////////////////////////////////////////////////

#include "RSPiX.h"
#include "score.h"
#include "dude.h"
#include "toolbar.h"
#include "update.h"

//////////////////////////////////////////////////////////////////////////////
// Macros
//////////////////////////////////////////////////////////////////////////////

// Time, in ms, between status updates.
#define SCORE_UPDATE_INTERVAL			1000
#define STATUS_DISPLAY_TIMEOUT		8000

#define STATUS_PRINT_X					2
#define STATUS_PRINT_Y					0
#define STATUS_PRINT_Y2					14
#define STATUS_PRINT_Y3					28

#define STATUS_FONT_SIZE				19
#define STATUS_DISPLAY_HEIGHT			40

#define MP_FONT_SIZE						11 //15
#define MP_PRINT_X						2
#define MP_PRINT_Y1						0
#define MP_PRINT_Y2						11
#define MP_PRINT_Y3						22

//------------------------ These are color matched in the toolbar module

#define HIGHSCORE_NAMEDIALOG_FILE	"menu/addname.gui"
#define HIGHSCORE_DIALOG_FILE			"menu/hiscore.gui"
#define HIGHSCORE_ITEM_FILE			"menu/HiScoreItem.gui"
//HighScore GUI disabled #define HIGH_SCORE_DLG

#if WITH_STEAMWORKS
extern bool EnableSteamCloud;
#define HIGHSCORE_SCORES_FILE						(EnableSteamCloud ? "steamcloud/high.ini" : "savegame/high.ini")
#else
#define HIGHSCORE_SCORES_FILE						"savegame/high.ini"
#endif

#define TEXT_SHADOW_COLOR				220

#define TEXT_HIGHLIGHT_COLOR			9

// This path gets prepended to the resource path before passing the
// GUI res request to the resource manager.  This makes it easy to
// keep the path for the file simple while in the GUI Editor so the default
// handling can take care of it there.  The GUI Editor does not use the resmgr,
// it simply loads it blindly with no regard to its current directory.
#define GUI_RES_DIR						"menu/"

// Maximum name length.
#define MAX_PLAYER_NAME_LEN			17


#define MAX_HIGH_SCORES					16

// defaults to -1 for some reason
// #define LONG_MAX 0x7FFFFFFFL

//////////////////////////////////////////////////////////////////////////////
// Variables
//////////////////////////////////////////////////////////////////////////////

CScoreboard g_scoreboard;
RPrint		ms_print;

static int32_t	ms_lScoreMaxTimeOut;		// Optional score timeout (max time spent
												// on score screen).

//////////////////////////////////////////////////////////////////////////////
// Functions.
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
// Helper to make a time value.
//////////////////////////////////////////////////////////////////////////////
inline char* CreateTimeString(	// Returns time string.  No failures.
	int32_t	lTimeVal)					// In:  Time value in milliseconds.
	{
	static char	szTime[100];

	int16_t sMinutes = lTimeVal / 60000;
	int16_t	sSeconds = (lTimeVal / 1000) % 60;
	sprintf(szTime, "%2.2d:%2.2d", sMinutes, sSeconds);

	return szTime;
	}


//////////////////////////////////////////////////////////////////////////////
// GuiReleaseRes - Release a resource that the requesting GUI wants to 
// discard.
//////////////////////////////////////////////////////////////////////////////

static void GuiReleaseRes(	// Returns nothing.
	RGuiItem* pgui)			// In:  Requesting GUI.
	{
	rspReleaseResource(&g_resmgrShell, &pgui->m_pimBkdRes);
	}

//////////////////////////////////////////////////////////////////////////////
// GuiGetRes - Get a resource that the requesting GUI wants to use for its
// background or state image.
//////////////////////////////////////////////////////////////////////////////

static int16_t GuiGetRes(		// Returns 0 on success; non-zero on failure.
	RGuiItem* pgui)			// In:  Requesting GUI.
	{
	int16_t sResult = 0;

	// Release resources first (just in case)
	GuiReleaseRes(pgui);

	// Allocate and load new resources.  We get the name of the file (which
	// is ASSUMED to have NO PATH!!) from the gui itself, then tack on the
	// path we need and get the resource from the resource manager.
	char szFile[RSP_MAX_PATH * 2];
	sprintf(szFile, "%s%s", GUI_RES_DIR, pgui->m_szBkdResName);

	if (rspGetResource(&g_resmgrShell, szFile, &pgui->m_pimBkdRes) == 0)
		{
		// Set palette via resource.
		ASSERT(pgui->m_pimBkdRes->m_pPalette != NULL);
		ASSERT(pgui->m_pimBkdRes->m_pPalette->m_type == RPal::PDIB);

		rspSetPaletteEntries(
			0,
			230,
			pgui->m_pimBkdRes->m_pPalette->Red(0),
			pgui->m_pimBkdRes->m_pPalette->Green(0),
			pgui->m_pimBkdRes->m_pPalette->Blue(0),
			pgui->m_pimBkdRes->m_pPalette->m_sPalEntrySize);

		// Update hardware palette.
		rspUpdatePalette();
		}
	else
		{
		sResult = -1;
		TRACE("GuiGetRes(): Failed to open file '%s'\n", szFile);
		}

	return sResult;
	}

//////////////////////////////////////////////////////////////////////////////
// EditInputUserFeedback -- Whines when the user causes an input 
// disgruntlement.
//////////////////////////////////////////////////////////////////////////////

static void EditInputUserFeedback(	// Called when a user input notification
												// should occur.
	REdit*	pedit)						// In:  Edit field.
	{
	PlaySample(g_smidEmptyWeapon, SampleMaster::UserFeedBack);
	}

////////////////////////////////////////////////////////////////////////////////
//
// Callback from RProcessGui for system update.
//
////////////////////////////////////////////////////////////////////////////////
static int32_t SysUpdate(			// Returns a non-zero ID to abort or zero
										// to continue.                          
	RInputEvent*	pie)			// Out: Next input event to process.     
	{
	int32_t	lIdRes	= 0;	// Assume no GUI ID pressed (i.e., continue).

	UpdateSystem();
	rspGetNextInputEvent(pie);
	// If timeout has expired . . .
	if (rspGetMilliseconds() > ms_lScoreMaxTimeOut)
		{
		// Auto push OK.
		lIdRes	= 1;
		}

	return lIdRes;
	}

//////////////////////////////////////////////////////////////////////////////
// ScoreInit - Set up the RPrint for the score
//////////////////////////////////////////////////////////////////////////////

void ScoreInit(void)
{
	// Setup print.
	ms_print.SetFont(STATUS_FONT_SIZE, &g_fontBig);
	ms_print.SetColor(
		gsStatusFontForeIndex, 
		gsStatusFontBackIndex, 
		gsStatusFontShadowIndex);

	// Make sure shadow is one off:
	ms_print.SetEffectAbs(RPrint::SHADOW_X,+1);
	ms_print.SetEffectAbs(RPrint::SHADOW_Y,+1);

	// Warning!  This may need to be set back again for gui items - if so, use 
	// my OWN print!

}

//////////////////////////////////////////////////////////////////////////////
// ScoreReset - Reset the scores and the display time
//////////////////////////////////////////////////////////////////////////////

void ScoreReset(void)
{
	g_scoreboard.Reset();
}

//////////////////////////////////////////////////////////////////////////////
// ScoreResetDisplay - Reset the timer for the display before the start 
//							  of each realm
//////////////////////////////////////////////////////////////////////////////

void ScoreResetDisplay(void)
{
	g_scoreboard.m_lLastStatusDrawTime = 0;
	g_scoreboard.m_lLastScoreDrawTime = 0;
}

//////////////////////////////////////////////////////////////////////////////
// ScoreRegisterKill - Characters should call this when they die
//////////////////////////////////////////////////////////////////////////////

void ScoreRegisterKill(CRealm* pRealm, U16 u16DeadGuy, U16 u16Killer)
{
	CThing* pShooter = NULL;
	pRealm->m_idbank.GetThingByID(&pShooter, u16Killer);
	if (pShooter && pShooter->GetClassID() == CThing::CDudeID)
	{
		if (u16DeadGuy == u16Killer)
			g_scoreboard.SubtractOne(((CDude*) pShooter)->m_sDudeNum);
		else
			g_scoreboard.AddOne(((CDude*) pShooter)->m_sDudeNum);
	}
}

//////////////////////////////////////////////////////////////////////////////
// ScoreUpdateDisplay - Display the score for the current mode
// Returns true, if pImage was updated; false otherwise.
//////////////////////////////////////////////////////////////////////////////

bool ScoreUpdateDisplay(RImage* pim, RRect* prc, CRealm* pRealm, CNetClient* pclient,
								int16_t sDstX,int16_t sDstY,CHood* pHood)
{
	RRect rcBox;
	RRect	rcDst;
	rcDst.sX	= prc->sX + STATUS_PRINT_X;
	rcDst.sY = prc->sY + STATUS_PRINT_Y;
	rcDst.sW = prc->sW - 2 * STATUS_PRINT_X;
	rcDst.sH	= prc->sH - STATUS_PRINT_Y;
	int16_t sMinutes = pRealm->m_lScoreTimeDisplay / 60000;
	int16_t sSeconds = (pRealm->m_lScoreTimeDisplay / 1000) % 60;
	bool	bDrew	= false;	// Assume we do not draw.

	int32_t	lCurTime	= pRealm->m_time.GetGameTime();
	if (lCurTime > g_scoreboard.m_lLastScoreDrawTime + SCORE_UPDATE_INTERVAL)
	{
		ms_print.SetColor(	// set current color
		gsStatusFontForeIndex, 
		gsStatusFontBackIndex, 
		gsStatusFontShadowIndex);

		// Set print/clip to area.
		// instead of clearing, drop the special backdrop.
		//rspRect(RSP_BLACK_INDEX, pim, rcDst.sX, rcDst.sY, rcDst.sW, rcDst.sH);

		if (pHood) rspBlit(pHood->m_pimTopBar,pim,0,0,sDstX,sDstY,
			pHood->m_pimTopBar->m_sWidth,pHood->m_pimTopBar->m_sHeight);
		
		int16_t sNumDudes = pRealm->m_asClassNumThings[CThing::CDudeID];	
		int16_t i;

		switch (pRealm->m_ScoringMode)
		{
			case CRealm::MPFrag:
				ms_print.SetFont(MP_FONT_SIZE, &g_fontBig);
				rcBox.sY = prc->sY + MP_PRINT_Y1;
				rcBox.sH = MP_FONT_SIZE + 1;
				rcBox.sW = rcDst.sW / sNumDudes;

				ms_print.SetJustifyLeft();
				ms_print.SetWordWrap(FALSE);
				for (i = 0; i < sNumDudes; i++)
				{
					rcBox.sX = rcDst.sX + (i * rcBox.sW);
					rcBox.sY = prc->sY + STATUS_PRINT_Y;
					ms_print.SetDestination(pim, &rcBox);
					ms_print.print(
						rcBox.sX,
						rcBox.sY,
						"%s",
						pclient->GetPlayerName(i)
						);

					rcBox.sY = prc->sY + STATUS_PRINT_Y2;
					ms_print.SetDestination(pim, &rcBox);
					ms_print.print(
						rcBox.sX,
						rcBox.sY,
						"%d",
						g_scoreboard.m_asScores[i]
						);
				}
				break;

			// These have the same display, but different ending conditions
			case CRealm::MPTimed:
			case CRealm::MPTimedFrag:
				ms_print.SetFont(MP_FONT_SIZE, &g_fontBig);
				rcBox.sY = prc->sY + MP_PRINT_Y1;
				rcBox.sH = MP_FONT_SIZE + 1;
				rcBox.sW = rcDst.sW / sNumDudes;

				ms_print.SetJustifyLeft();
				ms_print.SetWordWrap(FALSE);
				for (i = 0; i < sNumDudes; i++)
				{
					rcBox.sX = rcDst.sX + (i * rcBox.sW);
					rcBox.sY = prc->sY + MP_PRINT_Y1;
					ms_print.SetDestination(pim, &rcBox);
					ms_print.print(
						rcBox.sX,
						rcBox.sY,
						"%s",
						pclient->GetPlayerName(i)
						);

					rcBox.sY = prc->sY + MP_PRINT_Y2;
					ms_print.SetDestination(pim, &rcBox);
					ms_print.print(
						rcBox.sX,
						rcBox.sY,
						"%d",
						g_scoreboard.m_asScores[i]
						);

				}
				rcBox.sY = prc->sY + MP_PRINT_Y3;
				rcBox.sX = prc->sX;
				ms_print.SetDestination(pim, &rcBox);
				ms_print.print(
					rcDst.sX,
					rcDst.sY,
//					"Time Remaining %d:%2.2d",
					g_apszScoreDisplayText[pRealm->m_ScoringMode],					
					sMinutes,
					sSeconds);
				break;

			case CRealm::MPLastMan:
				rcBox.sY = prc->sY + STATUS_PRINT_Y;
				rcBox.sH = STATUS_FONT_SIZE + 1;
				rcBox.sW = rcDst.sW / sNumDudes;

				ms_print.SetJustifyLeft();
				ms_print.SetWordWrap(FALSE);
				for (i = 0; i < sNumDudes; i++)
				{
					// If this player is dead, set the color to dead color
					/*
						ms_print.SetColor(	// set current color
						gsStatusFontForeDeadIndex, 
						gsStatusFontBackIndex, 
						gsStatusFontShadowIndex);

							else

						ms_print.SetColor(	// set current color
						gsStatusFontForeIndex, 
						gsStatusFontBackIndex, 
						gsStatusFontShadowIndex);
					*/

					rcBox.sX = rcDst.sX + (i * rcBox.sW);
					rcBox.sY = prc->sY + STATUS_PRINT_Y;
					ms_print.SetDestination(pim, &rcBox);
					ms_print.print(
						rcBox.sX,
						rcBox.sY,
						"%s",
						pclient->GetPlayerName(i)
						);

					rcBox.sY = prc->sY + STATUS_PRINT_Y2;
					ms_print.SetDestination(pim, &rcBox);
					ms_print.print(
						rcBox.sX,
						rcBox.sY,
						"%d",
						g_scoreboard.m_asScores[i]
						);
				}
				break;

			case CRealm::MPLastManTimed:
				break;

			case CRealm::MPLastManFrag:
				break;

			case CRealm::MPLastManTimedFrag:
				break;

			case CRealm::Standard:
				ms_print.SetDestination(pim, &rcDst);
				ms_print.print(
					pim, 
					rcDst.sX, 
					rcDst.sY, 
//					"      Population %d                        Hostiles %d   Killed %d (%d%% / %d%%)",
					g_apszScoreDisplayText[pRealm->m_ScoringMode],
					pRealm->m_sPopulation,
					pRealm->m_sHostiles,
					pRealm->m_sHostileKills,
					pRealm->m_sHostileKills * 100 / ((pRealm->m_sHostileBirths != 0) ? pRealm->m_sHostileBirths : 1),
					(int16_t) pRealm->m_dKillsPercentGoal
					);
				break;

			case CRealm::Timed:
				ms_print.SetDestination(pim, &rcDst);
				ms_print.print(
					pim,
					rcDst.sX,
					rcDst.sY,
//					" Time Remaining %d:%2.2d                                Kills %d",
					g_apszScoreDisplayText[pRealm->m_ScoringMode],
					sMinutes,
					sSeconds,
					pRealm->m_sPopulationDeaths
					);
				break;

			case CRealm::TimedGoal:
				ms_print.SetDestination(pim, &rcDst);
				ms_print.print(
					pim,
					rcDst.sX,
					rcDst.sY,
//					" Time Remaining %d:%2.2d            Kills %d               Remaining %d / %d",
					g_apszScoreDisplayText[pRealm->m_ScoringMode],
					sMinutes,
					sSeconds,
					pRealm->m_sPopulationDeaths,
					pRealm->m_sKillsGoal - pRealm->m_sPopulationDeaths, pRealm->m_sPopulation
					);
				break;

			case CRealm::TimedFlag:
				ms_print.SetDestination(pim, &rcDst);
				ms_print.print(
					pim,
					rcDst.sX,
					rcDst.sY,
//					" Time Remaining %d:%2.2d",
					g_apszScoreDisplayText[pRealm->m_ScoringMode],
					sMinutes,
					sSeconds
					);
					break;

			case CRealm::Goal:
				ms_print.SetDestination(pim, &rcDst);
				ms_print.print(
					pim,
					rcDst.sX,
					rcDst.sY,
//					" Kills %d                     Remaining %d            Time Elapsed %d:%2.2d",
					g_apszScoreDisplayText[pRealm->m_ScoringMode],
					pRealm->m_sPopulationDeaths,
					pRealm->m_sKillsGoal - pRealm->m_sPopulationDeaths /*pRealm->m_sPopulation*/,
					sMinutes,
					sSeconds
					);
				break;

			case CRealm::CaptureFlag:
				ms_print.SetDestination(pim, &rcDst);
				ms_print.print(
					pim,
					rcDst.sX,
					rcDst.sY,
//					" Time Elapsed %d:%2.2d",
					g_apszScoreDisplayText[pRealm->m_ScoringMode], 
					sMinutes,
					sSeconds
					);
				break;

			case CRealm::Checkpoint:
				ms_print.SetDestination(pim, &rcDst);
				ms_print.print(
					pim,
					rcDst.sX,
					rcDst.sY,
//					" Clock %d:%2.2d    You have %d flags    Flags Remaining %d",
					g_apszScoreDisplayText[pRealm->m_ScoringMode],
					sMinutes,
					sSeconds,
					pRealm->m_sFlagsCaptured,
					pRealm->m_asClassNumThings[CThing::CFlagID] - pRealm->m_sFlagsCaptured
					);
				break;

			default:
				break;

		}
		g_scoreboard.m_lLastScoreDrawTime	= lCurTime;

		// Display the status or mission statement line
		if (lCurTime < g_scoreboard.m_lLastStatusDrawTime + STATUS_DISPLAY_TIMEOUT)
		{
			switch (pRealm->m_ScoringMode)
			{
				case CRealm::MPFrag:
					rcDst.sY = prc->sY + MP_PRINT_Y3;
					if (pRealm->m_sKillsGoal < 1)
					{
						rcDst.sX = prc->sX + 0;
						ms_print.SetDestination(pim, &rcDst);
						ms_print.print(
							rcDst.sX,
							rcDst.sY,
//							" There are no time or kill limits on this game - play as long as you like"
							g_apszScoreGoalText[CRealm::MPLastManTimedFrag] // Cheating since this is
																							// Really none of the scoring modes

						);
					}
					else
					{
						rcDst.sX = prc->sX + 220;
						ms_print.SetDestination(pim, &rcDst);
						ms_print.print(
							rcDst.sX,
							rcDst.sY,
//							" The first player to get %d kills wins",
							g_apszScoreGoalText[pRealm->m_ScoringMode],
							pRealm->m_sKillsGoal
						);
					}

					break;

				case CRealm::MPTimed:
					rcDst.sY = prc->sY + MP_PRINT_Y3;
					rcDst.sX = prc->sX + 180;
					ms_print.SetDestination(pim, &rcDst);
					ms_print.print(
						rcDst.sX,
						rcDst.sY,
//						" The player with the most kills when time expires is the winner"
						g_apszScoreGoalText[pRealm->m_ScoringMode]
						);
					break;

				case CRealm::MPTimedFrag:
					rcDst.sY = prc->sY + MP_PRINT_Y3;
					rcDst.sX = prc->sX + 220;
					ms_print.SetDestination(pim, &rcDst);
					ms_print.print(
						rcDst.sX,
						rcDst.sY,
//						" Try to reach %d kills before time expires",
						g_apszScoreGoalText[pRealm->m_ScoringMode],
						pRealm->m_sKillsGoal
						);
					break;

				case CRealm::Standard:
					rcDst.sY = prc->sY + STATUS_PRINT_Y2;

					ms_print.SetDestination(pim, &rcDst);
					ms_print.print(
						rcDst.sX,
						rcDst.sY,
//						"      You must kill %d%% of the hostiles.",
						g_apszScoreGoalText[pRealm->m_ScoringMode],
						(int16_t) pRealm->m_dKillsPercentGoal
						);
					break;

				case CRealm::Timed:
					rcDst.sY = prc->sY + STATUS_PRINT_Y2;
					ms_print.SetDestination(pim, &rcDst);
					ms_print.print(
						rcDst.sX,
						rcDst.sY,
//						" Score as many kills as possible in the time remaining."
						g_apszScoreGoalText[pRealm->m_ScoringMode]
						);
					break;

				case CRealm::TimedGoal:
					rcDst.sY = prc->sY + STATUS_PRINT_Y2;
					ms_print.SetDestination(pim, &rcDst);
					ms_print.print(
						rcDst.sX,
						rcDst.sY,
//						" Kill everyone before time runs out."
						g_apszScoreGoalText[pRealm->m_ScoringMode]
						);
					break;

				case CRealm::TimedFlag:
					rcDst.sY = prc->sY + STATUS_PRINT_Y2;
					ms_print.SetDestination(pim, &rcDst);
					ms_print.print(
						rcDst.sX,
						rcDst.sY,
//						" Capture the flag before time runs out."
						g_apszScoreGoalText[pRealm->m_ScoringMode]
						);
						break;

				case CRealm::Goal:
					rcDst.sY = prc->sY + STATUS_PRINT_Y2;
					ms_print.SetDestination(pim, &rcDst);
					ms_print.print(
						rcDst.sX,
						rcDst.sY,
//						" Kill %d People in as little time as possible.",
						g_apszScoreGoalText[pRealm->m_ScoringMode],
						pRealm->m_sKillsGoal
						);
					break;

				case CRealm::CaptureFlag:
					rcDst.sY = prc->sY + STATUS_PRINT_Y2;
					ms_print.SetDestination(pim, &rcDst);
					ms_print.print(
						rcDst.sX,
						rcDst.sY,
//						" Capture the flag in as little time as possible."
						g_apszScoreGoalText[pRealm->m_ScoringMode]
						);
					break;

				case CRealm::Checkpoint:
					rcDst.sY = prc->sY + STATUS_PRINT_Y2;
					ms_print.SetDestination(pim, &rcDst);
					ms_print.print(
						rcDst.sX,
						rcDst.sY,
//						" Grab as many flags as possible before time runs out."
						g_apszScoreGoalText[pRealm->m_ScoringMode]
						);
					break;

				default:
					break;
			}
		}


		// Note that we drew.
		bDrew	= true;
	}

	return bDrew;
}

//////////////////////////////////////////////////////////////////////////////
// ScoreDisplayStatus
//
//		Sets the status display timer so it will show for a few seconds
//////////////////////////////////////////////////////////////////////////////

void ScoreDisplayStatus(CRealm* pRealm)
{
	g_scoreboard.m_lLastStatusDrawTime = pRealm->m_time.GetGameTime();
}

//////////////////////////////////////////////////////////////////////////////
// ScoreSetMode - Set mode of scoring
//////////////////////////////////////////////////////////////////////////////

void ScoreSetMode(CScoreboard::ScoringMode Mode)
{
	g_scoreboard.SetScoringMode(Mode);
}


//////////////////////////////////////////////////////////////////////////////
// ScoreDisplayHighScores
//////////////////////////////////////////////////////////////////////////////

void ScoreDisplayHighScores(	// Returns nothing.
	CRealm* pRealm,				// In:  Realm won.
	CNetClient* pclient,			// In:  Client ptr for MP mode, or NULL in SP mode.
	int32_t lMaxTimeOut)				// In:  Max time on score screen (quits after this
										// duration, if not -1).
{
	RGuiItem* pguiRoot;
	RGuiItem::ms_print.SetFont(15, &g_fontPostal);
	RProcessGui guiDialog;
	int16_t sResult;
	char szScoringExplanation[512]	= "";
	int32_t alScores[MAX_HIGH_SCORES];
	char astrNames[MAX_HIGH_SCORES][MAX_PLAYER_NAME_LEN + 1];
	char szKeyName[256];
	RPrefs scores;

	typedef enum
		{
		Value,
		Time
		} ValType;

	ValType	vtScoringUnit	= Value;

	TRACE("LONG_MAX = %d\n", LONG_MAX);
	// Let's just not do any of this for modes that have no scoring . . .
	if (pRealm->m_ScoringMode >= CRealm::Timed && pRealm->m_ScoringMode <= CRealm::MPLastManTimedFrag && GetInputMode() != INPUT_MODE_PLAYBACK)
	{
		// Determine player's score and note how we determined it in a string
		// for the user.
		int32_t	lPlayerScore	= 0;
		switch (pRealm->m_ScoringMode)
			{
			case CRealm::Standard:
				// No high scores for this mode
				break;

			case CRealm::Timed:
				sprintf(szScoringExplanation, g_apszScoreExplanations[pRealm->m_ScoringMode], CreateTimeString(pRealm->m_lScoreInitialTime) );
				// Number of deaths.
				lPlayerScore	= pRealm->m_sPopulationDeaths;
				vtScoringUnit	= Value;
				break;

			case CRealm::TimedGoal:
				sprintf(szScoringExplanation, g_apszScoreExplanations[pRealm->m_ScoringMode], pRealm->m_sKillsGoal);
				// Elapsed time, if goal met.
				if (pRealm->m_sPopulationDeaths >= pRealm->m_sKillsGoal)
					{
					lPlayerScore	= pRealm->m_lScoreInitialTime - pRealm->m_lScoreTimeDisplay;
					}
				else
					{
					// Really bad elapsed time.
					lPlayerScore	= LONG_MAX;
					}

				vtScoringUnit	= Time;
				break;

			case CRealm::TimedFlag:
				sprintf(szScoringExplanation, g_apszScoreExplanations[pRealm->m_ScoringMode], pRealm->m_sKillsGoal);
				// Elapsed time, if goal met.
				if (pRealm->m_sFlagbaseCaptured >= pRealm->m_sFlagsGoal)
					{
					lPlayerScore	= pRealm->m_lScoreInitialTime - pRealm->m_lScoreTimeDisplay;
					}
				else
					{
					// Really bad elapsed time.
					lPlayerScore	= LONG_MAX;
					}

				vtScoringUnit	= Time;
				break;

			case CRealm::CaptureFlag:
				sprintf(szScoringExplanation, g_apszScoreExplanations[pRealm->m_ScoringMode], pRealm->m_sKillsGoal);
				// Time left, if goal met.
				if (pRealm->m_sFlagbaseCaptured >= pRealm->m_sFlagsGoal)
					{
					lPlayerScore	= pRealm->m_lScoreTimeDisplay;
					}
				else
					{
					// Really bad time.
					lPlayerScore	= LONG_MIN;
					}

				vtScoringUnit	= Time;
				break;

			case CRealm::Goal:
				sprintf(szScoringExplanation, g_apszScoreExplanations[pRealm->m_ScoringMode], pRealm->m_sKillsGoal);
				// Time left, if goal met.
				if (pRealm->m_sPopulationDeaths >= pRealm->m_sKillsGoal)
					{
					lPlayerScore	= pRealm->m_lScoreTimeDisplay;
					}
				else
					{
					// Really bad time.
					lPlayerScore	= LONG_MIN;
					}

				vtScoringUnit	= Time;
				break;

			case CRealm::Checkpoint:
				sprintf(szScoringExplanation, g_apszScoreExplanations[pRealm->m_ScoringMode], 0);
				// Number of flags captured.
				lPlayerScore	= pRealm->m_sFlagsCaptured;
				vtScoringUnit	= Value;
				break;

			case CRealm::MPTimed:
			case CRealm::MPFrag:
			case CRealm::MPLastMan:
			case CRealm::MPCaptureFlag:
			case CRealm::MPTimedFlag:
			case CRealm::MPTimedFrag:
			case CRealm::MPLastManFrag:
			case CRealm::MPLastManTimed:
			case CRealm::MPLastManTimedFrag:

				sprintf(szScoringExplanation, g_apszScoreExplanations[pRealm->m_ScoringMode], MAX_HIGH_SCORES);
				vtScoringUnit	= Value;
				break;
			}

		// Get the name or description string for this realm file and use that as
		// the prefs section name from which to get the high scores.  Scores are
		// stored as longs whether they be times in seconds or counts and the names
		// are stored as strings.

		// Temporarily I will base the section name on the scoring method
		// until the realm description function is available.

		int16_t	sPlayersScorePosition	= -1;	// Valid score index once/if we find a slot
														// for this player's score.

		// If not a multiplayer scoring . . .
		if (pRealm->m_flags.bMultiplayer == false)
			{
			// Try to open the file, but if it doesn't exist, then we simply won't be
			// getting any values from it.
			int16_t sOpenRes = scores.Open(FindCorrectFile(HIGHSCORE_SCORES_FILE, "aAwW+"), "r"); // Say we're writing so that FindCorrectFile will give us the prefpath.
			TRACE("sOpenRes = %d\n", sOpenRes);
			// Read in the scores file
			int16_t	sSrcIndex;
			int16_t	sDstIndex;
			for (sSrcIndex = 0, sDstIndex = 0; sDstIndex < MAX_HIGH_SCORES; sDstIndex++)
				{
				sprintf(szKeyName, "Player%d", sSrcIndex);

				if (sOpenRes == 0)
					scores.GetVal((char*) pRealm->m_rsRealmString, szKeyName, "<Empty>", astrNames[sDstIndex]);
				else
					strcpy(astrNames[sDstIndex], "<Empty>");
					
				// Determine if our score beat this score.
				bool	bPlayerBeatThisScore	= false;
				sprintf(szKeyName, "Score%d", sSrcIndex);
				// Some scoring modes need to default to zero scores, but the timed levels
				// need to default to some high, easy to beat time if there is no saved score
				if (vtScoringUnit == Value)
					{
					if (sOpenRes == 0)
						scores.GetVal((char*) pRealm->m_rsRealmString, szKeyName, (int32_t) 0, &(alScores[sDstIndex]));
					else
						alScores[sDstIndex] = 0;
						
					// Did we get a higher value than in score?
					if (lPlayerScore > alScores[sDstIndex])
						{
						bPlayerBeatThisScore	= true;
						}
					}
				else
					{
					if (sOpenRes == 0)
						scores.GetVal((char*) pRealm->m_rsRealmString, szKeyName, (int32_t) 3600000, &(alScores[sDstIndex]));
					else
						alScores[sDstIndex] = (int32_t) 3600000;
			
					// Did we get a better time than read in score?
					if (lPlayerScore < alScores[sDstIndex] )
						{
						bPlayerBeatThisScore	= true;
						}
					}

				// If we beat this score and haven't yet found a score position . . .
				if (bPlayerBeatThisScore == true && sPlayersScorePosition < 0)
					{
					// Remember player's score.
					alScores[sDstIndex]		= lPlayerScore;
					// Clear player's name.
					astrNames[sDstIndex][0]	= '\0';
					// Remember player's score position.
					sPlayersScorePosition	= sDstIndex;
					// Don't increment the source index.
					}
				else
					{
					// Move to the next source score val and name from the INI.
					sSrcIndex++;
					}
				}

			scores.Close();
			}
		else
			{
			ASSERT(pclient);

			int32_t	alTempScores[MAX_HIGH_SCORES];
			char	astrTempNames[MAX_HIGH_SCORES][MAX_PLAYER_NAME_LEN + 1];

			int16_t	sIndex;
			for (sIndex = 0; sIndex < MAX_HIGH_SCORES ; sIndex++)
				{
				if (sIndex < pRealm->m_asClassNumThings[CThing::CDudeID])
					{
					strncpy(astrTempNames[sIndex], pclient->GetPlayerName(sIndex), MAX_PLAYER_NAME_LEN);
					// Strncpy does not NULL terminate if the 'n' is less than or equal to the length
					// of the src string.
					astrTempNames[sIndex][MAX_PLAYER_NAME_LEN]	= '\0';

					alTempScores[sIndex]	= g_scoreboard.m_asScores[sIndex];
					}
				else
					{
					astrTempNames[sIndex][0]	= '\0';
					alTempScores[sIndex]			= LONG_MIN + 1;
					}
				}

			// Find the largest score (most frags in all modes) and put it at the
			// next position.
			int16_t	sDstIndex;
			int16_t	sSrcIndex;
			int16_t	sHighestScoreIndex;
			int32_t	lHighestScore;
			
			// This declaration relies on false being zero!!
			ASSERT(false == 0);
			bool	abAlreadyCopied[MAX_HIGH_SCORES]	=	{ false, };

			for (sDstIndex = 0;	sDstIndex < MAX_HIGH_SCORES; sDstIndex++)
				{
				sHighestScoreIndex	= -1;
				lHighestScore			= LONG_MIN;

				// Find the highest score of the ones not yet copied.
				for (sSrcIndex = 0; sSrcIndex < MAX_HIGH_SCORES; sSrcIndex++)
					{
					// If not yet copied . . .
					if (abAlreadyCopied[sSrcIndex] == false)
						{
						// If this score is higher . . .
						if (alTempScores[sSrcIndex] > lHighestScore)
							{
							sHighestScoreIndex	= sSrcIndex;
							lHighestScore			= alTempScores[sSrcIndex];
							}
						}
					}

				// Use the highest score.
				ASSERT(sHighestScoreIndex != -1);
				alScores[sDstIndex]	= alTempScores[sHighestScoreIndex];
				// This copy is safe b/c astrTempNames[] and astrNames[] are the
				// same length.
				
				// Check for safety (future changes).
				ASSERT(sizeof(astrNames[0]) >= sizeof(astrTempNames[0]) );

				strcpy(astrNames[sDstIndex], astrTempNames[sHighestScoreIndex] );
				// Note that this score is already placed.
				abAlreadyCopied[sHighestScoreIndex]	= true;

				// If this is us . . .
				if (sHighestScoreIndex == pclient->GetID() )
					{
					// Remember our position (placement) so we can highlight it.
					sPlayersScorePosition	= sDstIndex;
					}
				}

			// Note that Player's score position stays -1 since there's no name to enter.
			}


		int16_t i;

		#ifdef HIGH_SCORE_DLG
		if (rspGetResource(&g_resmgrShell, HIGHSCORE_DIALOG_FILE, (RDlg**)&pguiRoot) == 0)
		{
			TRACE("Bazooper.\n");
			RGuiItem* pguiOk			= pguiRoot->GetItemFromId(1);
			RGuiItem* pguiCancel		= pguiRoot->GetItemFromId(2);

			RTxt* ptextExplain1		= (RTxt*) pguiRoot->GetItemFromId(50);
			RTxt* ptextExplain2		= (RTxt*) pguiRoot->GetItemFromId(51);
			RListBox*	plbScores	= (RListBox*) pguiRoot->GetItemFromId(1000);

			// Set to the input field if the player gets a high score.
			RGuiItem*	pguiPlayersName	= NULL;
		#endif
			// Create and add all score items.
			int16_t	sScoreIndex;
			bool	bGotAllScoreItems	= true;
		#ifdef HIGH_SCORE_DLG
			if (plbScores)
				{
				ASSERT(plbScores->m_type == RGuiItem::ListBox);
		#endif
				for (sScoreIndex = 0; sScoreIndex < MAX_HIGH_SCORES && bGotAllScoreItems; sScoreIndex++)
					{
					// If there's an associated name or this is the one we're adding . . .
					if (astrNames[sScoreIndex][0] != '\0' || sPlayersScorePosition == sScoreIndex)
						{
						#ifdef HIGH_SCORE_DLG
						RGuiItem*	pguiItem;
						if (rspGetResource(&g_resmgrShell, HIGHSCORE_ITEM_FILE, &pguiItem) == 0)
							{
							// Get the two settable items.
							RGuiItem*	pguiName		= pguiItem->GetItemFromId(100);
							RGuiItem*	pguiScore	= pguiItem->GetItemFromId(101);
							RGuiItem*	pguiPlace	= pguiItem->GetItemFromId(102);
							if (pguiName && pguiScore)
								{
								// Add shadow attributes.
								pguiName->m_sTextEffects			|= RGuiItem::Shadow;
								pguiName->m_u32TextShadowColor	=	TEXT_SHADOW_COLOR;
								pguiScore->m_sTextEffects			|= RGuiItem::Shadow;
								pguiScore->m_u32TextShadowColor	=	TEXT_SHADOW_COLOR;

								// If this is the place for the new name . . .
								if (sPlayersScorePosition == sScoreIndex)
									{
									// Set the focus to this item.
									pguiName->SetFocus();
									// Limit input text to the space in our storage area.
									// Must be edit field for this op.
									ASSERT(pguiName->m_type == RGuiItem::Edit);
									((REdit*)pguiName)->m_sMaxText	= sizeof(astrNames[0]) - 1;
									// Highlight this entry.
									pguiName->m_u32TextColor	= TEXT_HIGHLIGHT_COLOR;
									// Remember which one so we can get the name later.
									pguiPlayersName	= pguiName;
									}
								else
									{
									// Deactivate all others.
									pguiName->m_sActive	= FALSE;
									}

								// Set placement.
								pguiPlace->SetText("%d)", sScoreIndex + 1);
								pguiPlace->Compose();

								// Set name.
								pguiName->SetText("%s", astrNames[sScoreIndex]);
								pguiName->Compose();

								// Set score.
								// There are two types of scores.
								if (vtScoringUnit == Value)
									{
									// Value.
									pguiScore->SetText("%ld %s", alScores[sScoreIndex], g_apszScoreUnits[pRealm->m_ScoringMode] );
									}
								else
									{
									// Time.
									pguiScore->SetText("%s %s", CreateTimeString(alScores[sScoreIndex] ), g_apszScoreUnits[pRealm->m_ScoringMode] );
									}

								pguiScore->Compose();

								// Mark item as an encapsulator.  When an item is marked this way the listbox
								// knows it's okay to move it around and stuff.
								RListBox::MakeEncapsulator(pguiItem);
								
								// Add to the list box . . .
								if (plbScores->AddItem(pguiItem) )
									{
									// Success.
									}
								else
									{
									TRACE("ScoreDisplayHighScores(): Unable to add item to listbox.\n");
									bGotAllScoreItems	= false;
									}
								}
							else
								{
								TRACE("ScoreDisplayHighScores(): Missing items in this instance of \"%d\".\n",
									HIGHSCORE_ITEM_FILE);
								bGotAllScoreItems	= false;
								}
							}
						else
							{
							TRACE("ScoreDisplayHighScores(): Failed to get instance of \"%d\".\n",
								HIGHSCORE_ITEM_FILE);
							bGotAllScoreItems	= false;
							}
						#else
							if (sPlayersScorePosition == sScoreIndex)
							{
								strcpy(astrNames[sScoreIndex], "Dude");
							}
						#endif
						}
					}
				#ifdef HIGH_SCORE_DLG
				// Repaginate now.
				plbScores->AdjustContents();

				// If we have an entry . . .
				if (pguiPlayersName)
					{
					// Make sure it's visible . . .
					plbScores->EnsureVisible(pguiPlayersName, RListBox::Bottom);
					}
				} else
				{
					TRACE("plbScores is false or something.\n");
				}

			if (ptextExplain1 != NULL &&
				 ptextExplain2 != NULL &&
				 plbScores		!= NULL &&
				 bGotAllScoreItems == true)
			{
				// Get some colors free.
				PalTranOn();

				// Set the callbacks for the resource load and discard (note that it 
				// already tried to load it during the above rspGetResource() and failed 
				// b/c the default implementation has no clue about the resmgr).
				pguiRoot->m_fnGetRes			= GuiGetRes;
				pguiRoot->m_fnReleaseRes	= GuiReleaseRes;

				pguiRoot->ReleaseRes();
				// Recompose the root item (does not recompose children).  This time
				// it should successfully find the resources via the Get callback.
				pguiRoot->Compose();
					
				// Let us handle updates.
				guiDialog.m_fnUpdate		= SysUpdate;

				// Center the GUI root.
				pguiRoot->Move(
					g_pimScreenBuf->m_sWidth / 2 - pguiRoot->m_im.m_sWidth / 2,
					g_pimScreenBuf->m_sHeight / 2 - pguiRoot->m_im.m_sHeight / 2);

				// Make the explanation texts shadowed.
				ptextExplain1->m_sTextEffects			|= RGuiItem::Shadow;
				ptextExplain1->m_u32TextShadowColor	=	TEXT_SHADOW_COLOR;
				
				ptextExplain2->m_sTextEffects			|= RGuiItem::Shadow;
				ptextExplain2->m_u32TextShadowColor	=	TEXT_SHADOW_COLOR;
				ptextExplain2->Compose();

				// Store current mouse show level so we can restore it.
				int16_t	sOrigShowLevel	= rspGetMouseCursorShowLevel();
				// Make sure it's visible.
// Let's not do this and instead try to insinuate keyboard use.
//				rspSetMouseCursorShowLevel(1);

				// Make sure there's no timeout on while player is adding their name.
				ms_lScoreMaxTimeOut	= LONG_MAX;

				// If we want a high score from this player . . .
				if (sPlayersScorePosition >= 0 && pRealm->m_flags.bMultiplayer == false)
					{
					TRACE("High score! Good job. You must've killed at least one enemy to beat the default score.\n");
					// Ask the player for their name.
					ptextExplain1->SetText("Please enter your name.\n");
					ptextExplain1->Compose();
					// Don't clean the screen when done so we can have a smooth transition
					// to the next DoModal().
					guiDialog.m_sFlags	= RProcessGui::NoCleanScreen;
					// Do the dialog once to get the name.
					guiDialog.DoModal(pguiRoot, pguiOk, pguiCancel);
					// Clear the focus.
					RGuiItem::SetFocus(NULL);

					ASSERT(pguiPlayersName);
					// Get the user's name for saving.
					pguiPlayersName->GetText(astrNames[sPlayersScorePosition], sizeof(astrNames[sPlayersScorePosition]) );
					}

				// Set the explanation text.
				ptextExplain1->SetText("%s", szScoringExplanation);
				ptextExplain1->Compose();

				// Don't set time out time until after player has entered name for
				// reduced frustration.
				// If timeout specified . . . 
				if (lMaxTimeOut >= 0)
					{
					ms_lScoreMaxTimeOut	= rspGetMilliseconds() + lMaxTimeOut;
					}
				else
					{
					ms_lScoreMaxTimeOut	= LONG_MAX;
					}

				// Set the focus to the listbox's vertical scrollbar so that the arrows will work.
				plbScores->m_sbVert.SetFocus();

				// This time we want the screen cleared.
				guiDialog.m_sFlags	= 0;
				// Display the high scores.
				TRACE("Do you know what 'modal' means?\n");
				guiDialog.DoModal(pguiRoot, pguiOk, pguiCancel);
				TRACE("Hooray!\n");

				// Restore mouse cursor show level.
				rspSetMouseCursorShowLevel(sOrigShowLevel);
				#endif
				TRACE("sPlayersScorePosition = %d, pRealm->m_flags.bMultiplayer = %s\n", sPlayersScorePosition, pRealm->m_flags.bMultiplayer ? "true" : "false");
				// If we got a high score . . .
				if (sPlayersScorePosition >= 0 && pRealm->m_flags.bMultiplayer == false)
					{
					RPrefs prefsScores;
					// Save the scores to the file.  First we open it in read+ mode, which is
					// safe if the file already exists.  If that fails, we assume the file does
					// NOT exist and we try to open it in write+ mode, which will clobber the
					// contents of the file if it does exist.
					sResult = prefsScores.Open(HIGHSCORE_SCORES_FILE, "r+");
					if (sResult != SUCCESS)
						sResult = prefsScores.Open(HIGHSCORE_SCORES_FILE, "w+");
					if (sResult == SUCCESS)
						{
						for (i = 0; i < MAX_HIGH_SCORES; i++)
							{
							sprintf(szKeyName, "Player%d", i);
							prefsScores.SetVal((char*) pRealm->m_rsRealmString, szKeyName, astrNames[i]);
							sprintf(szKeyName, "Score%d", i);
							prefsScores.SetVal((char*) pRealm->m_rsRealmString, szKeyName, alScores[i]);
							}
						}
					prefsScores.Close();
					}

#ifdef HIGH_SCORE_DLG
				// Put the colors back.
				PalTranOff();

			}
			if (plbScores)
				{
#if 0
				// Get rid of all score item instances.
				RGuiItem*	pguiScoreItem	= plbScores->GetFirst();
				while (pguiScoreItem)
					{
					// Remove the listbox's encapsulator property.
					pguiScoreItem->RemoveProp(ENCAPSULATOR_PROP_KEY);

					// Release the current one.
					rspReleaseResourceInstance(&g_resmgrShell, &pguiScoreItem);

					// Set the next one as the current.
					pguiScoreItem	= plbScores->GetNext();
					}
#else
				plbScores->RemoveAll();
#endif
				}
			TRACE("Whew, that was a wild ride.\n");
			rspReleaseResource(&g_resmgrShell, &pguiRoot);
		} else {
			TRACE("failed to load GUI resource\n");
		}
#endif
	}
}

//////////////////////////////////////////////////////////////////////////////
// ScoreHighestKills
//
// Return the highest number of kills among all of the players.  This will
// be called to determine if a frag limit level is over.
//
//////////////////////////////////////////////////////////////////////////////

int16_t ScoreHighestKills(CRealm* pRealm)
{
	int16_t sHighest = 0;
	int16_t sNumDudes = pRealm->m_asClassNumThings[CThing::CDudeID];	
	int16_t i;

	for (i = 0; i < sNumDudes; i++)
	{
		if (g_scoreboard.m_asScores[i] > sHighest)
			sHighest = g_scoreboard.m_asScores[i];
	}
	
	return sHighest;	
}

//////////////////////////////////////////////////////////////////////////////
// Score_GetBestForLvl
//
// Return the highest number of kills among all of the players.  This will
// be called to determine if a frag limit level is over.
//
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
// EOF
//////////////////////////////////////////////////////////////////////////////