]> git.cameronkatri.com Git - bsdgames-darwin.git/blobdiff - rogue/score.c
Whitespace.
[bsdgames-darwin.git] / rogue / score.c
index 920a4dc4503331f96f2408767ec2c6a3d2bb66ca..231f0c6d8ad62e2d596691be58783e8df7f6e9bb 100644 (file)
@@ -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.
  * 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.
  *
  * SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
 #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); x<len-1; x++) {
+               str[x] = ' ';
+       }
+       str[len-1] = 0;
+}
+
+static
+void
+unpad_spaces(char *str)
+{
+       size_t x;
+       for (x=strlen(str); x>0 && 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<numscores; i++) {
+               if (!strcmp(scores[i].username, login_name)) {
+                       /* found our score */
+                       if (rogue.gold < scores[i].gold) {
+                               /* we didn't do as well as last time */
+                               score_only = 1;
+                       } else {
+                               /* we did better; mark entry for removal */
+                               found_player = i;
                        }
+                       break;
                }
        }
+
+       /* Remove a superseded entry, if any. */
        if (found_player != -1) {
-               ne--;
-               for (i = found_player; i < ne; i++) {
-                       (void) strcpy(scores[i], scores[i+1]);
-                       (void) strcpy(n_names[i], n_names[i+1]);
+               numscores--;
+               for (i = found_player; i < numscores; i++) {
+                       scores[i] = scores[i+1];
                }
        }
+
+       /* If we're going to insert ourselves, do it now */
        if (!score_only) {
-               for (i = 0; i < ne; i++) {
-                       x = 5;
-                       while (scores[i][x] == ' ') {
-                               x++;
-                       }
-                       s = lget_number(scores[i] + x);
 
-                       if (rogue.gold >= 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");
 }