/***************************************
  $Header: /home/amb/xbomb/RCS/hiscore.c 1.7 1995/11/16 20:16:23 amb Exp $

  XBomb - 'Minesweeper' game - Version 2

  Hi-score table management.

  Written by Andrew M. Bishop

  This file Copyright 1994 1995 Andrew M. Bishop
  It may be distributed under the GNU Public License, version 2, or
  any higher version.  See section COPYING of the GNU Public license
  for conditions under which this file may be redistributed.
  ***************************************/


#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include "xbomb.h"

#if defined(__sun__) && !defined(__svr4__)
int    fprintf(FILE*, const char*,...);
int    printf(const char*, ... );
int    sscanf(char*, const char*,...);
int    fread(void*,unsigned int,unsigned int, FILE*);
int    fwrite(const void*,unsigned int,unsigned int, FILE*);
int    fclose(FILE*);
long   time(long*);
#endif

extern int grid_type;
extern char levels[NLEVELS][LEVELSLEN],types[NTYPES][TYPESLEN];
extern int widths[NLEVELS],heights[NLEVELS],nbombs[NLEVELS];

static char filenames[NTYPES][FILENAMELEN]=HIGH_SCORE_FILENAMES;
static char pos[10][5]={"Top","2nd","3rd","4th","5th","6th","7th","8th","9th","10th"};
static int  score[NLEVELS][10];
static char name[NLEVELS][10][20];
static long date[NLEVELS][10];

struct score_name {int score;char name[20];long date;};

static void decrypt_score(struct score_name* sn);
static void encrypt_score(struct score_name* sn);

/*++++++++++++++++++++++++++++++++++++++
  Load in the high score table.
  ++++++++++++++++++++++++++++++++++++++*/

void LoadHighScores()
{
 FILE *f;
 int i,j;
 struct score_name sn;

 for(i=0;i<NLEVELS;i++)
    for(j=0;j<10;j++)
      {
       score[i][j]=9999999;
       strcpy(name[i][j],"nobody");
       date[i][j]=0;
      }

 f=fopen(filenames[grid_type-GAME_TYPE],"r");

 if(!f)
   {
    fprintf(stderr,"\nXBomb: Cannot open high score table '%s'\n",filenames[grid_type-GAME_TYPE]);
    return;
   }

 for(i=0;i<NLEVELS;i++)
    for(j=0;j<10;j++)
      {
       if(!fread(&sn,sizeof(sn),1,f))
          break;
       decrypt_score(&sn);
       score[i][j]=sn.score;
       strcpy(name[i][j],sn.name);
       date[i][j]=sn.date;
      }

 fclose(f);
}


/*++++++++++++++++++++++++++++++++++++++
  Saves the high score table.
  ++++++++++++++++++++++++++++++++++++++*/

void SaveHighScores()
{
 FILE *f;
 int i,j;
 struct score_name sn;

 f=fopen(filenames[grid_type-GAME_TYPE],"w");

 if(!f)
   {
    fprintf(stderr,"\nXBomb: Cannot open high score table '%s'\n",filenames[grid_type-GAME_TYPE]);
    return;
   }

 for(i=0;i<NLEVELS;i++)
    for(j=0;j<10;j++)
      {
       sn.score=score[i][j];
       strcpy(sn.name,name[i][j]);
       sn.date=date[i][j];
       encrypt_score(&sn);
       fwrite(&sn,sizeof(sn),1,f);
      }

 fclose(f);

 chmod(filenames[grid_type-GAME_TYPE],S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
}


/*++++++++++++++++++++++++++++++++++++++
  Prints the high score tables.

  int level The level to print the scores for.
  ++++++++++++++++++++++++++++++++++++++*/

void PrintHighScores(int level)
{
 int l,j;

 LoadHighScores();

 if(level==-1)
    printf("\nHigh score tables for %s\n",types[grid_type-GAME_TYPE]);

 for(l=(level==-1?0:level);l<(level==-1?NLEVELS:level+1);l++)
   {
    printf("\nHigh scores for %s level (%dx%d grid of %s with %d bombs)\n",levels[l],widths[l],heights[l],types[grid_type-GAME_TYPE],nbombs[l]);
    for(j=0;j<10;j++)
      {
       printf("%4s : %12s = ",pos[j],name[l][j]);
       if(!date[l][j])
          printf("  SLOW");
       else if(l==0)
          printf("%6.2f",(double)score[l][j]/1000.0);
       else if(l==1)
          printf("%6.1f",(double)score[l][j]/1000.0);
       else
          printf("%6.0f",(double)score[l][j]/1000.0);
       if(date[l][j])
          printf(" : %s",ctime(&date[l][j]));
       else
         {printf(" : Never\n");break;}
      }
    printf("\n");
   }
}


/*++++++++++++++++++++++++++++++++++++++
  Adds a high score to the table if it is good enough.

  int level The level that has been completed.

  int ticks The time that was taken.
  ++++++++++++++++++++++++++++++++++++++*/

void AddHighScore(int level,int ticks)
{
 int j;
 int changed=-1;

 LoadHighScores();

 for(j=0;j<10;j++)
    if(ticks<score[level][j])
       {changed=j;break;}

 if(changed!=-1)
   {
    for(j=9;j>changed;j--)
      {
       score[level][j]=score[level][j-1];
       strcpy(name[level][j],name[level][j-1]);
       date[level][j]=date[level][j-1];
      }
    score[level][changed]=ticks;
    cuserid(name[level][changed]);
    date[level][changed]=time(&date[level][changed]);
    SaveHighScores();
   }
 else
    printf("Sorry not good enough.\n");

 PrintHighScores(level);
}


/*++++++++++++++++++++++++++++++++++++++
  Decrypts the high score table

  struct score_name* sn The score and name to decrypt.
  ++++++++++++++++++++++++++++++++++++++*/

static void decrypt_score(struct score_name* sn)
{
 int i;
 char *p=(char*)sn;

 for(i=0;i<sizeof(struct score_name);i++)
    p[i]^=125;

 return;
}


/*++++++++++++++++++++++++++++++++++++++
  Encrypts the high score table

  struct score_name* sn The score and name to encrypt.
  ++++++++++++++++++++++++++++++++++++++*/

static void encrypt_score(struct score_name* sn)
{
 int i;
 char *p=(char*)sn;

 for(i=0;i<sizeof(struct score_name);i++)
    p[i]^=125;

 return;
}
