Home | Gaming | Programming | Play Online | Contact | Keyword Query
Games++ Games & Game Programming

GAMES++
Games++ Home
Games++ Gaming
Games++ Programming
Beta Testing Games
Free Online Games
Hints & Cheats

BROWSER UTILITIES
E-mail This Page
Add to Favorites

SITE SEARCH

Web Games++

AFFILIATES
Cheat Codes
Trickster Wiki
Game Ratings
Gameboy Cheats
PlayStation Cheats
BlackBerry Games
Photoshop Tutorials
Illustrator Tutorials
ImageReady Tutorials

ADVERTISEMENT

High Scores

Techtutor Part 3

Part 1 | Part 2 | Part 3 | Part 4 | Part 5

Introduction

Welcome to part 3 of the Techtutor, this one is mainly for SuperFX users, because it explains how to read a string using the keyboard. It does however contains some information for beginners interested in putting a great highscore table in their game...

For an example of a very stylish high-score, read source at bottom

Need More Input...

First of all we'll need to get the name of the player, and the best way would be to let him/her type it. One problem occurs when using the engine, because we don't have the normal keyboard interupt...

We could ofcourse switch back to the old one, but it can be done different. The Engine contains an array which has the "names" of all the keys, and we are going to use that array... For the example, take a look at the GETINPUT procedure (tech03.pas) This procedure will get the input of the player, and return it. Note that this procedure could still use some work, like checking on ESCAPE to exit the input, and it has a few bugs in it. But the most important thing is shown, the checking on the correct key-pressed.

HighScore Typecasting

Before we code anything, we'll have to define a HIGHSCORE type like this:

     TYPE  TScore = record
            name   : string[8];
            score  : longint;
            level  : word;
            date   : Longint;
           end;
  
     VAR   HiScore  : array[1..15] of Tscore;

The example will record the following things about the new high-score:

  • Name of player, the most important item
  • Score of player, very nice to know...
  • Level reached, the level the player reached.
  • Date of game, this is to show when the game was played...

Of course, not all these are needed, but just use what you want in you're game, and simply erase the rest. Now that we have the type, we made an array of 1..15, so we can record 15 players. Again this can be changed for you're own desires.

Who Makes the List...

The next thing we should do is check if the player has a new highscore. To do this, we'll have to walk thru the existing list, and see if the score is larger then the lowest. If it is, then we need to know if it's higher then the next, and the next, and the next, etc...

{=-=-= Example =-=-=-=}
FUNCTION SeeHIScore(Nscore:longint;Nlevel:word):boolean;
VAR i,j  : byte;
    done : boolean;
    dow,hs      : word;
    tempD        : DateTime;

BEGIN
 SeeHiscore:=false;
 if NscoreHiScore[i].score then dec(i) else Done:=true;
 until (i=0) or (done);
    inc(i);
    SeeHiScore:=true;
    for j:=14 downto i do HiScore[j+1]:=HiScore[j];
    with HiScore[i] do begin             { add new highscore }
         Name:=GetName;                  { get the name }

         score := Nscore;                { add score }
         level := NLevel;                { add level }
         GetDate(TempD.year,TempD.month,TempD.day,dow);
         GetTime(TempD.hour,TempD.min,TempD.sec,hs);
         PackTime(TempD,date);           { add date  }
    end;
END;
{=-=-= End of Example =-=-=-=}

This procedure will not only look if we got an highscore, it will also add the new score to the list, and call the GETINPUT procedure for the name.

Show Me, I Wanna See It

So now we got a high-score table...but we still can't see it. Showing the table is the most simple thing in the SuperFX Engine, just walk thru the table, and write the text on screen! You could, ofcourse, first draw a background or something and then put the text "over" it. For the example look at SHOWHISCORE. It will display the complete table (NOTE: this procedure is different from the one found in the example, this one can be used without the SuperFX engine).

{=-=-=-= Example =-=-=-=}
PROCEDURE ShowHIScore;  { for normal text-screens   untested!!! }
VAR i    : byte;
    zin  : string;
    Tdate: DateTime;
    ScoreOFS : byte;
BEGIN
 textcolor(7); textbackground(0); clrscr; 
 ScoreOfs:=2;	

 REPEAT
   gotoxy(1,1); write('NR'); 	  
   gotoxy(4,1,); write('Name'); 
   gotoxy(14,1); write('Score');
   gotoxy(20,1); write('Level');
   gotoxy(26,1); write('Time');
   gotoxy(36,1); write('Date');

   for i:=1 to 15 do begin
     with HiScore[i] do begin
          {
             Show NAME and rank
          }
          str(i,zin);
          while length(zin)<2 do zin:=' '+zin;
          zin:=zin+'. '+NAME;
	gotoxy(1,scoreofs+i); write(zin);
          {
            Show the Score
          }
          str(score,zin);
          while length(zin)<9 do zin:='.'+zin;
          gotoxy(4,scoreofs+i); write(zin);
          {
            Show the level
          }
          str(level,zin);
          gotoxy(20,scoreofs+i); write(zin);
          {
            Get the time of the played game
          }
          UnpackTime(Date,TDate);
          {
             Show the hour played
          }
          str(Tdate.hour,zin);
          while length(zin)<2 do zin:=' '+zin;
          zin:=zin+':';
          gotoxy(26,scoreofs+i); write(zin);
          {
            Show minutes
          }
          str(Tdate.Min,zin);
          while length(zin)<2 do zin:='0'+zin;
          gotoxy(29,scoreofs+i); write(zin);
          {
            Show month name
          }
          zin:=MNames[Tdate.Month];
          zin:=zin+'-';
          gotoxy(36,scoreofs+i); write(zin);
          {
            Show the day
          }
          str(Tdate.day,zin);
          while length(zin)<2 do zin:=' '+zin;
          gotoxy(40,scoreofs+i); write(zin);
          {
            Show the Year
          }
          str(Tdate.year,zin);
          gotoxy(43,scoreofs+i); write(zin);
     end;
   end;

 repeat until port[$60]<>156;
END;

{=-=-=-= End of Example =-=-=-=}

Loading the score

A highscore should ofcourse be saved to disk, so it can be loaded later when the game is played again... so that's what we are going to do. First of all we should be able to load the existing High-score table. You could start loading the file, but what if the file does not exist? so at the start of you're game make sure you "fill" the high-score with some fake values, but remember that the player has to be able to easily get higher scores then the fake ones! Now we have to check if the file exists, if it does we can safely start loading. Note that you don't go and read in a loop from 1 to 15 (or 10), because maybe some one tinkered with the scores and there might only be 4 highscores in the file. So keep track of that..for an example look at the LOADSCORES procedure.

Note: You could add a nice thing here, because if you find somethings wrong with the highscore file, you could create a new blank table, and put in very hi scores the list...just a thought.

{=-=-=-= Example =-=-=-=}
PROCEDURE LoadScores;
VAR f : file;
    i : byte;
    dow,hs      : word;
    tempD       : DateTime;
BEGIN
 assign(f,'hiscore.his');       { name of the hiscore file }
 {$I-}
   reset(f,1);
 {$I+}
  if ioresult<>0 then begin     { No hiscore file found, so create one! }
     rewrite(f,1);
     Hiscore[01].score:=1500;  Hiscore[02].score:=1400;
     Hiscore[03].score:=1300;  Hiscore[04].score:=1200;
     Hiscore[05].score:=1100;  Hiscore[06].score:=1000;
     Hiscore[07].score:=0900;  Hiscore[08].score:=0800;
     Hiscore[09].score:=0700;  Hiscore[10].score:=0600;
     Hiscore[11].score:=0500;  Hiscore[12].score:=0400;
     Hiscore[13].score:=0300;  Hiscore[14].score:=0200;
     Hiscore[15].score:=0100;
     for i:=1 to 15 do begin
         with HiScore[i] do begin
              Name:='ME!';
              Level:=$101;
              GetDate(TempD.year,TempD.month,TempD.day,dow);
              GetTime(TempD.hour,TempD.min,TempD.sec,hs);
              PackTime(TempD,date);
         end;
         blockwrite(f,hiscore[i],sizeof(TScore));
     end;
     close(f);
     exit; { done the loading, so exit }
  end;
 i:=1;
 while (not eof(f)) and (i<16) do begin
       blockread(f,hiscore[i],sizeof(TSCORE));
       inc(i);
 end;
 close(f);
END;
{=-=-= End of Example =-=-=}

Saving the score

After the player get's a new high-score, it's best to save it at once. because if the game crashes the player might loose it's score, and be pissed off at the game, and the programmer (you!). The saving is the easiest of all procedures:

  • Open a NEW file
  • Loop thru the scores, saving them one by one...

I know that you should do some error checking, because if the game is run from CD, you won't be able to save!

{=-=-= Example =-=-=}
PROCEDURE SaveScores;
VAR f : file;
    i : byte;
    dow,hs      : word;
    tempD        : DateTime;
BEGIN
 assign(f,'hiscore.his');
 rewrite(f,1);
 for i:=1 to 15 do blockwrite(f,hiscore[i],sizeof(TSCORE));
 close(f);
END;
{=-=-= End of Example =-=-=-=}

That's all folks

Well that was a brief explanation about high-scores, and how to implement them. I know that most people won't even look at this because they think it's to simple for them, well they had to learn it somewhere and might not even be doing it that correctly, who knows? But for the beginning game-programmers this could be a usefull text, and for the SuperFX Engine users it handy to know who to read the keyboard keys...

Next Tech topic: Collisions

{*******************************Source Code*********************************}
{

        TechTutor3
        HighScores for the SuperFX Engine

        Coding by P.Bestebroer
        FreeWare

        To get this code to work, you need the SuperFX engine, and a little
        bit of programming...

        Contacting:

         HTTP://people.zeelandnet.nl/rpb/
        EMAIL:just4fun@zeelandnet.nl

}
PROGRAM Tech03;

USES CRT,DOS,SuperFX;

{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

                           Hi-Score procedures

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
CONST MNAmes      : array[1..12] of string[3] = (
                    'JAN','FEB','MAR','APR','MAY','JUN','JUL','AUG','SEP',
                    'OCT','NOV','DEC');

TYPE  TScore = record
        name   : string[8];     { name of the player }
        score  : longint;       { the high-score of the player }
        level  : word;          { the level the played reached }
        date   : Longint;       { the date of the played game  }
      end;

VAR   HiScore  : array[1..15] of Tscore;          { a top-15 high-score table}

{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{
        Load the hiscores

        Expects: Nothing
        Returns: Nothing
}
PROCEDURE LoadScores;
VAR f : file;
    i : byte;
    dow,hs      : word;
    tempD       : DateTime;
BEGIN
 assign(f,'hiscore.his');       { name of the hiscore file }
 {$I-}
   reset(f,1);
 {$I+}
  if ioresult<>0 then begin     { No hiscore file found, so create one! }
     rewrite(f,1);
     Hiscore[01].score:=1500;  Hiscore[02].score:=1400;
     Hiscore[03].score:=1300;  Hiscore[04].score:=1200;
     Hiscore[05].score:=1100;  Hiscore[06].score:=1000;
     Hiscore[07].score:=0900;  Hiscore[08].score:=0800;
     Hiscore[09].score:=0700;  Hiscore[10].score:=0600;
     Hiscore[11].score:=0500;  Hiscore[12].score:=0400;
     Hiscore[13].score:=0300;  Hiscore[14].score:=0200;
     Hiscore[15].score:=0100;
     for i:=1 to 15 do begin
         with HiScore[i] do begin
              Name:='SFX';
              Level:=$101;
              GetDate(TempD.year,TempD.month,TempD.day,dow);
              GetTime(TempD.hour,TempD.min,TempD.sec,hs);
              PackTime(TempD,date);
         end;
         blockwrite(f,hiscore[i],sizeof(TScore));
     end;
     close(f);
     exit; { done the loading, so exit }
  end;
 i:=1;
 while (not eof(f)) and (i<16) do begin
       blockread(f,hiscore[i],sizeof(TSCORE));
       inc(i);
 end;
 close(f);
END;

{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{
        Save the hiscores

        Expects: Nothing
        Returns: Nothing
}
PROCEDURE SaveScores;
VAR f : file;
    i : byte;
    dow,hs      : word;
    tempD        : DateTime;
BEGIN
 assign(f,'hiscore.his');
 rewrite(f,1);
 for i:=1 to 15 do blockwrite(f,hiscore[i],sizeof(TSCORE));
 close(f);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{
        Get the player name

        Expects: Nothing
        Returns: The name
}
FUNCTION GetNAME:string;
VAR zin : string;
    i   : byte;
    stop: boolean;
BEGIN
 zin:='';
 UPDATEMAP;                                     { draw background map }
 WText(100,120,zin);                             { show current name   }
 WText(120,90, 'A NEW HIGH SCORE!');             { text1 }
 WText(100,105,'PLEASE ENTER YOU''R NAME');      { text2 }
 SHOWBITMAP;                                    { show virtual page   }
 FadeIn(0,255);                                 { fade in the colors  }
 stop:=false;
 repeat
   UPDATEMAP;                                   { draw background map }
   WText(100,120,zin+'@');                       { show current name   }
   WText(120,90, 'A NEW HIGH SCORE!');           { text1 }
   WText(100,105,'PLEASE ENTER YOU''R NAME');    { text2 }
   SHOWBITMAP;                                  { show virtual page }

   if key[ 28] then stop:=true;                 { ENTER key         }
   IF length(zin)<8 then begin
       for i:=1 to 84 do if key[i] then begin
           if length(KeyName[i])=1 then zin:=zin+KeyName[i]; { add letter    }
           if KeyName[i]='Space' then zin:=zin+' ';          { add space     }
           if Key[ 14{BackSpace}] then begin                 { delete char   }
              if length(zin)>1 then zin:=copy(zin,1,length(zin)-1)
                 else zin:='';
           end;
           while key[i] do;         { repeat until key is unpressed }
       end;
    END else IF key[ 14{BackSpace}] then begin
        if length(zin)>1 then zin:=copy(zin,1,length(zin)-1) else zin:='';
        while AnyPressed do;
    END;
 until key[ 28 ] or stop;
 GetName:=zin;                      { return the sentence (name) }
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{
        See if we've got a new hi-score

        Expects: the score gotten by the player
        Returns: Nothing
}
FUNCTION SeeHIScore(Nscore:longint;Nlevel:word):boolean;
VAR i,j  : byte;
    done : boolean;
    dow,hs      : word;
    tempD        : DateTime;

BEGIN
 SeeHiscore:=false;
 if NscoreHiScore[i].score then dec(i) else Done:=true;
 until (i=0) or (done);
    inc(i);
    SeeHiScore:=true;
    for j:=14 downto i do HiScore[j+1]:=HiScore[j];
    with HiScore[i] do begin             { add new highscore }
         Name:=GetName;                  { get the name }

         score := Nscore;                { add score }
         level := NLevel;                { add level }
         GetDate(TempD.year,TempD.month,TempD.day,dow);
         GetTime(TempD.hour,TempD.min,TempD.sec,hs);
         PackTime(TempD,date);           { add date  }
    end;
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{
        Show the hiscores

        Expects: Nothing
        Returns: Nothing
}
PROCEDURE ShowHIScore;
VAR i    : byte;
    zin  : string;
    Tdate: DateTime;
    ScoreOFS : byte;
    YSpd     : byte;
    YAdd     : integer;
    YPos     : integer;
BEGIN
 Fadeout(0,255);         { fade the colors out }
 ClearScreen;            { clear the screen }
 SetPal;                 { set correct palette }

 SetTEXTSegment(vpage_seg); { make sure text is printed on correct page }

 ScoreOfs:=20;              { Y offset of score }

 Ypos:=199;                 { these variables }
 Yspd:=9;                   { are used }
 Yadd:=-1;                  { for "bouncing" the screen }
 REPEAT
   AddImage(8,10,StatusSprite[1].data,false,false);      { rank  }
   AddImage(37,10,StatusSprite[2].data,false,false);     { name  }
   AddImage(105,10,StatusSprite[3].data,false,false);    { score }
   AddImage(159,10,StatusSprite[4].data,false,false);    { stage }
   AddImage(200,10,StatusSprite[5].data,false,false);    { time  }
   AddImage(255,10,StatusSprite[6].data,false,false);    { date  }

   UpdateMap;               { show the background map }

   for i:=1 to 15 do begin
     with HiScore[i] do begin
          {
             Show NAME and rank
          }
          str(i,zin);
          while length(zin)<2 do zin:=' '+zin;
          zin:=zin+'. '+NAME;
          Wtext(10,ScoreOfs+(i*9),zin);

          {
            Show the Score
          }
          str(score,zin);
          while length(zin)<9 do zin:='.'+zin;
          Wtext(95,ScoreOfs+(i*9),zin);

          {
            Show the level
          }
          str(level div 256,zin);
          Wtext(166,ScoreOfs+(i*9),zin+'-');
          str(level and $ff,zin);
          Wtext(177,ScoreOfs+(i*9),zin);
          {
            Get the time of the played game
          }
          UnpackTime(Date,TDate);
          {
             Show the hour played
          }
          str(Tdate.hour,zin);
          while length(zin)<2 do zin:=' '+zin;
          zin:=zin+':';
          Wtext(195,ScoreOfs+(i*9),zin);
          {
            Show minutes
          }
          str(Tdate.Min,zin);
          while length(zin)<2 do zin:='0'+zin;
          Wtext(212,ScoreOfs+(i*9),zin);

          {
            Show month name
          }
          zin:=MNames[Tdate.Month];
          zin:=zin+'-';
          Wtext(236,ScoreOfs+(i*9),zin);
          {
            Show the day
          }
          str(Tdate.day,zin);
          while length(zin)<2 do zin:=' '+zin;
          Wtext(261,ScoreOfs+(i*9),zin);
          {
            Show the Year
          }
          str(Tdate.year,zin);
          Wtext(278,ScoreOfs+(i*9),zin);
     end;
   end;

   {
      Show the screen normal, or bounce it in if needed
   }
   if (ypos=0) and (yspd=0) then ShowBitmap else begin
      asm
        xor ax,ax
        mov bx,Ypos
        call Displace
      end;
      inc(ypos,yadd);
      if yadd>-8 then dec(Yadd);
      if ypos<=0 then begin
         Ypos:=0;
         Yadd:=Yspd;
         if Yspd>0 then dec(Yspd) else Yspd:=0;
      end;
   end;

 until (ypos=0) and (yspd=0);
 repeat until ANYPRESSED;
 FadeOut(0,255);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
BEGIN
  while port[$60]<>156 do ;
  textcolor(7); textbackground(0); clrscr;
  writeln('TechTutor #3');
  writeln('written by P.Bestebroer, Just4Fun Productions');
  writeln('');
  writeln('This tutor should work, but you need a few things:');
  writeln(' * The SuperFX engine (its freeware, so why not download it ;)');
  writeln(' * some grafichs to use');
  writeln(' * and a game to put it in!');
  writeln;
  writeln('These little procedures where ripped from a space-invadors game');
  writeln('I was working on (never got finished) I just ripped it out, and');
  writeln('used them as example material.');

  writeln('Press a key');
  writeln;
  writeln;
  writeln;
  writeln('----------------------------------');
  writeln('Contacting: just4fun@zeelandnet.nl');
  writeln('http://people.zeelandnet.nl/rpb   ');
  writeln('----------------------------------');
  repeat until port[$60]<>156;

  {=-=-=-=-= This should be the order of calling the procedures =-=-=-=-=}
  LoadScores;
  if SeeHiScore(1000,5) then SaveScores;
             {score^ ^name}
  ShowHiScore;
END.
Copyright © 1998-2007, Games++ All rights reserved. | Privacy Policy