1 /* SCCS Id: @(#)topten.c 3.4 2000/01/21 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
7 #include "patchlevel.h"
10 /* We don't want to rewrite the whole file, because that entails */
11 /* creating a new version which requires that the old one be deletable. */
12 # define UPDATE_RECORD_IN_PLACE
16 * Updating in place can leave junk at the end of the file in some
17 * circumstances (if it shrinks and the O.S. doesn't have a straightforward
18 * way to truncate it). The trailing junk is harmless and the code
19 * which reads the scores will ignore it.
21 #ifdef UPDATE_RECORD_IN_PLACE
22 static long final_fpos
;
25 #define done_stopprint program_state.stopprint
27 #define newttentry() (struct toptenentry *) alloc(sizeof(struct toptenentry))
28 #define dealloc_ttentry(ttent) free((void *) (ttent))
29 #define NAMSZ 10 /* several parts of this code depend on this, don't just change this value! --Amy */
32 #define PERSMAX 10000 /* entries per name/uid per char. allowed */
33 #define POINTSMIN 1 /* must be > 0 */
34 #define ENTRYMAX 10000 /* must be >= 10 */
36 #if !defined(MICRO) && !defined(MAC) && !defined(WIN32) && !defined(PUBLIC_SERVER)
37 #define PERS_IS_UID /* delete for PERSMAX per name; now per uid */
40 struct toptenentry
*tt_next
;
41 #ifdef UPDATE_RECORD_IN_PLACE
45 int deathdnum
, deathlev
;
46 int maxlvl
, hp
, maxhp
, deaths
;
47 int ver_major
, ver_minor
, patchlevel
;
48 long deathdate
, birthdate
;
53 char plrole
[ROLESZ
+1];
54 char plrace
[ROLESZ
+1];
55 char plgend
[ROLESZ
+1];
56 char plalign
[ROLESZ
+1];
61 STATIC_DCL
void topten_print(const char *);
62 STATIC_DCL
void topten_print_bold(const char *);
63 STATIC_DCL xchar
observable_depth(d_level
*);
64 STATIC_DCL
void outheader(void);
65 STATIC_DCL
void outentry(int,struct toptenentry
*,BOOLEAN_P
);
66 STATIC_DCL
void readentry(FILE *,struct toptenentry
*);
67 STATIC_DCL
void writeentry(FILE *,struct toptenentry
*);
68 STATIC_DCL
void free_ttlist(struct toptenentry
*);
70 STATIC_DCL
void write_xlentry(FILE *,struct toptenentry
*);
71 STATIC_DCL
long encodexlogflags(void);
73 STATIC_DCL
int classmon(char *,BOOLEAN_P
);
74 STATIC_DCL
int score_wanted(BOOLEAN_P
, int,struct toptenentry
*,int,const char **,int);
76 STATIC_DCL
long encodeconduct(void);
79 STATIC_DCL
long encodeachieve(void);
80 STATIC_DCL
char* encodeachieveX(void);
83 STATIC_DCL
void nsb_mung_line(char*);
84 STATIC_DCL
void nsb_unmung_line(char*);
87 /* must fit with end.c; used in rip.c */
88 NEARDATA
const char * const killed_by_prefix
[] = {
89 "killed by ", "betrayed by ", "choked on ", "poisoned by ", "died of ",
90 "drowned in ", "burned by ", "dissolved in ", "crushed to death by ",
91 "petrified by ", "turned to slime by ", "killed by ",
95 static winid toptenwin
= WIN_ERR
;
97 #ifdef RECORD_START_END_TIME
98 static time_t deathtime
= 0L;
105 if (toptenwin
== WIN_ERR
)
108 putstr(toptenwin
, ATR_NONE
, x
);
115 if (toptenwin
== WIN_ERR
)
118 putstr(toptenwin
, ATR_BOLD
, x
);
122 observable_depth(lev
)
125 #if 0 /* if we ever randomize the order of the elemental planes, we
126 must use a constant external representation in the record file */
127 if (In_endgame(lev
)) {
128 if (Is_astralevel(lev
)) return -5;
129 else if (Is_waterlevel(lev
)) return -4;
130 else if (Is_firelevel(lev
)) return -3;
131 else if (Is_airlevel(lev
)) return -2;
132 else if (Is_earthlevel(lev
)) return -1;
133 else return 0; /* ? */
139 #ifdef RECORD_CONDUCT
145 if(u
.uconduct
.unvegetarian
) e
|= 0x1L
;
146 if(u
.uconduct
.unvegan
) e
|= 0x2L
;
147 if(u
.uconduct
.food
) e
|= 0x4L
;
148 if(u
.uconduct
.gnostic
) e
|= 0x8L
;
149 if(u
.uconduct
.weaphit
) e
|= 0x10L
;
150 if(u
.uconduct
.killer
) e
|= 0x20L
;
151 if(u
.uconduct
.literate
) e
|= 0x40L
;
152 if(u
.uconduct
.polypiles
) e
|= 0x80L
;
153 if(u
.uconduct
.polyselfs
) e
|= 0x100L
;
154 if(u
.uconduct
.wishes
) e
|= 0x200L
;
155 if(u
.uconduct
.wisharti
) e
|= 0x400L
;
156 if(num_genocides()) e
|= 0x800L
;
157 if(u
.uconduct
.praydone
) e
|= 0x1000L
;
166 struct toptenentry
*tt
;
168 #ifdef NO_SCAN_BRACK /* Version_ Pts DgnLevs_ Hp___ Died__Born id */
169 static const char fmt
[] = "%d %d %d %ld %d %d %d %d %d %d %ld %ld %d%*c";
170 static const char fmt005
[] = "%s %c %s %s%*c";
171 static const char fmt33
[] = "%s %s %s %s %s %s%*c";
173 static const char fmt
[] = "%d.%d.%d %ld %d %d %d %d %d %d %ld %ld %d ";
174 static const char fmt005
[] = "%s %c %[^,],%[^\n]%*c";
175 static const char fmt33
[] = "%s %s %s %s %[^,],%[^\n]%*c";
178 #ifdef UPDATE_RECORD_IN_PLACE
179 /* note: fscanf() below must read the record's terminating newline */
180 final_fpos
= tt
->fpos
= ftell(rfile
);
184 #ifdef RECORD_CONDUCT
188 if(fscanf(rfile
, fmt
,
189 &tt
->ver_major
, &tt
->ver_minor
, &tt
->patchlevel
,
190 &tt
->points
, &tt
->deathdnum
, &tt
->deathlev
,
191 &tt
->maxlvl
, &tt
->hp
, &tt
->maxhp
, &tt
->deaths
,
192 &tt
->deathdate
, &tt
->birthdate
,
193 &tt
->uid
) != TTFIELDS
)
197 /* Check for backwards compatibility */
198 if (!tt
->ver_major
&& !tt
->ver_minor
&& tt
->patchlevel
< 6) {
201 if (fscanf(rfile
, fmt005
,
202 tt
->plrole
, tt
->plgend
,
203 tt
->name
, tt
->death
) != 4)
205 tt
->plrole
[1] = '\0';
206 if ((i
= str2role(tt
->plrole
)) >= 0)
207 strcpy(tt
->plrole
, roles
[i
].filecode
);
208 tt
->plrole
[ROLESZ
] = 0;
209 strcpy(tt
->plrace
, "?");
210 strcpy(tt
->plgend
, (tt
->plgend
[0] == 'M') ? "Mal" : "Fem");
211 strcpy(tt
->plalign
, "?");
212 } else if (fscanf(rfile
, fmt33
,
213 tt
->plrole
, tt
->plrace
, tt
->plgend
,
214 tt
->plalign
, tt
->name
, tt
->death
) != 6)
218 nsb_unmung_line(tt
->name
);
219 nsb_unmung_line(tt
->death
);
223 #ifdef RECORD_CONDUCT
225 /* If the string "Conduct=%d" appears, set tt->conduct and remove that
226 * portion of the string */
228 for(dp
= tt
->death
; *dp
; dp
++) {
229 if(!strncmp(dp
, " Conduct=", 9)) {
231 sscanf(dp2
, "%ld", &tt
->conduct
);
232 /* Find trailing null or space */
233 while(*dp2
&& *dp2
!= ' ')
236 /* Cut out the " Conduct=" portion of the death string */
248 if(tt
->conduct
< 0 || tt
->conduct
> 8191)
255 /* check old score entries for Y2K problem and fix whenever found */
256 if (tt
->points
> 0) {
257 if (tt
->birthdate
< 19000000L) tt
->birthdate
+= 19000000L;
258 if (tt
->deathdate
< 19000000L) tt
->deathdate
+= 19000000L;
265 struct toptenentry
*tt
;
267 #ifdef RECORD_CONDUCT
268 char *cp
= eos(tt
->death
);
270 /* Add a trailing " Conduct=%d" to tt->death */
271 /*if(tt->conduct != 8191) {*/
272 cp
= tt
->death
+ strlen(tt
->death
);
273 sprintf(cp
, " Conduct=%ld", tt
->conduct
);
278 nsb_mung_line(tt
->name
);
279 nsb_mung_line(tt
->death
);
280 /* Version_ Pts DgnLevs_ Hp___ Died__Born id */
281 (void) fprintf(rfile
,"%d %d %d %ld %d %d %d %d %d %d %ld %ld %d ",
283 (void) fprintf(rfile
,"%d.%d.%d %ld %d %d %d %d %d %d %ld %ld %d ",
285 tt
->ver_major
, tt
->ver_minor
, tt
->patchlevel
,
286 tt
->points
, tt
->deathdnum
, tt
->deathlev
,
287 tt
->maxlvl
, tt
->hp
, tt
->maxhp
, tt
->deaths
,
288 tt
->deathdate
, tt
->birthdate
, tt
->uid
);
289 if (!tt
->ver_major
&& !tt
->ver_minor
&& tt
->patchlevel
< 6)
291 (void) fprintf(rfile
,"%s %c %s %s\n",
293 (void) fprintf(rfile
,"%s %c %s,%s\n",
295 tt
->plrole
, tt
->plgend
[0],
296 onlyspace(tt
->name
) ? "_" : tt
->name
, tt
->death
);
299 (void) fprintf(rfile
,"%s %s %s %s %s %s\n",
301 (void) fprintf(rfile
,"%s %s %s %s %s,%s\n",
303 tt
->plrole
, tt
->plrace
, tt
->plgend
, tt
->plalign
,
304 onlyspace(tt
->name
) ? "_" : tt
->name
, tt
->death
);
307 nsb_unmung_line(tt
->name
);
308 nsb_unmung_line(tt
->death
);
311 #ifdef RECORD_CONDUCT
312 /* Return the tt->death line to the original form */
318 /* Use \t instead of ":" so that we don't have to mangle anything else (3.6.0)*/
319 #define XLOG_SEP "\t"
322 write_xlentry(rfile
,tt
)
324 struct toptenentry
*tt
;
329 /* Log all of the data found in the regular logfile */
331 "version=slex-%d.%d.%d"
332 XLOG_SEP
"points=%ld"
333 XLOG_SEP
"deathdnum=%d"
334 XLOG_SEP
"deathlev=%d"
339 XLOG_SEP
"deathdate=%ld"
340 XLOG_SEP
"birthdate=%ld"
342 tt
->ver_major
, tt
->ver_minor
, tt
->patchlevel
,
343 tt
->points
, tt
->deathdnum
, tt
->deathlev
,
344 tt
->maxlvl
, tt
->hp
, tt
->maxhp
, tt
->deaths
,
345 tt
->deathdate
, tt
->birthdate
, tt
->uid
);
352 tt
->plrole
, tt
->plrace
, tt
->plgend
, tt
->plalign
);
354 (void)fprintf(rfile
, XLOG_SEP
"hybrid=%s", hybrid_strcode());
356 (void)fprintf(rfile
, XLOG_SEP
"gamemode=%s", gamemode_strcode());
358 (void)fprintf(rfile
, XLOG_SEP
"name=%s", plname
);
360 (void)fprintf(rfile
, XLOG_SEP
"alias=%s", plalias
);
362 (void)fprintf(rfile
, XLOG_SEP
"death=%s", tt
->death
);
364 #ifdef RECORD_CONDUCT
365 (void)fprintf(rfile
, XLOG_SEP
"conduct=0x%lx", 0x1fffL
& ~encodeconduct());
369 (void)fprintf(rfile
, XLOG_SEP
"turns=%ld", moves
);
372 #ifdef RECORD_ACHIEVE
373 (void)fprintf(rfile
, XLOG_SEP
"achieve=0x%lx", encodeachieve());
374 (void)fprintf(rfile
, XLOG_SEP
"achieveX=%s", encodeachieveX());
377 #ifdef RECORD_REALTIME
378 (void)fprintf(rfile
, XLOG_SEP
"realtime=%ld", (long)realtime_data
.realtime
);
381 #ifdef RECORD_START_END_TIME
382 (void)fprintf(rfile
, XLOG_SEP
"starttime=%ld", (long)u
.ubirthday
);
383 (void)fprintf(rfile
, XLOG_SEP
"endtime=%ld", (long)deathtime
);
386 /* Amy addition: unlike any other variant, your role and race can change during gameplay. This is for junethack,
387 * where a certain competition is about ascending as many as possible starting combinations. */
388 (void)fprintf(rfile
, XLOG_SEP
"role0=%s", ustartrole
.filecode
);
390 (void)fprintf(rfile
, XLOG_SEP
"race0=%s", ustartrace
.filecode
);
392 #ifdef RECORD_GENDER0
393 (void)fprintf(rfile
, XLOG_SEP
"gender0=%s", genders
[flags
.initgend
].filecode
);
397 (void)fprintf(rfile
, XLOG_SEP
"align0=%s",
398 aligns
[1 - u
.ualignbase
[A_ORIGINAL
]].filecode
);
401 fprintf(rfile
, XLOG_SEP
"flags=0x%lx", encodexlogflags());
403 (void)fprintf(rfile
,"%s", "\n");
407 static long encodexlogflags(void) {
421 #endif /* XLOGFILE */
425 struct toptenentry
*tt
;
427 struct toptenentry
*ttnext
;
429 while (tt
->points
> 0) {
430 ttnext
= tt
->tt_next
;
442 int rank
, rank0
= -1, rank1
= 0;
443 int occ_cnt
= PERSMAX
;
444 register struct toptenentry
*t0
, *tprev
;
445 struct toptenentry
*t1
;
447 register int flg
= 0;
454 #endif /* XLOGFILE */
456 /* Under DICE 3.0, this crashes the system consistently, apparently due to
457 * corruption of *rfile somewhere. Until I figure this out, just cut out
458 * topten support entirely - at least then the game exits cleanly. --AC
464 /* If we are in the midst of a panic, cut out topten entirely.
465 * topten uses alloc() several times, which will lead to
466 * problems if the panic was the result of an alloc() failure.
468 if (program_state
.panicking
)
471 if (flags
.toptenwin
) {
472 toptenwin
= create_nhwindow(NHW_TEXT
);
475 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
476 #define HUP if (!program_state.done_hup)
482 restore_colors(); /* make sure the screen is black on white */
484 /* create a new 'topten' entry */
487 /* deepest_lev_reached() is in terms of depth(), and reporting the
488 * deepest level reached in the dungeon death occurred in doesn't
489 * seem right, so we have to report the death level in depth() terms
490 * as well (which also seems reasonable since that's all the player
491 * sees on the screen anyway)
493 t0
->ver_major
= VERSION_MAJOR
;
494 t0
->ver_minor
= VERSION_MINOR
;
495 t0
->patchlevel
= PATCHLEVEL
;
496 t0
->points
= u
.urexp
;
497 t0
->deathdnum
= u
.uz
.dnum
;
498 t0
->deathlev
= observable_depth(&u
.uz
);
499 t0
->maxlvl
= deepest_lev_reached(TRUE
);
501 t0
->maxhp
= u
.uhpmax
;
502 t0
->deaths
= u
.umortality
;
504 (void) strncpy(t0
->plrole
, urole
.filecode
, ROLESZ
);
505 t0
->plrole
[ROLESZ
] = '\0';
506 (void) strncpy(t0
->plrace
, urace
.filecode
, ROLESZ
);
507 t0
->plrace
[ROLESZ
] = '\0';
508 (void) strncpy(t0
->plgend
, genders
[flags
.female
].filecode
, ROLESZ
);
509 t0
->plgend
[ROLESZ
] = '\0';
510 (void) strncpy(t0
->plalign
, aligns
[1-u
.ualign
.type
].filecode
, ROLESZ
);
511 t0
->plalign
[ROLESZ
] = '\0';
512 (void) strncpy(t0
->name
, playeraliasname
, NAMSZ
);
513 t0
->name
[NAMSZ
] = '\0';
515 switch (killer_format
) {
516 default: impossible("bad killer format?");
518 strcat(t0
->death
, killed_by_prefix
[how
]);
519 (void) strncat(t0
->death
, an(killer
),
520 DTHSZ
-strlen(t0
->death
));
523 strcat(t0
->death
, killed_by_prefix
[how
]);
524 (void) strncat(t0
->death
, killer
,
525 DTHSZ
-strlen(t0
->death
));
527 case NO_KILLER_PREFIX
:
528 (void) strncat(t0
->death
, killer
, DTHSZ
);
531 t0
->birthdate
= yyyymmdd(u
.ubirthday
);
532 t0
->deathdate
= yyyymmdd((time_t)0L);
534 #ifdef RECORD_START_END_TIME
535 /* Make sure that deathdate and deathtime refer to the same time; it
536 * wouldn't be good to have deathtime refer to the day after deathdate. */
538 #if defined(BSD) && !defined(POSIX_TYPES)
539 (void) time((long *)&deathtime
);
541 (void) time(&deathtime
);
544 t0
->deathdate
= yyyymmdd(deathtime
);
546 t0
->deathdate
= yyyymmdd((time_t)0L);
547 #endif /* RECORD_START_END_TIME */
549 #ifdef RECORD_CONDUCT
550 t0
->conduct
= encodeconduct();
553 #ifdef UPDATE_RECORD_IN_PLACE
557 #ifdef LOGFILE /* used for debugging (who dies of what, where) */
559 if (lock_file_area(LOGAREA
, LOGFILE
, 10)) {
561 if (lock_file(LOGFILE
, SCOREPREFIX
, 10)) {
563 if(!(lfile
= fopen_datafile_area(LOGAREA
, LOGFILE
, "a", SCOREPREFIX
))) {
564 HUP
raw_print("Cannot open log file!");
566 writeentry(lfile
, t0
);
567 (void) fclose(lfile
);
569 unlock_file_area(LOGAREA
, LOGFILE
);
575 if(lock_file_area(LOGAREA
, XLOGFILE
, 10)) {
577 if(lock_file(XLOGFILE
, SCOREPREFIX
, 10)) {
579 if(!(xlfile
= fopen_datafile_area(LOGAREA
, XLOGFILE
, "a", SCOREPREFIX
))) {
580 HUP
raw_print("Cannot open extended log file!");
582 write_xlentry(xlfile
, t0
);
583 (void) fclose(xlfile
);
585 unlock_file_area(LOGAREA
, XLOGFILE
);
587 #endif /* XLOGFILE */
589 if (wizard
|| discover
|| u
.freeplaymode
) {
590 if (how
!= PANICKED
) HUP
{
594 "Since you were in %s mode, the score list will not be checked.",
595 wizard
? "wizard" : u
.freeplaymode
? "freeplay" : "discover");
607 /* "Forget Quitters" patch - Elronnd suggested that if the game went on for long enough, it should count --Amy */
608 if (how
== QUIT
&& (moves
&& moves
< 100)) {
609 char pbuf
[]="Since you quit, the score list will not be checked.";
621 /* some startscummers will escape instead, but probably very early --Amy */
622 if (how
== ESCAPED
&& (moves
&& moves
< 10)) {
623 char pbuf
[]="Since you escaped early, the score list will not be checked.";
636 if (!lock_file_area(NH_RECORD_AREA
, NH_RECORD
, 60))
638 if (!lock_file(NH_RECORD
, SCOREPREFIX
, 60))
642 #ifdef UPDATE_RECORD_IN_PLACE
643 rfile
= fopen_datafile_area(NH_RECORD_AREA
, NH_RECORD
, "r+", SCOREPREFIX
);
645 rfile
= fopen_datafile_area(NH_RECORD_AREA
, NH_RECORD
, "r", SCOREPREFIX
);
649 HUP
raw_print("Cannot open record file!");
650 unlock_file_area(NH_RECORD_AREA
, NH_RECORD
);
654 HUP
topten_print("");
659 /* assure minimum number of points */
660 if(t0
->points
< POINTSMIN
) t0
->points
= 0;
662 t1
= tt_head
= newttentry();
664 /* rank0: -1 undefined, 0 not_on_list, n n_th on list */
666 readentry(rfile
, t1
);
667 if (t1
->points
< POINTSMIN
) t1
->points
= 0;
668 if(rank0
< 0 && t1
->points
< t0
->points
) {
675 #ifdef UPDATE_RECORD_IN_PLACE
676 t0
->fpos
= t1
->fpos
; /* insert here */
680 flg
++; /* ask for a rewrite */
683 if(t1
->points
== 0) break;
686 t1
->uid
== t0
->uid
&&
688 strncmp(t1
->name
, t0
->name
, NAMSZ
) == 0 &&
690 !strncmp(t1
->plrole
, t0
->plrole
, ROLESZ
) &&
698 "You didn't beat your previous score of %ld points.",
713 if(rank
<= ENTRYMAX
) {
714 t1
->tt_next
= newttentry();
718 if(rank
> ENTRYMAX
) {
723 if(flg
) { /* rewrite record file */
724 #ifdef UPDATE_RECORD_IN_PLACE
725 (void) fseek(rfile
, (t0
->fpos
>= 0 ?
726 t0
->fpos
: final_fpos
), SEEK_SET
);
728 (void) fclose(rfile
);
729 if(!(rfile
= fopen_datafile_area(NH_RECORD_AREA
, NH_RECORD
, "w", SCOREPREFIX
))){
730 HUP
raw_print("Cannot write record file");
731 unlock_file_area(NH_RECORD_AREA
, NH_RECORD
);
732 free_ttlist(tt_head
);
735 #endif /* UPDATE_RECORD_IN_PLACE */
736 if(!done_stopprint
) if(rank0
> 0){
738 topten_print("You made the top ten list!");
740 dump("", "You made the top ten list!");
745 "You reached the %d%s place on the top %d list.",
746 rank0
, ordin(rank0
), ENTRYMAX
);
760 if(rank0
== 0) rank0
= rank1
;
761 if(rank0
<= 0) rank0
= rank
;
762 if(!done_stopprint
) outheader();
764 for(rank
= 1; t1
->points
!= 0; rank
++, t1
= t1
->tt_next
) {
766 #ifdef UPDATE_RECORD_IN_PLACE
769 ) writeentry(rfile
, t1
);
770 if (done_stopprint
) continue;
771 if (rank
> flags
.end_top
&&
772 (rank
< rank0
- flags
.end_around
||
773 rank
> rank0
+ flags
.end_around
) &&
778 strncmp(t1
->name
, t0
->name
, NAMSZ
)
781 if (rank
== rank0
- flags
.end_around
&&
782 rank0
> flags
.end_top
+ flags
.end_around
+ 1 &&
790 outentry(rank
, t1
, FALSE
);
792 outentry(rank
, t1
, TRUE
);
794 outentry(rank
, t1
, TRUE
);
795 outentry(0, t0
, TRUE
);
798 if(rank0
>= rank
) if(!done_stopprint
)
799 outentry(0, t0
, TRUE
);
800 #ifdef UPDATE_RECORD_IN_PLACE
802 # ifdef TRUNCATE_FILE
803 /* if a reasonable way to truncate a file exists, use it */
804 truncate_file(rfile
);
806 /* use sentinel record rather than relying on truncation */
807 t1
->points
= 0L; /* terminates file when read back in */
808 t1
->ver_major
= t1
->ver_minor
= t1
->patchlevel
= 0;
809 t1
->uid
= t1
->deathdnum
= t1
->deathlev
= 0;
810 t1
->maxlvl
= t1
->hp
= t1
->maxhp
= t1
->deaths
= 0;
811 t1
->plrole
[0] = t1
->plrace
[0] = t1
->plgend
[0] = t1
->plalign
[0] = '-';
812 t1
->plrole
[1] = t1
->plrace
[1] = t1
->plgend
[1] = t1
->plalign
[1] = 0;
813 t1
->birthdate
= t1
->deathdate
= yyyymmdd((time_t)0L);
814 strcpy(t1
->name
, "@");
815 strcpy(t1
->death
, "<eod>\n");
816 writeentry(rfile
, t1
);
817 (void) fflush(rfile
);
818 # endif /* TRUNCATE_FILE */
820 #endif /* UPDATE_RECORD_IN_PLACE */
821 (void) fclose(rfile
);
822 unlock_file_area(NH_RECORD_AREA
, NH_RECORD
);
823 free_ttlist(tt_head
);
826 if (flags
.toptenwin
&& !done_stopprint
) display_nhwindow(toptenwin
, 1);
828 if (!t0_used
) dealloc_ttentry(t0
);
829 if (flags
.toptenwin
) {
830 destroy_nhwindow(toptenwin
);
841 strcpy(linebuf
, " No Points Name");
843 while(bp
< linebuf
+ COLNO
- 9) *bp
++ = ' ';
844 strcpy(bp
, "Hp [max]");
845 topten_print(linebuf
);
851 /* so>0: standout line; so=0: ordinary line */
853 outentry(rank
, t1
, so
)
854 struct toptenentry
*t1
;
858 boolean second_line
= TRUE
;
860 char *bp
, hpbuf
[24], linebuf3
[BUFSZ
];
865 if (rank
) sprintf(eos(linebuf
), "%3d", rank
);
866 else strcat(linebuf
, " ");
868 sprintf(eos(linebuf
), " %10ld %.10s", t1
->points
, t1
->name
);
869 sprintf(eos(linebuf
), "-%s", t1
->plrole
);
870 if (t1
->plrace
[0] != '?')
871 sprintf(eos(linebuf
), "-%s", t1
->plrace
);
872 /* Printing of gender and alignment is intentional. It has been
873 * part of the NetHack Geek Code, and illustrates a proper way to
874 * specify a character from the command line.
876 sprintf(eos(linebuf
), "-%s", t1
->plgend
);
877 if (t1
->plalign
[0] != '?')
878 sprintf(eos(linebuf
), "-%s ", t1
->plalign
);
880 strcat(linebuf
, " ");
881 if (!strncmp("escaped", t1
->death
, 7)) {
882 sprintf(eos(linebuf
), "escaped the dungeon %s[max level %d]",
883 !strncmp(" (", t1
->death
+ 7, 2) ? t1
->death
+ 7 + 2 : "",
885 /* fixup for closing paren in "escaped... with...Amulet)[max..." */
886 if ((bp
= index(linebuf
, ')')) != 0)
887 *bp
= (t1
->deathdnum
== astral_level
.dnum
) ? '\0' : ' ';
889 } else if (!strncmp("ascended", t1
->death
, 8)) {
891 #ifdef RECORD_CONDUCT
892 /* Add a notation for conducts kept */
893 if(t1
->conduct
!= 4095) {
896 const char *conduct_names
[] = {
897 "Food", "Vgn", "Vgt", "Ath", "Weap", "Pac",
898 "Ill", "Poly", "Form", "Wish", "Art", "Geno",
901 strcat(eos(linebuf
), "(");
902 for(i
= 0, m
= 1; conduct_names
[i
]; i
+= skip
+ 1, m
<<= (skip
+ 1)) {
907 /* Only show one of foodless, vegan, vegetarian */
911 /* Only show one of wishless, artiwishless */
914 /* Add a hyphen for multiple conducts */
915 if(dash
) strcat(eos(linebuf
), "-");
916 strcat(eos(linebuf
), conduct_names
[i
]);
919 strcat(eos(linebuf
), ") ");
923 sprintf(eos(linebuf
), "ascended to demigod%s-hood",
924 (t1
->plgend
[0] == 'F') ? "dess" : "");
927 if (!strncmp(t1
->death
, "quit", 4)) {
928 strcat(linebuf
, "quit");
930 } else if (!strncmp(t1
->death
, "died of st", 10)) {
931 strcat(linebuf
, "starved to death");
933 } else if (!strncmp(t1
->death
, "choked", 6)) {
934 sprintf(eos(linebuf
), "choked on h%s food",
935 (t1
->plgend
[0] == 'F') ? "er" : "is");
936 } else if (!strncmp(t1
->death
, "poisoned", 8)) {
937 strcat(linebuf
, "was poisoned");
938 } else if (!strncmp(t1
->death
, "crushed", 7)) {
939 strcat(linebuf
, "was crushed to death");
940 } else if (!strncmp(t1
->death
, "petrified by ", 13)) {
941 strcat(linebuf
, "turned to stone");
942 } else strcat(linebuf
, "died");
944 if (t1
->deathdnum
== astral_level
.dnum
) {
945 int deathlev
= t1
->deathlev
;
946 const char *arg
, *fmt
= " on the Plane of %s";
948 if (!t1
->ver_major
&& !t1
->ver_minor
&& t1
->patchlevel
< 7)
953 fmt
= " on the %s Plane";
954 arg
= "Astral"; break;
956 arg
= "Water"; break;
962 arg
= "Earth"; break;
966 sprintf(eos(linebuf
), fmt
, arg
);
968 sprintf(eos(linebuf
), " in %s", dungeons
[t1
->deathdnum
].dname
);
969 /*if (t1->deathdnum != knox_level.dnum)*/ /* not working for some reason, so let's just remove the check */
970 sprintf(eos(linebuf
), " on level %d", t1
->deathlev
);
971 if (t1
->deathlev
!= t1
->maxlvl
)
972 sprintf(eos(linebuf
), " [max %d]", t1
->maxlvl
);
975 /* kludge for "quit while already on Charon's boat" */
976 if (!strncmp(t1
->death
, "quit ", 5))
977 strcat(linebuf
, t1
->death
+ 4);
979 strcat(linebuf
, ".");
981 /* Quit, starved, ascended, and escaped contain no second line */
983 sprintf(eos(linebuf
), " %c%s.", highc(*(t1
->death
)), t1
->death
+1);
985 lngr
= (int)strlen(linebuf
);
986 if (t1
->hp
<= 0) hpbuf
[0] = '-', hpbuf
[1] = '\0';
987 else sprintf(hpbuf
, "%d", t1
->hp
);
988 /* beginning of hp column after padding (not actually padded yet) */
989 hppos
= COLNO
- (sizeof(" Hp [max]")-1); /* sizeof(str) includes \0 */
990 while (lngr
>= hppos
) {
991 for(bp
= eos(linebuf
);
992 !(*bp
== ' ' && (bp
-linebuf
< hppos
));
995 /* special case: word is too long, wrap in the middle */
996 if (linebuf
+15 >= bp
) bp
= linebuf
+ hppos
- 1;
997 /* special case: if about to wrap in the middle of maximum
998 dungeon depth reached, wrap in front of it instead */
999 if (bp
> linebuf
+ 5 && !strncmp(bp
- 5, " [max", 5)) bp
-= 5;
1001 /* gigabug from vanilla: infinite loop if the line is too long, fix from the variant that calls itself 3.7 */
1003 strcpy(linebuf3
, bp
);
1005 strcpy(linebuf3
, bp
+1);
1009 while (bp
< linebuf
+ (COLNO
-1)) *bp
++ = ' ';
1011 topten_print_bold(linebuf
);
1013 dump("*", linebuf
[0]==' '? linebuf
+1: linebuf
);
1016 topten_print(linebuf
);
1018 dump(" ", linebuf
[0]==' '? linebuf
+1: linebuf
);
1021 sprintf(linebuf
, "%15s %s", "", linebuf3
);
1022 lngr
= strlen(linebuf
);
1024 /* beginning of hp column not including padding */
1025 hppos
= COLNO
- 7 - (int)strlen(hpbuf
);
1028 if (bp
<= linebuf
+ hppos
) {
1029 /* pad any necessary blanks to the hit point entry */
1030 while (bp
< linebuf
+ hppos
) *bp
++ = ' ';
1032 sprintf(eos(bp
), " %s[%d]",
1033 (t1
->maxhp
< 10) ? " " : (t1
->maxhp
< 100) ? " " : "",
1039 if (so
>= COLNO
) so
= COLNO
-1;
1040 while (bp
< linebuf
+ so
) *bp
++ = ' ';
1042 topten_print_bold(linebuf
);
1044 topten_print(linebuf
);
1046 dump(" ", linebuf
[0]==' '? linebuf
+1: linebuf
);
1051 score_wanted(current_ver
, rank
, t1
, playerct
, players
, uid
)
1052 boolean current_ver
;
1054 struct toptenentry
*t1
;
1056 const char **players
;
1061 if (current_ver
&& (t1
->ver_major
!= VERSION_MAJOR
||
1062 t1
->ver_minor
!= VERSION_MINOR
||
1063 t1
->patchlevel
!= PATCHLEVEL
))
1067 if (!playerct
&& t1
->uid
== uid
)
1071 for (i
= 0; i
< playerct
; i
++) {
1072 if (players
[i
][0] == '-' && index("prga", players
[i
][1]) &&
1073 players
[i
][2] == 0 && i
+ 1 < playerct
) {
1074 char *arg
= (char *)players
[i
+ 1];
1075 if ((players
[i
][1] == 'p' &&
1076 str2role(arg
) == str2role(t1
->plrole
)) ||
1077 (players
[i
][1] == 'r' &&
1078 str2race(arg
) == str2race(t1
->plrace
)) ||
1079 (players
[i
][1] == 'g' &&
1080 str2gend(arg
) == str2gend(t1
->plgend
)) ||
1081 (players
[i
][1] == 'a' &&
1082 str2align(arg
) == str2align(t1
->plalign
)))
1086 else if (strcmp(players
[i
], "all") == 0 ||
1087 strncmp(t1
->name
, players
[i
], NAMSZ
) == 0 ||
1088 (players
[i
][0] == '-' &&
1089 players
[i
][1] == t1
->plrole
[0] &&
1090 players
[i
][2] == 0) ||
1091 (digit(players
[i
][0]) && rank
<= atoi(players
[i
])))
1097 #ifdef RECORD_ACHIEVE
1101 /* Achievement bitfield:
1103 * 0 obtained the Bell of Opening
1104 * 1 entered gehennom (by any means)
1105 * 2 obtained the Candelabrum of Invocation
1106 * 3 obtained the Book of the Dead
1107 * 4 performed the invocation ritual
1108 * 5 obtained the amulet
1109 * 6 entered elemental planes
1110 * 7 entered astral plane
1111 * 8 ascended (not "escaped in celestial disgrace!")
1112 * 9 obtained the luckstone from the Mines
1113 * 10 obtained the sokoban prize
1115 * 12 killed Nightmare
1117 * 14 killed Beholder
1121 * 18 killed The Largest Giant
1124 * 21 killed Aphrodite
1125 * 22 killed Frankenstein
1129 * 26 imbued the Bell of Opening
1130 * 27 imbued the Amulet of Yendor
1137 if(achieve
.get_bell
) r
|= 1L << 0;
1138 if(achieve
.enter_gehennom
) r
|= 1L << 1;
1139 if(achieve
.get_candelabrum
) r
|= 1L << 2;
1140 if(achieve
.get_book
) r
|= 1L << 3;
1141 if(achieve
.perform_invocation
) r
|= 1L << 4;
1142 if(achieve
.get_amulet
) r
|= 1L << 5;
1143 if(In_endgame(&u
.uz
)) r
|= 1L << 6;
1144 if(Is_astralevel(&u
.uz
)) r
|= 1L << 7;
1145 if(achieve
.ascended
) r
|= 1L << 8;
1146 if(achieve
.get_luckstone
) r
|= 1L << 9;
1147 if(achieve
.finish_sokoban
) r
|= 1L << 10;
1148 if(achieve
.killed_medusa
) r
|= 1L << 11;
1149 if(achieve
.killed_nightmare
) r
|= 1L << 12;
1150 if(achieve
.killed_vecna
) r
|= 1L << 13;
1151 if(achieve
.killed_beholder
) r
|= 1L << 14;
1152 if(achieve
.killed_ruggo
) r
|= 1L << 15;
1153 if(achieve
.killed_kroo
) r
|= 1L << 16;
1154 if(achieve
.killed_grund
) r
|= 1L << 17;
1155 if(achieve
.killed_largestgiant
) r
|= 1L << 18;
1156 if(achieve
.killed_shelob
) r
|= 1L << 19;
1157 if(achieve
.killed_girtab
) r
|= 1L << 20;
1158 if(achieve
.killed_aphrodite
) r
|= 1L << 21;
1159 if(achieve
.killed_frankenstein
) r
|= 1L << 22;
1160 if(achieve
.killed_croesus
) r
|= 1L << 23;
1161 if(achieve
.killed_dagon
) r
|= 1L << 24;
1162 if(achieve
.killed_hydra
) r
|= 1L << 25;
1163 if(achieve
.imbued_bell
) r
|= 1L << 26;
1164 if(achieve
.imbued_amulet
) r
|= 1L << 27;
1170 char encoded_achievements
[BUFSZ
];
1171 char* encodeachieveX(void)
1173 /* Achievement bitfield:
1175 * 0 killed an elder priest
1176 * 1 killed the Motherfucker Glass Golem
1177 * 2 killed Tiksrvzllat
1179 * 4 reached the bottom of the Swimming Pools
1180 * 5 killed Erogenous Katia
1181 * 6 killed the Witch King of Angmar
1182 * 7 obtained the stone of magic resistance from the Deep Mines
1183 * 8 visited all five DevNull challenge dungeons
1184 * 9 killed the Minotaur of the Maze
1186 * 11 killed Stahngnir
1188 * 13 completed the Rival Quest
1189 * 14 completed Minus World
1192 * but this isn't a bitfield, it's a string...
1195 encoded_achievements
[0] = '\0';
1197 if(achieveX
.killed_elderpriest
) sprintf(eos(encoded_achievements
), "%s,", "killed_elderpriest");
1198 if(achieveX
.killed_glassgolem
) sprintf(eos(encoded_achievements
), "%s,", "killed_glassgolem");
1199 if(achieveX
.killed_tiksrvzllat
) sprintf(eos(encoded_achievements
), "%s,", "killed_tiksrvzllat");
1200 if(achieveX
.killed_bofh
) sprintf(eos(encoded_achievements
), "%s,", "killed_bofh");
1201 if(achieveX
.swimmingpool_cleared
) sprintf(eos(encoded_achievements
), "%s,", "swimmingpool_cleared");
1202 if(achieveX
.killed_katia
) sprintf(eos(encoded_achievements
), "%s,", "killed_katia");
1203 if(achieveX
.killed_witchking
) sprintf(eos(encoded_achievements
), "%s,", "killed_witchking");
1204 if(achieveX
.get_magresstone
) sprintf(eos(encoded_achievements
), "%s,", "get_magresstone");
1205 if(achieveX
.devnull_complete
) sprintf(eos(encoded_achievements
), "%s,", "devnull_complete");
1206 if(achieveX
.killed_minotaur
) sprintf(eos(encoded_achievements
), "%s,", "killed_minotaur");
1207 if(achieveX
.killed_kalwina
) sprintf(eos(encoded_achievements
), "%s,", "killed_kalwina");
1208 if(achieveX
.killed_stahngnir
) sprintf(eos(encoded_achievements
), "%s,", "killed_stahngnir");
1209 if(achieveX
.killed_ariane
) sprintf(eos(encoded_achievements
), "%s,", "killed_ariane");
1210 if(achieveX
.completed_rivalquest
) sprintf(eos(encoded_achievements
), "%s,", "completed_rivalquest");
1211 if(achieveX
.completed_minusworld
) sprintf(eos(encoded_achievements
), "%s,", "completed_minusworld");
1212 if(achieveX
.killed_vera
) sprintf(eos(encoded_achievements
), "%s,", "killed_vera");
1213 if(achieveX
.killed_elaine
) sprintf(eos(encoded_achievements
), "%s,", "killed_elaine");
1216 if ((len
=strlen(encoded_achievements
))) { encoded_achievements
[len
-1] = '\0'; }
1217 return encoded_achievements
;
1222 * print selected parts of score list.
1223 * argc >= 2, with argv[0] untrustworthy (directory names, et al.),
1224 * and argv[1] starting with "-s".
1231 const char **players
;
1233 boolean current_ver
= TRUE
, init_done
= FALSE
;
1234 register struct toptenentry
*t1
;
1236 boolean match_found
= FALSE
;
1241 const char *player0
;
1244 if (argc
< 2 || strncmp(argv
[1], "-s", 2)) {
1245 raw_printf("prscore: bad arguments (%d)", argc
);
1249 rfile
= fopen_datafile_area(NH_RECORD_AREA
, NH_RECORD
, "r", SCOREPREFIX
);
1251 raw_print("Cannot open record file!");
1257 extern winid amii_rawprwin
;
1258 init_nhwindows(&argc
, argv
);
1259 amii_rawprwin
= create_nhwindow(NHW_TEXT
);
1263 /* If the score list isn't after a game, we never went through
1264 * initialization. */
1265 if (wiz1_level
.dlevel
== 0) {
1271 if (!argv
[1][2]){ /* plain "-s" */
1274 } else argv
[1] += 2;
1276 if (argc
> 1 && !strcmp(argv
[1], "-v")) {
1277 current_ver
= FALSE
;
1286 players
= (const char **)0;
1291 player0
= "all"; /* single user system */
1293 player0
= "hackplayer";
1300 players
= (const char **)++argv
;
1304 t1
= tt_head
= newttentry();
1305 for (rank
= 1; ; rank
++) {
1306 readentry(rfile
, t1
);
1307 if (t1
->points
== 0) break;
1309 score_wanted(current_ver
, rank
, t1
, playerct
, players
, uid
))
1311 t1
->tt_next
= newttentry();
1315 (void) fclose(rfile
);
1324 for (rank
= 1; t1
->points
!= 0; rank
++, t1
= t1
->tt_next
) {
1325 if (score_wanted(current_ver
, rank
, t1
, playerct
, players
, uid
))
1326 (void) outentry(rank
, t1
, 0);
1329 sprintf(pbuf
, "Cannot find any %sentries for ",
1330 current_ver
? "current " : "");
1331 if (playerct
< 1) strcat(pbuf
, "you.");
1333 if (playerct
> 1) strcat(pbuf
, "any of ");
1334 for (i
= 0; i
< playerct
; i
++) {
1335 /* stop printing players if there are too many to fit */
1336 if (strlen(pbuf
) + strlen(players
[i
]) + 2 >= BUFSZ
) {
1337 if (strlen(pbuf
) < BUFSZ
-4) strcat(pbuf
, "...");
1338 else strcpy(pbuf
+strlen(pbuf
)-4, "...");
1341 strcat(pbuf
, players
[i
]);
1342 if (i
< playerct
-1) {
1343 if (players
[i
][0] == '-' &&
1344 index("prga", players
[i
][1]) && players
[i
][2] == 0)
1346 else strcat(pbuf
, ":");
1351 raw_printf("Usage: %s -s [-v] <playertypes> [maxrank] [playernames]",
1354 raw_printf("Player types are: [-p role] [-r race] [-g gender] [-a align]");
1356 free_ttlist(tt_head
);
1359 extern winid amii_rawprwin
;
1360 display_nhwindow(amii_rawprwin
, 1);
1361 destroy_nhwindow(amii_rawprwin
);
1362 amii_rawprwin
= WIN_ERR
;
1374 /* Look for this role in the role table */
1375 for (i
= 0; roles
[i
].name
.m
; i
++)
1376 if (!strncmp(plch
, roles
[i
].filecode
, ROLESZ
)) {
1377 if (fem
&& roles
[i
].femalenum
!= NON_PM
)
1378 return roles
[i
].femalenum
;
1379 else if (roles
[i
].malenum
!= NON_PM
)
1380 return roles
[i
].malenum
;
1384 /* this might be from a 3.2.x score for former Elf class */
1385 if (!strcmp(plch
, "E")) return PM_RANGER
;
1387 impossible("What weird role is this? (%s)", plch
);
1388 return (PM_HUMAN_MUMMY
);
1392 undeadclassmon(plch
, fem
)
1398 /* Look for this role in the role table */
1399 for (i
= 0; roles
[i
].name
.m
; i
++)
1400 if (!strncmp(plch
, roles
[i
].filecode
, ROLESZ
)) {
1401 if (fem
&& roles
[i
].undeadfemalenum
!= NON_PM
)
1402 return roles
[i
].undeadfemalenum
;
1403 else if (roles
[i
].undeadmalenum
!= NON_PM
)
1404 return roles
[i
].undeadmalenum
;
1408 /* this might be from a 3.2.x score for former Elf class */
1409 if (!strcmp(plch
, "E")) return PM_RANGER
;
1411 impossible("What weird role is this? (%s)", plch
);
1412 return (PM_HUMAN_MUMMY
);
1416 * Get a random player name and class from the high score list,
1417 * and attach them to an object (for statues or morgue corpses).
1423 int rank
, rankamount
;
1426 register struct toptenentry
*tt
;
1428 struct toptenentry tt_buf
;
1430 if (!otmp
) return((struct obj
*) 0);
1432 rfile
= fopen_datafile_area(NH_RECORD_AREA
, NH_RECORD
, "r", SCOREPREFIX
);
1434 impossible("Cannot open record file!");
1435 return (struct obj
*)0;
1440 rank
= rnd(rankamount
); /* new code by Amy that allows more randomness - up to 1000 entries can be read now */
1442 rank
= rnd(rankamount
);
1443 for(i
= rank
; i
; i
--) {
1444 readentry(rfile
, tt
);
1445 if(tt
->points
== 0) break;
1448 if(tt
->points
== 0) {
1450 rankamount
= (rank
- 1);
1451 if (rankamount
< 1) {
1452 impossible("Not enough records!");
1453 return (struct obj
*)0;
1458 otmp
= (struct obj
*) 0;
1460 /* reset timer in case corpse started out as lizard or troll */
1461 if (otmp
->otyp
== CORPSE
) obj_stop_timers(otmp
);
1462 otmp
->corpsenm
= classmon(tt
->plrole
, (tt
->plgend
[0] == 'F'));
1463 otmp
->owt
= weight(otmp
);
1464 otmp
= oname(otmp
, tt
->name
);
1465 if (otmp
->otyp
== CORPSE
) start_corpse_timeout(otmp
);
1468 (void) fclose(rfile
);
1473 * Get a random player name and class from the high score list,
1474 * and attach them to a monster (for ghost summon spell). --Amy
1477 tt_mname(mm
, revive_corpses
, mm_flags
)
1479 boolean revive_corpses
;
1486 if (!rn2(2)) cnt
= (monster_difficulty() + 1)/10;
1487 if (!rn2(5)) cnt
+= rnz(5);
1488 if (cnt
< 1) cnt
= 1;
1496 int rank
, rankamount
;
1499 register struct toptenentry
*tt
;
1501 struct toptenentry tt_buf
;
1503 /*if (!mtmp) { pline("No records!");
1507 rfile
= fopen_datafile_area(NH_RECORD_AREA
, NH_RECORD
, "r", SCOREPREFIX
);
1509 impossible("Cannot open record file!");
1514 rank
= rnd(rankamount
); /* new code by Amy that allows more randomness - up to 1000 entries can be read now */
1516 rank
= rnd(rankamount
);
1517 for(i
= rank
; i
; i
--) {
1518 readentry(rfile
, tt
);
1519 if(tt
->points
== 0) break;
1522 if(tt
->points
== 0) {
1524 rankamount
= (rank
- 1);
1525 if (rankamount
< 1) {
1526 impossible("Not enough records!");
1532 /* we should only end up here if there are no entries --Amy */
1533 if (enexto(&cc
, mm
->x
, mm
->y
, youmonst
.data
) &&
1535 !(otmp
= sobj_at(CORPSE
, cc
.x
, cc
.y
)) ||
1538 mtmp
= makemon(&mons
[PM_UNDEAD_ARCHEOLOGIST
+ rn2(PM_UNDEAD_WIZARD
- PM_UNDEAD_ARCHEOLOGIST
+ 1)], cc
.x
, cc
.y
, mm_flags
);
1540 /*mtmp = (struct monst *) 0;*/
1543 /*mtmp = undeadclassmon(tt->plrole, (tt->plgend[0] == 'F')) ;*/
1545 if (enexto(&cc
, mm
->x
, mm
->y
, youmonst
.data
) &&
1547 !(otmp
= sobj_at(CORPSE
, cc
.x
, cc
.y
)) ||
1552 mtmp
= makemon(&mons
[undeadclassmon(tt
->plrole
, (tt
->plgend
[0] == 'F'))], cc
.x
, cc
.y
, mm_flags
);
1553 christen_monst(mtmp
, tt
->name
);
1554 /*mtmp = christen_monst(mtmp, tt->name);*/
1558 (void) fclose(rfile
);
1563 #ifdef NO_SCAN_BRACK
1564 /* Lattice scanf isn't up to reading the scorefile. What */
1565 /* follows deals with that; I admit it's ugly. (KL) */
1566 /* Now generally available (KL) */
1571 while ((p
= index(p
, ' ')) != 0) *p
= '|';
1578 while ((p
= index(p
, '|')) != 0) *p
= ' ';
1580 #endif /* NO_SCAN_BRACK */
1582 #if defined(GTK_GRAPHICS) || defined(PROXY_GRAPHICS)
1586 toptenwin
= create_nhwindow(NHW_TEXT
);
1594 destroy_nhwindow(toptenwin
);
1595 toptenwin
= WIN_ERR
;
1602 static char string
[BUFSZ
];
1605 if (u
.freeplaymode
) sprintf(eos(string
), "freeplay");
1606 if (flags
.gehenna
) sprintf(eos(string
), "gehenna");
1607 if (flags
.dudley
) sprintf(eos(string
), "dudley");
1608 if (flags
.iwbtg
) sprintf(eos(string
), "iwbtg");
1609 if (flags
.elmstreet
) sprintf(eos(string
), "elmstreet");
1610 if (flags
.hippie
) sprintf(eos(string
), "hippie");
1611 if (flags
.blindfox
) sprintf(eos(string
), "blindfox");
1612 if (flags
.uberlostsoul
) sprintf(eos(string
), "uberlostsoul");
1613 if (flags
.lostsoul
&& !(flags
.uberlostsoul
)) sprintf(eos(string
), "lostsoul");
1615 if (flags
.gmmode
) sprintf(eos(string
), "gmmode");
1616 if (flags
.supergmmode
) sprintf(eos(string
), "supergmmode");
1618 if (flags
.wonderland
) sprintf(eos(string
), "wonderland");
1619 if (flags
.zapem
) sprintf(eos(string
), "zapm");
1620 if (flags
.assholemode
) sprintf(eos(string
), "asshole");
1622 if (!u
.freeplaymode
&& !(flags
.gehenna
) && !(flags
.dudley
)
1624 && !(flags
.gmmode
) && !(flags
.supergmmode
)
1626 && !(flags
.iwbtg
) && !(flags
.assholemode
) && !(flags
.elmstreet
) && !(flags
.hippie
) && !(flags
.blindfox
) && !(flags
.uberlostsoul
) && !(flags
.lostsoul
) && !(flags
.wonderland
) && !(flags
.zapem
)) sprintf(eos(string
), "none");