/* * File for the fun ends * Death or a total win * * Advanced Rogue * Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T * All rights reserved. * * Based on "Rogue: Exploring the Dungeons of Doom" * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman * All rights reserved. * * See the file LICENSE.TXT for full copyright and licensing information. */ /* Print flags for scoring */ #define REALLIFE 1 /* Print out machine and logname */ #define EDITSCORE 2 /* Edit the current score file */ #define ADDSCORE 3 /* Add a new score */ #include #include #include #include #include "curses.h" #include #include #include #include #include "network.h" #include "rogue.h" #include "mach_dep.h" /* * If you change this structure, change the compatibility routines * scoreout() and scorein() to reflect the change. Also update SCORELEN. */ struct sc_ent { unsigned long sc_score; char sc_name[LINELEN]; char sc_system[SYSLEN]; char sc_login[LOGLEN]; short sc_flgs; short sc_level; short sc_ctype; short sc_monster; short sc_quest; }; #define SCORELEN \ (sizeof(unsigned long) + LINELEN + SYSLEN + LOGLEN + 5*sizeof(short)) static char *rip[] = { " __________", " / \\", " / REST \\", " / IN \\", " / PEACE \\", " / \\", " | |", " | |", " | killed by |", " | |", " | 1984 |", " *| * * * | *", " ________)/\\\\_//(\\/(/\\)/\\//\\/|_)_______", 0 }; char *killname(short monst); void scorein(struct sc_ent scores[], FILE *inf); void scoreout(struct sc_ent scores[], FILE *outf); void showpack(char *howso); int update(struct sc_ent top_ten[], unsigned long amount, short quest, char *whoami, short flags, short level, short monst, short ctype, char *system, char *login); void byebye(int sig) { NOOP(sig); if (!isendwin()) { clear(); endwin(); } printf("\n"); exit(0); } /* * death: * Do something really fun when he dies */ void death(short monst) { register char **dp = rip, *killer; register struct tm *lt; time_t date; char buf[80]; struct tm *localtime(); time(&date); lt = localtime(&date); clear(); move(8, 0); while (*dp) printw("%s\n", *dp++); mvaddstr(14, 28-((strlen(whoami)+1)/2), whoami); sprintf(buf, "%lu Points", pstats.s_exp ); mvaddstr(15, 28-((strlen(buf)+1)/2), buf); killer = killname(monst); mvaddstr(17, 28-((strlen(killer)+1)/2), killer); mvaddstr(18, 26, (sprintf(prbuf, "%4d", 1900+lt->tm_year), prbuf)); move(LINES-1, 0); refresh(); writelog(pstats.s_exp, KILLED, monst); score(pstats.s_exp, KILLED, monst); exit(0); } char * killname(short monst) { static char mons_name[LINELEN]; int i; if (monst > NUMMONST) return("a strange monster"); if (monst >= 0) { switch (monsters[monst].m_name[0]) { case 'a': case 'e': case 'i': case 'o': case 'u': sprintf(mons_name, "an %s", monsters[monst].m_name); break; default: sprintf(mons_name, "a %s", monsters[monst].m_name); } return(mons_name); } for (i = 0; i< DEATHNUM; i++) { if (deaths[i].reason == monst) break; } if (i >= DEATHNUM) return ("strange death"); return (deaths[i].name); } /* * score -- figure score and post it. */ /* VARARGS2 */ void score(unsigned long amount, int flags, short monst) { static struct sc_ent top_ten[NUMSCORE]; register struct sc_ent *scp; register int i; register struct sc_ent *sc2; register char *killer; register int prflags = 0; short upquest = 0, wintype = 0, uplevel = 0, uptype = 0; /* For network updating */ char upsystem[SYSLEN], uplogin[LOGLEN]; char *thissys; /* Holds the name of this system */ char *compatstr=NULL; /* Holds scores for writing compatible score files */ #define REASONLEN 3 static char *reason[] = { "killed", "quit", "A total winner", "somehow left", }; char *packend; memset(top_ten,0,sizeof(top_ten)); signal(SIGINT, byebye); if (flags != WINNER && flags != SCOREIT && flags != UPDATE) { if (flags == CHICKEN) packend = "when you quit"; else packend = "at your untimely demise"; mvaddstr(LINES - 1, 0, retstr); refresh(); wgetnstr(cw,prbuf,80); showpack(packend); } purse = 0; /* Steal all the gold */ /* * Open file and read list */ if (scoreboard == NULL) { printf("\nCannot open score_file.\n"); return; } /* Get this system's name */ thissys = md_gethostname(); for (scp = top_ten; scp <= &top_ten[NUMSCORE-1]; scp++) { scp->sc_score = 0L; for (i = 0; i < 80; i++) scp->sc_name[i] = rnd(255); scp->sc_quest= RN; scp->sc_flgs = RN; scp->sc_level = RN; scp->sc_monster = RN; scp->sc_ctype = 0; strncpy(scp->sc_system, thissys, SYSLEN); scp->sc_login[0] = '\0'; } /* * If this is a SCOREIT optin (rogue -s), don't call byebye. The * endwin() call in byebye() will result in a core dump. */ if (flags == SCOREIT) signal(SIGINT, SIG_DFL); else signal(SIGINT, byebye); if (flags != SCOREIT && flags != UPDATE) { mvaddstr(LINES - 1, 0, retstr); refresh(); fflush(stdout); wgetnstr(stdscr,prbuf,80); } /* Check for special options */ if (strcmp(prbuf, "names") == 0) prflags = REALLIFE; #ifdef WIZARD else if (wizard) { if (strcmp(prbuf, "edit") == 0) prflags = EDITSCORE; else if (strcmp(prbuf, "add") == 0) { prflags = ADDSCORE; waswizard = FALSE; /* We want the new score recorded */ } } #endif /* Read the score and convert it to a compatible format */ scorein(top_ten, scoreboard); /* Convert it */ /* Get some values if this is an update */ if (flags == UPDATE) { int errcheck, errors = 0; upquest = (short) netread(&errcheck, sizeof(short), stdin); if (errcheck) errors++; if (fread(whoami, 1, LINELEN, stdin) != LINELEN) errors++; wintype = (short) netread(&errcheck, sizeof(short), stdin); if (errcheck) errors++; uplevel = (short) netread(&errcheck, sizeof(short), stdin); if (errcheck) errors++; uptype = (short) netread(&errcheck, sizeof(short), stdin); if (errcheck) errors++; if (fread(upsystem, 1, SYSLEN, stdin) != SYSLEN) errors++; if (fread(uplogin, 1, LOGLEN, stdin) != LOGLEN) errors++; if (errors) { fclose(scoreboard); free(compatstr); return; } } /* * Insert player in list if need be */ if (!waswizard) { char *login = NULL; if (flags != UPDATE) { login = md_getusername(); } if (flags == UPDATE) (void) update(top_ten, amount, upquest, whoami, wintype, uplevel, monst, uptype, upsystem, uplogin); else { #ifdef WIZARD if (prflags == ADDSCORE) { /* Overlay characteristic by new ones */ char buffer[80]; int atoi(); clear(); mvaddstr(1, 0, "Score: "); mvaddstr(2, 0, "Quest (number): "); mvaddstr(3, 0, "Name: "); mvaddstr(4, 0, "System: "); mvaddstr(5, 0, "Login: "); mvaddstr(6, 0, "Level: "); mvaddstr(7, 0, "Char type: "); mvaddstr(8, 0, "Result: "); /* Get the score */ move(1, 7); get_str(buffer, stdscr); amount = atol(buffer); /* Get the character's quest -- must be a number */ move(2, 16); get_str(buffer, stdscr); quest_item = atoi(buffer); /* Get the character's name */ move(3, 6); get_str(buffer, stdscr); strncpy(whoami, buffer, LINELEN); /* Get the system */ move(4, 8); get_str(buffer, stdscr); strncpy(thissys, buffer, SYSLEN); /* Get the login */ move(5, 7); get_str(buffer, stdscr); strncpy(login, buffer, LOGLEN); /* Get the level */ move(6, 7); get_str(buffer, stdscr); level = max_level = (short) atoi(buffer); /* Get the character type */ move(7, 11); get_str(buffer, stdscr); switch (buffer[0]) { case 'F': case 'f': default: player.t_ctype = C_FIGHTER; break; case 'C': case 'c': player.t_ctype = C_CLERIC; break; case 'M': case 'm': player.t_ctype = C_MAGICIAN; break; case 'T': case 't': player.t_ctype = C_THIEF; break; } /* Get the win type */ move(8, 8); get_str(buffer, stdscr); switch (buffer[0]) { case 'W': case 'w': case 'T': case 't': flags = WINNER; break; case 'Q': case 'q': flags = CHICKEN; break; case 'k': case 'K': default: flags = KILLED; break; } /* Get the monster if player was killed */ if (flags == KILLED) { mvaddstr(9, 0, "Death type: "); get_str(buffer, stdscr); if (buffer[0] == 'M' || buffer[0] == 'm') monst = makemonster(FALSE); else monst = getdeath(); } } #endif if (update(top_ten, amount, (short) quest_item, whoami, flags, (flags == WINNER) ? (short) max_level : (short) level, monst, player.t_ctype, thissys, login) #ifdef NUMNET && fork() == 0 /* Spin off network process */ #endif ) { #ifdef NUMNET /* Send this update to the other systems in the network */ int i, j; char cmd[256]; /* Command for remote execution */ FILE *rmf, *popen(); /* For input to remote command */ for (i=0; i/dev/null", Network[i].system, Network[i].rogue); /* Execute the command */ if ((rmf=popen(cmd, "w")) != NULL) { unsigned long temp; /* Temporary value */ /* Write out the parameters */ (void) netwrite((unsigned long) amount, sizeof(unsigned long), rmf); (void) netwrite((unsigned long) monst, sizeof(short), rmf); (void) netwrite((unsigned long) quest_item, sizeof(short), rmf); (void) fwrite(whoami, 1, strlen(whoami), rmf); for (j=strlen(whoami); jsc_score != 0) { switch (scp->sc_ctype) { case C_FIGHTER: class = "fighter"; when C_MAGICIAN: class = "magician"; when C_CLERIC: class = "cleric"; when C_THIEF: class = "thief"; otherwise: class = "unknown"; } /* Make sure we have an in-bound reason */ if (scp->sc_flgs > REASONLEN) scp->sc_flgs = REASONLEN; printf("%3d %10lu\t%s (%s)", scp - top_ten + 1, scp->sc_score, scp->sc_name, class); if (prflags == REALLIFE) printf(" [in real life %.*s!%.*s]", SYSLEN, scp->sc_system, LOGLEN, scp->sc_login); printf(":\n\t\t%s on level %d", reason[scp->sc_flgs], scp->sc_level); switch (scp->sc_flgs) { case KILLED: printf(" by"); killer = killname(scp->sc_monster); printf(" %s", killer); break; case WINNER: printf(" with the %s", rel_magic[scp->sc_quest].mi_name); break; } if (prflags == EDITSCORE) { fflush(stdout); fgets(prbuf,80,stdin); printf("\n"); if (prbuf[0] == 'd') { for (sc2 = scp; sc2 < &top_ten[NUMSCORE-1]; sc2++) *sc2 = *(sc2 + 1); top_ten[NUMSCORE-1].sc_score = 0; for (i = 0; i < 80; i++) top_ten[NUMSCORE-1].sc_name[i] = rnd(255); top_ten[NUMSCORE-1].sc_flgs = RN; top_ten[NUMSCORE-1].sc_level = RN; top_ten[NUMSCORE-1].sc_monster = RN; scp--; } else if (prbuf[0] == 'e') { printf("Death type: "); fgets(prbuf,80,stdin); if (prbuf[0] == 'M' || prbuf[0] == 'm') scp->sc_monster = makemonster(FALSE); else scp->sc_monster = getdeath(); clear(); refresh(); } } else printf("\n"); } } /* if (prflags == EDITSCORE) endwin(); */ /* End editing windowing */ } if ((flags != SCOREIT) && (flags != UPDATE)) { printf("\n[Press return to exit]"); fflush(stdout); fgets(prbuf,80,stdin); } } void writelog(unsigned long amount, int flags, short monst) { #ifdef LOGFILE char fate[100]; char *class; struct linked_list *item; struct object *obj; char had_quest = '0'; if (waswizard) return; if (logfile == NULL) return; switch (player.t_ctype) { case C_FIGHTER: class = "Fighter"; when C_MAGICIAN: class = "Magician"; when C_CLERIC: class = "Cleric"; when C_THIEF: class = "Thief"; otherwise: class = "Unknown"; } for (item = pack; item != NULL; item = next(item)) { obj = OBJPTR(item); if (obj->o_type == RELIC && obj->o_which == quest_item) had_quest = '1'; } if (flags == KILLED) { sprintf(fate, "killed by %s", killname(monst)); } else if (flags == CHICKEN) { sprintf(fate, "quit"); } else if (flags == WINNER) { sprintf(fate, "escaped"); } else return; fprintf(logfile, "%ld %ld %s %d %s %d %d %d %c %s\n", time(NULL), amount, whoami, pstats.s_lvl, class, level, max_level, quest_item, had_quest, fate); fclose(logfile); #endif return; } /* * scorein: * Convert a character string that has been translated from a * score file by scoreout() back to a score file structure. */ void scorein(struct sc_ent scores[], FILE *inf) { int i; char scoreline[100]; for(i = 0; i < NUMSCORE; i++) { encread((char *) &scores[i].sc_name, LINELEN, inf); encread((char *) &scores[i].sc_system, SYSLEN, inf); encread((char *) &scores[i].sc_login, LINELEN, inf); encread((char *) scoreline, 100, inf); sscanf(scoreline, " %lu %d %d %d %d %d \n", &scores[i].sc_score, &scores[i].sc_flgs, &scores[i].sc_level, &scores[i].sc_ctype, &scores[i].sc_monster, &scores[i].sc_quest); } } /* * scoreout: * Convert a score file structure to a character string. We do * this for compatibility sake since some machines write out fields in * different orders. */ void scoreout(struct sc_ent scores[], FILE *outf) { int i; char scoreline[100]; for(i = 0; i < NUMSCORE; i++) { memset(scoreline,0,100); encwrite((char *) scores[i].sc_name, LINELEN, outf); encwrite((char *) scores[i].sc_system, SYSLEN, outf); encwrite((char *) scores[i].sc_login, LINELEN, outf); sprintf(scoreline, " %lu %d %d %d %d %d \n", scores[i].sc_score, scores[i].sc_flgs, scores[i].sc_level, scores[i].sc_ctype, scores[i].sc_monster,scores[i].sc_quest); encwrite((char *) scoreline, 100, outf); } } /* * showpack: * Display the contents of the hero's pack */ void showpack(char *howso) { reg char *iname; reg int cnt, packnum; reg struct linked_list *item; reg struct object *obj; idenpack(); cnt = 1; clear(); mvprintw(0, 0, "Contents of your pack %s:\n",howso); packnum = 'a'; for (item = pack; item != NULL; item = next(item)) { obj = OBJPTR(item); iname = inv_name(obj, FALSE); mvprintw(cnt, 0, "%c) %s\n",packnum++,iname); if (++cnt >= LINES - 2 && next(item) != NULL) { cnt = 1; mvaddstr(LINES - 1, 0, morestr); refresh(); wait_for(stdscr,' '); clear(); } } mvprintw(cnt + 1,0,"--- %d Gold Pieces ---",purse); refresh(); } void total_winner(void) { register struct linked_list *item; register struct object *obj; register int worth; register char c; register int oldpurse; clear(); standout(); addstr(" \n"); addstr(" @ @ @ @ @ @@@ @ @ \n"); addstr(" @ @ @@ @@ @ @ @ @ \n"); addstr(" @ @ @@@ @ @ @ @ @ @@@ @@@@ @@@ @ @@@ @ \n"); addstr(" @@@@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ \n"); addstr(" @ @ @ @ @ @ @ @@@@ @ @ @@@@@ @ @ @ \n"); addstr(" @ @ @ @ @ @@ @ @ @ @ @ @ @ @ @ @ \n"); addstr(" @@@ @@@ @@ @ @ @ @@@@ @@@@ @@@ @@@ @@ @ \n"); addstr(" \n"); addstr(" Congratulations, you have made it to the light of day! \n"); standend(); addstr("\nYou have joined the elite ranks of those who have escaped the\n"); addstr("Dungeons of Doom alive. You journey home and sell all your loot at\n"); addstr("a great profit and are appointed leader of a "); switch (player.t_ctype) { case C_MAGICIAN:addstr("magic user's guild.\n"); when C_FIGHTER: addstr("fighters guild.\n"); when C_CLERIC: addstr("monastery.\n"); when C_THIEF: addstr("thief's guild.\n"); otherwise: addstr("tavern.\n"); } mvaddstr(LINES - 1, 0, spacemsg); refresh(); wait_for(stdscr,' '); clear(); mvaddstr(0, 0, " Worth Item"); oldpurse = purse; for (c = 'a', item = pack; item != NULL; c++, item = next(item)) { obj = OBJPTR(item); worth = get_worth(obj); if (obj->o_group == 0) worth *= obj->o_count; whatis(item); mvprintw(c - 'a' + 1, 0, "%c) %6d %s", c, worth, inv_name(obj, FALSE)); purse += worth; } mvprintw(c - 'a' + 1, 0," %5d Gold Pieces ", oldpurse); refresh(); writelog(pstats.s_exp + (long) purse, WINNER, '\0'); score(pstats.s_exp + (long) purse, WINNER, '\0'); exit(0); } int update(struct sc_ent top_ten[], unsigned long amount, short quest, char *whoami, short flags, short level, short monst, short ctype, char *system, char *login) { register struct sc_ent *scp, *sc2; int retval=0; /* 1 if a change, 0 otherwise */ for (scp = top_ten; scp < &top_ten[NUMSCORE]; scp++) { if (amount >= scp->sc_score) break; #ifdef LIMITSCORE /* Limits player to one entry per class per uid */ /* If this good score is the same class and uid, then forget it */ if (strncmp(scp->sc_login, login, LOGLEN) == 0 && scp->sc_ctype == ctype && strncmp(scp->sc_system, system, SYSLEN) == 0) return(0); #endif } if (scp < &top_ten[NUMSCORE]) { retval = 1; #ifdef LIMITSCORE /* Limits player to one entry per class per uid */ /* If a lower scores exists for the same login and class, delete it */ for (sc2 = scp ;sc2 < &top_ten[NUMSCORE]; sc2++) { if (sc2->sc_score == 0L) break; /* End of useful scores */ if (strncmp(sc2->sc_login, login, LOGLEN) == 0 && sc2->sc_ctype == ctype && strncmp(sc2->sc_system, system, SYSLEN) == 0) { /* We want to delete this entry */ while (sc2 < &top_ten[NUMSCORE-1]) { *sc2 = *(sc2+1); sc2++; } sc2->sc_score = 0L; } } #endif for (sc2 = &top_ten[NUMSCORE-1]; sc2 > scp; sc2--) *sc2 = *(sc2-1); scp->sc_score = amount; scp->sc_quest = quest; strncpy(scp->sc_name, whoami, LINELEN); scp->sc_flgs = flags; scp->sc_level = level; scp->sc_monster = monst; scp->sc_ctype = ctype; strncpy(scp->sc_system, system, SYSLEN); strncpy(scp->sc_login, login, LOGLEN); } return(retval); }