X-Git-Url: https://git.cameronkatri.com/bsdgames-darwin.git/blobdiff_plain/028f8eac412e30600924633f62e0ded209deff6e..7ea815843146ff6795b20eac97afcac82f672785:/rogue/score.c diff --git a/rogue/score.c b/rogue/score.c index 920a4dc4..231f0c6d 100644 --- a/rogue/score.c +++ b/rogue/score.c @@ -1,6 +1,8 @@ +/* $NetBSD: score.c,v 1.15 2009/08/12 08:44:45 dholland Exp $ */ + /* - * Copyright (c) 1988 The Regents of the University of California. - * All rights reserved. + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Timothy C. Stoehr. @@ -13,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -34,9 +32,13 @@ * SUCH DAMAGE. */ +#include #ifndef lint -/*static char sccsid[] = "from: @(#)score.c 5.5 (Berkeley) 6/1/90";*/ -static char rcsid[] = "$Id: score.c,v 1.3 1993/09/23 22:28:42 mycroft Exp $"; +#if 0 +static char sccsid[] = "@(#)score.c 8.1 (Berkeley) 5/31/93"; +#else +__RCSID("$NetBSD: score.c,v 1.15 2009/08/12 08:44:45 dholland Exp $"); +#endif #endif /* not lint */ /* @@ -55,17 +57,19 @@ static char rcsid[] = "$Id: score.c,v 1.3 1993/09/23 22:28:42 mycroft Exp $"; #include "rogue.h" #include "pathnames.h" -extern char login_name[]; -extern char *m_names[]; -extern short max_level; -extern boolean score_only, no_skull, msg_cleared; -extern char *byebye_string, *nick_name; +static void center(short, const char *); +static int get_value(const object *); +static void id_all(void); +static void sell_pack(void); +static void sf_error(void) __attribute__((__noreturn__)); -killed_by(monster, other) -object *monster; -short other; +void +killed_by(const object *monster, short other) { - char buf[128]; + const char *mechanism = "killed by something unknown (?)"; + char mechanism_buf[128]; + const char *article; + char message_buf[128]; md_ignore_signals(); @@ -76,32 +80,35 @@ short other; if (other) { switch(other) { case HYPOTHERMIA: - (void) strcpy(buf, "died of hypothermia"); + mechanism = "died of hypothermia"; break; case STARVATION: - (void) strcpy(buf, "died of starvation"); + mechanism = "died of starvation"; break; case POISON_DART: - (void) strcpy(buf, "killed by a dart"); + mechanism = "killed by a dart"; break; case QUIT: - (void) strcpy(buf, "quit"); + mechanism = "quit"; break; case KFIRE: - (void) strcpy(buf, "killed by fire"); + mechanism = "killed by fire"; break; } } else { - (void) strcpy(buf, "Killed by "); if (is_vowel(m_names[monster->m_char - 'A'][0])) { - (void) strcat(buf, "an "); + article = "an"; } else { - (void) strcat(buf, "a "); + article = "a"; } - (void) strcat(buf, m_names[monster->m_char - 'A']); + snprintf(mechanism_buf, sizeof(mechanism_buf), + "Killed by %s %s", + article, m_names[monster->m_char - 'A']); + mechanism = mechanism_buf; } - (void) strcat(buf, " with "); - sprintf(buf+strlen(buf), "%ld gold", rogue.gold); + snprintf(message_buf, sizeof(message_buf), + "%s with %ld gold", mechanism, rogue.gold); + if ((!other) && (!no_skull)) { clear(); mvaddstr(4, 32, "__---------__"); @@ -121,15 +128,16 @@ short other; mvaddstr(18, 31, "\\_ _/"); mvaddstr(19, 33, "~---------~"); center(21, nick_name); - center(22, buf); + center(22, message_buf); } else { - message(buf, 0); + messagef(0, "%s", message_buf); } - message("", 0); + messagef(0, "%s", ""); /* gcc objects to just "" */ put_scores(monster, other); } -win() +void +win(void) { unwield(rogue.weapon); /* disarm and relax */ unwear(rogue.armor); @@ -145,20 +153,22 @@ win() mvaddstr(17, 11, "Congratulations, you have been admitted to the"); mvaddstr(18, 11, "Fighters' Guild. You return home, sell all your"); mvaddstr(19, 11, "treasures at great profit and retire into comfort."); - message("", 0); - message("", 0); + messagef(0, "%s", ""); /* gcc objects to just "" */ + messagef(0, "%s", ""); /* gcc objects to just "" */ id_all(); sell_pack(); - put_scores((object *) 0, WIN); + put_scores(NULL, WIN); } -quit(from_intrpt) -boolean from_intrpt; +void +quit(boolean from_intrpt) { - char buf[128]; + char buf[DCOLS]; short i, orow, ocol; boolean mc; + orow = ocol = 0; + mc = FALSE; md_ignore_signals(); if (from_intrpt) { @@ -172,7 +182,7 @@ boolean from_intrpt; } } check_message(); - message("really quit?", 1); + messagef(1, "really quit?"); if (rgetchar() != 'y') { md_heed_signals(); check_message(); @@ -190,198 +200,320 @@ boolean from_intrpt; clean_up(byebye_string); } check_message(); - killed_by((object *) 0, QUIT); + killed_by(NULL, QUIT); } -put_scores(monster, other) -object *monster; -short other; +/* + * The score file on disk is up to ten entries of the form + * score block [80 bytes] + * nickname block [30 bytes] + * + * The score block is to be parsed as follows: + * bytes 0-1 Rank (" 1" to "10") + * bytes 2-4 space padding + * bytes 5-15 Score/gold + * byte 15 up to a ':' Login name + * past the ':' Death mechanism + * + * The nickname block is an alternate name to be printed in place of the + * login name. Both blocks are supposed to contain a null-terminator. + */ + +struct score_entry { + long gold; + char username[80]; + char death[80]; + char nickname[30]; +}; + +#define NUM_SCORE_ENTRIES 10 + +static void make_score(struct score_entry *, const object *, int); + +static +void +pad_spaces(char *str, size_t len) { - short i, n, rank = 10, x, ne = 0, found_player = -1; - char scores[10][82]; - char n_names[10][30]; - char buf[128]; + size_t x; + for (x=strlen(str); x0 && str[x-1]==' '; x--); + str[x] = 0; +} + +static +int +read_score_entry(struct score_entry *se, FILE *fp) +{ + char score_block[80]; + char nickname_block[30]; + size_t n, x; + + n = fread(score_block, 1, sizeof(score_block), fp); + if (n==0) { + /* EOF */ + return 0; + } + if (n != sizeof(score_block)) { + sf_error(); + } + + n = fread(nickname_block, 1, sizeof(nickname_block), fp); + if (n != sizeof(nickname_block)) { + sf_error(); + } + + xxxx(score_block, sizeof(score_block)); + xxxx(nickname_block, sizeof(nickname_block)); + + /* Ensure null termination */ + score_block[sizeof(score_block)-1] = 0; + nickname_block[sizeof(nickname_block)-1] = 0; + + /* If there are other nulls in the score block, file is corrupt */ + if (strlen(score_block)!=sizeof(score_block)-1) { + sf_error(); + } + /* but this is NOT true of the nickname block */ + + /* quash trailing spaces */ + unpad_spaces(score_block); + unpad_spaces(nickname_block); + + for (x=5; score_block[x] == ' '; x++); + se->gold = lget_number(score_block+x); + + for (x=15; score_block[x] != 0 && score_block[x] != ':'; x++); + if (score_block[x] == 0) { + sf_error(); + } + score_block[x++] = 0; + strlcpy(se->username, score_block+15, sizeof(se->username)); + + strlcpy(se->death, score_block+x, sizeof(se->death)); + strlcpy(se->nickname, nickname_block, sizeof(se->nickname)); + + return 1; +} + +static +void +write_score_entry(const struct score_entry *se, int rank, FILE *fp) +{ + char score_block[80]; + char nickname_block[30]; + + /* avoid writing crap to score file */ + memset(score_block, 0, sizeof(score_block)); + memset(nickname_block, 0, sizeof(nickname_block)); + + snprintf(score_block, sizeof(score_block), + "%2d %6ld %s: %s", + rank+1, se->gold, se->username, se->death); + strlcpy(nickname_block, se->nickname, sizeof(nickname_block)); + + /* pad blocks out with spaces */ + pad_spaces(score_block, sizeof(score_block)); + /*pad_spaces(nickname_block, sizeof(nickname_block)); -- wrong! */ + + xxxx(score_block, sizeof(score_block)); + xxxx(nickname_block, sizeof(nickname_block)); + + fwrite(score_block, 1, sizeof(score_block), fp); + fwrite(nickname_block, 1, sizeof(nickname_block), fp); +} + +void +put_scores(const object *monster, short other) +{ + short i, rank=-1, found_player = -1, numscores = 0; + struct score_entry scores[NUM_SCORE_ENTRIES]; + const char *name; FILE *fp; - long s; - boolean pause = score_only; + boolean dopause = score_only; md_lock(1); - if ((fp = fopen(_PATH_SCOREFILE, "r+")) == NULL) { - message("cannot read/write/create score file", 0); + setegid(egid); + if ((fp = fopen(_PATH_SCOREFILE, "r+")) == NULL && + (fp = fopen(_PATH_SCOREFILE, "w+")) == NULL) { + setegid(gid); + messagef(0, "cannot read/write/create score file"); sf_error(); } + setegid(gid); rewind(fp); - (void) xxx(1); - - for (i = 0; i < 10; i++) { - if (((n = fread(scores[i], sizeof(char), 80, fp)) < 80) && (n != 0)) { - sf_error(); - } else if (n != 0) { - xxxx(scores[i], 80); - if ((n = fread(n_names[i], sizeof(char), 30, fp)) < 30) { - sf_error(); - } - xxxx(n_names[i], 30); - } else { + (void)xxx(1); + + for (numscores = 0; numscores < NUM_SCORE_ENTRIES; numscores++) { + if (read_score_entry(&scores[numscores], fp) == 0) { break; } - ne++; - if ((!score_only) && (found_player == -1)) { - if (!name_cmp(scores[i]+15, login_name)) { - x = 5; - while (scores[i][x] == ' ') { - x++; - } - s = lget_number(scores[i] + x); - if (rogue.gold < s) { - score_only = 1; - } else { - found_player = i; - } + } + + /* Search the score list. */ + for (i=0; i= s) { + /* if we aren't better than anyone, add at end. */ + rank = numscores; + + /* Otherwise, find our slot. */ + for (i = 0; i < numscores; i++) { + if (rogue.gold >= scores[i].gold) { rank = i; break; } } - if (ne == 0) { - rank = 0; - } else if ((ne < 10) && (rank == 10)) { - rank = ne; - } - if (rank < 10) { - insert_score(scores, n_names, nick_name, rank, ne, monster, - other); - if (ne < 10) { - ne++; + + if (rank < NUM_SCORE_ENTRIES) { + /* Open up a slot */ + for (i = numscores; i > rank; i--) { + scores[i] = scores[i-1]; } + numscores++; + + /* Put our info in the slot */ + make_score(&scores[rank], monster, other); } + + /* Now rewrite the score file */ + + md_ignore_signals(); rewind(fp); + (void)xxx(1); + + for (i = 0; i < numscores; i++) { + write_score_entry(&scores[i], i, fp); + } } + md_lock(0); + fclose(fp); + + /* Display the scores */ clear(); mvaddstr(3, 30, "Top Ten Rogueists"); mvaddstr(8, 0, "Rank Score Name"); - md_ignore_signals(); - - (void) xxx(1); - - for (i = 0; i < ne; i++) { + for (i = 0; i < numscores; i++) { if (i == rank) { standout(); } - if (i == 9) { - scores[i][0] = '1'; - scores[i][1] = '0'; + + if (scores[i].nickname[0]) { + name = scores[i].nickname; } else { - scores[i][0] = ' '; - scores[i][1] = i + '1'; - } - nickize(buf, scores[i], n_names[i]); - mvaddstr(i+10, 0, buf); - if (rank < 10) { - xxxx(scores[i], 80); - fwrite(scores[i], sizeof(char), 80, fp); - xxxx(n_names[i], 30); - fwrite(n_names[i], sizeof(char), 30, fp); + name = scores[i].username; } + + mvprintw(i+10, 0, "%2d %6ld %s: %s", + i+1, scores[i].gold, name, scores[i].death); + if (i == rank) { standend(); } } - md_lock(0); refresh(); - fclose(fp); - message("", 0); - if (pause) { - message("", 0); + messagef(0, "%s", ""); /* gcc objects to just "" */ + if (dopause) { + messagef(0, "%s", ""); } clean_up(""); } -insert_score(scores, n_names, n_name, rank, n, monster, other) -char scores[][82]; -char n_names[][30]; -char *n_name; -short rank, n; -object *monster; +static +void +make_score(struct score_entry *se, const object *monster, int other) { - short i; - char buf[128]; + const char *death = "bolts from the blue (?)"; + const char *hasamulet; + char deathbuf[80]; - if (n > 0) { - for (i = n; i > rank; i--) { - if ((i < 10) && (i > 0)) { - (void) strcpy(scores[i], scores[i-1]); - (void) strcpy(n_names[i], n_names[i-1]); - } - } - } - sprintf(buf, "%2d %6d %s: ", rank+1, rogue.gold, login_name); + se->gold = rogue.gold; + strlcpy(se->username, login_name, sizeof(se->username)); if (other) { switch(other) { case HYPOTHERMIA: - (void) strcat(buf, "died of hypothermia"); + death = "died of hypothermia"; break; case STARVATION: - (void) strcat(buf, "died of starvation"); + death = "died of starvation"; break; case POISON_DART: - (void) strcat(buf, "killed by a dart"); + death = "killed by a dart"; break; case QUIT: - (void) strcat(buf, "quit"); + death = "quit"; break; case WIN: - (void) strcat(buf, "a total winner"); + death = "a total winner"; break; case KFIRE: - (void) strcpy(buf, "killed by fire"); + death = "killed by fire"; break; } } else { - (void) strcat(buf, "killed by "); - if (is_vowel(m_names[monster->m_char - 'A'][0])) { - (void) strcat(buf, "an "); + const char *mn, *article; + + mn = m_names[monster->m_char - 'A']; + if (is_vowel(mn[0])) { + article = "an"; } else { - (void) strcat(buf, "a "); + article = "a"; } - (void) strcat(buf, m_names[monster->m_char - 'A']); - } - sprintf(buf+strlen(buf), " on level %d ", max_level); - if ((other != WIN) && has_amulet()) { - (void) strcat(buf, "with amulet"); + + snprintf(deathbuf, sizeof(deathbuf), + "killed by %s %s", article, mn); + death = deathbuf; } - for (i = strlen(buf); i < 79; i++) { - buf[i] = ' '; + + if (other != WIN && has_amulet()) { + hasamulet = " with amulet"; + } else { + hasamulet = ""; } - buf[79] = 0; - (void) strcpy(scores[rank], buf); - (void) strcpy(n_names[rank], n_name); + + snprintf(se->death, sizeof(se->death), "%s on level %d%s", + death, max_level, hasamulet); + + strlcpy(se->nickname, nick_name, sizeof(se->nickname)); } -is_vowel(ch) -short ch; +boolean +is_vowel(short ch) { return( (ch == 'a') || (ch == 'e') || @@ -390,7 +522,8 @@ short ch; (ch == 'u') ); } -sell_pack() +static void +sell_pack(void) { object *obj; short row = 2, val; @@ -408,9 +541,8 @@ sell_pack() rogue.gold += val; if (row < DROWS) { - sprintf(buf, "%5d ", val); - get_desc(obj, buf+11); - mvaddstr(row++, 0, buf); + get_desc(obj, buf, sizeof(buf)); + mvprintw(row++, 0, "%5d %s", val, buf); } } obj = obj->next_object; @@ -419,15 +551,16 @@ sell_pack() if (rogue.gold > MAX_GOLD) { rogue.gold = MAX_GOLD; } - message("", 0); + messagef(0, "%s", ""); /* gcc objects to just "" */ } -get_value(obj) -object *obj; +static int +get_value(const object *obj) { short wc; int val; + val = 0; wc = obj->which_kind; switch(obj->what_is) { @@ -469,7 +602,8 @@ object *obj; return(val); } -id_all() +static void +id_all(void) { short i; @@ -490,24 +624,8 @@ id_all() } } -name_cmp(s1, s2) -char *s1, *s2; -{ - short i = 0; - int r; - - while(s1[i] != ':') { - i++; - } - s1[i] = 0; - r = strcmp(s1, s2); - s1[i] = ':'; - return(r); -} - -xxxx(buf, n) -char *buf; -short n; +void +xxxx(char *buf, short n) { short i; unsigned char c; @@ -515,15 +633,14 @@ short n; for (i = 0; i < n; i++) { /* It does not matter if accuracy is lost during this assignment */ - c = (unsigned char) xxx(0); + c = (unsigned char)xxx(0); buf[i] ^= c; } } long -xxx(st) -boolean st; +xxx(boolean st) { static long f, s; long r; @@ -539,34 +656,8 @@ boolean st; return(r); } -nickize(buf, score, n_name) -char *buf, *score, *n_name; -{ - short i = 15, j; - - if (!n_name[0]) { - (void) strcpy(buf, score); - } else { - (void) strncpy(buf, score, 16); - - while (score[i] != ':') { - i++; - } - - (void) strcpy(buf+15, n_name); - j = strlen(buf); - - while (score[i]) { - buf[j++] = score[i++]; - } - buf[j] = 0; - buf[79] = 0; - } -} - -center(row, buf) -short row; -char *buf; +static void +center(short row, const char *buf) { short margin; @@ -574,9 +665,10 @@ char *buf; mvaddstr(row, margin, buf); } -sf_error() +static void +sf_error(void) { md_lock(0); - message("", 1); + messagef(1, "%s", ""); /* gcc objects to just "" */ clean_up("sorry, score file is out of order"); }