/********************************** scores.c **********************/ #include #include #include "sdi.h" /* * Copyright 1987 by Mark Weiser. * Permission to reproduce and use in any manner whatsoever on Suns is granted * so long as this copyright and other identifying marks of authorship * in the code and the game remain intact and visible. Use of this code * in other products is reserved to me--I'm working on Mac and IBM versions. */ /* * This code is responsible * reading, updating, and displaying the score file. */ #ifndef SCOREFILE #define SCOREFILE "/usr/games/lib/sdi_scores" #endif struct scores *get_scores(); /* Already updated is used to prevent rewriting the score file more than * once per game. */ static int already_updated = 0; /* * This routine is called whenever there is absolutely positively a new * game beginning, and so if it ever gets anywhere it is ok to update * the score file. */ new_score() { already_updated = 0; } /* * Read in the old scores and insert the current game score into the file * if it is within the top ten. No scores are recorded in gamemaster mode. */ update_scores() { extern int gamemaster; struct scores *scp = NULL; int score = atol((char *)xv_get(score_item, PANEL_VALUE)); int level = atol((char *)xv_get(level_item, PANEL_VALUE)); int skill = (int)xv_get(skill_item, PANEL_VALUE); if (already_updated || gamemaster) return; if ((scp = get_scores()) == NULL) return; while (scp->score > score) { scp += 1; } if (scp->score >= 0) { struct scores *new_sc = sc_end; while (--new_sc > scp) { strcpy(new_sc->name, (new_sc-1)->name); new_sc->score = (new_sc-1)->score; new_sc->level = (new_sc-1)->level; new_sc->skill = (new_sc-1)->skill; } strcpy(scp->name, USER_NAME); scp->score = score; scp->level = level; scp->skill = skill; } if (! put_scores(sc)) { printf("Could not write to score file '%s'.\n",scorefile); } already_updated = 1; } /* * Get the name of the current user. */ char * get_name() { char *s; struct passwd *p; if ((char *)0 != (s = (char *)getlogin())) return s; p = (struct passwd *)getpwuid(getuid()); return p->pw_name; } /* * Read the score file. The format is obvious. Exactly 11 scores are always * returned. The 11th is a sentinal with score '-1'. If the score file did * not have 10, then the extras are for user '(nobody)', score 0. * A user name may not contain a "'". The result of get_scores is an array * of score structures, statically allocated. */ struct scores * get_scores() { struct scores *scp; char *tmpfile, *getenv(); FILE *f; if (scorefile) { tmpfile = scorefile; } else if ((tmpfile = getenv("SDI_SCORES")) != NULL) { tmpfile = scorefile; } else { tmpfile = "/usr/games/lib/sdi_scores"; } /* Try hard to open some kind of score file */ if (((f = fopen(tmpfile, "r+")) == NULL)) { tmpfile = SCOREFILE; if (((f = fopen(tmpfile, "r+")) == NULL)) { tmpfile = "/usr/games/lib/sdi_scores"; if ((f = fopen("/usr/games/lib/sdi_scores", "r+")) == NULL) return NULL; } } scorefile = tmpfile; /* read entries */ scp = sc; while (scp < sc_end && (fscanf(f, " '%[^']' %d %d %d", scp->name, &scp->score, &scp->level, &scp->skill) == 4) && scp->score > 0) { scp += 1; } while (scp < sc_end) { strcpy(scp->name, "(nobody)"); scp->score = 0; scp->level = 0; scp->skill = 0; scp += 1; } scp->score = -1; fclose(f); return sc; } /* * Write a list of scores to the score file. Never called directly, except * by update_scores. */ put_scores(scp) struct scores *scp; { FILE *f; if ((f = fopen(scorefile, "w")) == NULL) return 0; /* write entries */ while (scp->score > 0) { fprintf(f, "'%s' %d %d %d\n", scp->name, scp->score, scp->level, scp->skill); scp += 1; } fclose(f); return 1; } /* * This routine formats the score file for display when the 'scores' * button is pressed. */ static char string_for_build_scores[1024]; char * build_scores() { char *sp = string_for_build_scores; struct scores *scp; char *type_of_skill; scp = (struct scores *)get_scores(); if (scp == NULL) { strcpy(sp, "Could not find a score file."); } else { strcpy(sp, "No scores yet: play some games."); while (scp->score > 0) { switch(scp->skill) { case 0: type_of_skill = " novice"; break; case 1: type_of_skill = "n occasional user"; break; case 2: type_of_skill = "n expert"; break; } sprintf(sp, "%s, playing as a%s, melted with score %d at level %d.\n", scp->name, type_of_skill, scp->score, scp->level); scp += 1; sp += strlen(sp); } } return string_for_build_scores; } /* * Free the result of a call to build_scores. */ free_scores(a) char **a; { /* Oh, how I long for garbage collection. */ while (*++a) free(*a); }