[Back to GRAPHICS SWAG index]  [Back to Main SWAG index]  [Original]


program SpriteGame;         {Verifies a VGA is present}
{$G+,R-}
(* jh  Syntax:  spritegame.exe  [number]
  optional number is the total population of sprites.  Default is maxsprites.
*)
{ Original Sprites program by Bas van Gaalen, Holland, PD }
{ Modified by Luis Mezquita Raya }
{ Modified by John Howard (jh) into a game }
{ 30-MAY-1994 jh Version 1.0
  Now a game to see which sprite survives the longest.
  Renamed tScrArray to Screen, and tSprArray to SpriteData.
  Removed CRT unit & saved around 1616 bytes.  Added command line parameter.
  Added timer and energy definitions to provide statistics.
  21-JUN-1994 jh Version 1.1 = ~7.5k
  Added OnlyVGA and SetMode procedures.  Added CharSet & CharType definitions.
  Implemented characters as sprites.
  29-JUN-1994 jh Version 1.2 = ~8.5k due to command line help
  Places identification on each sprite by using HexDigits.  CharColor defaults
  to sprite number (0..maxsprites) as a color index in the palette.  Fixed bug
  in moire background screen limits.
}
const
      maxsprites=128;                   { Number of sprites is [1..128] }
      pxsize=320;                       { screen x-size }
      pysize=200;                       { screen y-size }
      xsize=32;                         { sprite x-size }
      ysize=32;                         { sprite y-size }
      CharRows=8;                       { Characters are 8 rows high }
      HexDigits : ARRAY[0..15] OF Char = '0123456789ABCDEF';

type
      Screen=array[0..pysize-1, 0..pxsize-1] of byte;
      pScreen=^Screen;
      SpriteData=array[0..ysize-1, 0..xsize-1] of byte;
      pSpriteData=^SpriteData;
      SprRec=record
              x,y : word;              {Absolute location of sprite}
              xspd,yspd : shortint;    {Velocity horizontal and vertical}
              energy : shortint;       {Hide is neg., dead is 0, show is pos.}
              buf : pSpriteData;       {Rectangle of sprite definition}
             end;
      CharType = array[1..CharRows] of Byte;

var
      CharSet : array[0..255] of CharType absolute $F000:$FA6E;
      sprite : array[1..maxsprites] of SprRec;
      vidscr,virscr,bgscr : pScreen;   {video, virtual, background screens}
      dead : byte;                     {Counts the dead sprites}
      survivor : byte;                 {Identify the last dead sprite}
      Population : word;               {Population from 1..128}
      {CharColor : byte;}              {Character digit color 0..255}

      Timer : longint;                 {Stopwatch}
      H, M, S, S100 : Word;
      Startclock, Stopclock : Real;
      mins, secs     : integer;
      Code: integer;                     {temporary result of VAL conversion}

procedure GetTime(var Hr, Mn, Sec, S100 : word); assembler; {Avoids DOS unit}
asm
    mov ah,2ch
    int 21h
    xor ah,ah                 {fast register clearing instead of MOV AH,0}
    mov al,dl
    les di,S100
    stosw
    mov al,dh
    les di,Sec
    stosw
    mov al,cl
    les di,Mn
    stosw
    mov al,ch
    les di,Hr
    stosw
end;

procedure StartTimer;
begin
  GetTime(H, M, S, S100);
  StartClock := (H * 3600) + (M * 60) + S + (S100 / 100);
end;

procedure StopTimer;
begin
  GetTime(H, M, S, S100);
  StopClock := (H * 3600) + (M * 60) + S + (S100 / 100);
  Timer := trunc(StopClock - StartClock);
  secs := Timer mod 60;                             {Seconds remaining}
  mins := Timer div 60;                             {Reduce into minutes}
end;
function KeyPressed : boolean; assembler;   {Avoids unit CRT.KeyPressed}
asm
    mov ah,01h;    int 16h;    jnz @0;    xor ax,ax;    jmp @1;
@0: mov al,1
@1:
end;

procedure SetMode(M:byte); assembler;
asm
    mov ah,0;        mov al,M;        int 10h;
end;
procedure SetPal(col,r,g,b:byte); assembler;      {256 color palette}
asm
    mov dx,03c8h
    mov al,col             {color}
    out dx,al
    inc dx
    mov al,r               {red component}
    out dx,al
    mov al,g               {green component}
    out dx,al
    mov al,b               {blue component}
    out dx,al
end;
procedure flip(srcscr, destscr : pScreen); assembler;   {copy screen}
asm
    push ds
    lds si,srcscr
    les di,destscr
    mov cx,pxsize*pysize/2
    rep movsw
    pop ds
end;
procedure cls(scr : pScreen); assembler;   {clear screen}
asm
    les di,scr;  xor ax,ax;  mov cx,pxsize*pysize/2;  rep stosw
end;
procedure retrace; assembler;
asm
        mov dx,03dah
@vert1: in al,dx
        test al,8
        jnz @vert1
@vert2: in al,dx
        test al,8
        jz @vert2
end;
procedure PutSprite(var sprite: SprRec; virseg: pScreen); assembler;
asm
        push ds
        lds si,sprite                   { get sprite segment }
        les di,virseg                   { get virtual screen segment }
        mov ax,SprRec[ds:si].y
        shl ax,6
        mov di,ax
        shl ax,2
        add di,ax                       { y*pxsize }
        add di,SprRec[ds:si].x          { y*pxsize+x }
        mov dx,pxsize-xsize             { number of pixels left on line }
        lds si,SprRec[ds:si].buf
        mov bx,ysize
@l1:    mov cx,xsize
@l0:    lodsb
        or al,al
        jz @skip                        { check if transparent "Black" }
        mov es:[di],al                  { draw it }
@skip:  inc di
        dec cx
        jnz @l0
        add di,dx
        dec bx
        jnz @l1
        pop ds
end;
procedure OnlyVGA; assembler;
asm
  @CheckForVga: {push    es}
                mov     AH,1ah         {Get Display Combination Code}
                mov     AL,00h         {AX := $1A00;}
                int     10h            {Intr($10, Regs);}
                cmp     AL,1ah         {IsVGA:= (AL=$1A) AND((BL=7) OR(BL=8))}
                jne     @NoVGA
                cmp     BL,07h         {VGA w/ monochrome analog display}
                je      @VgaPresent
                cmp     BL,08h         {VGA w/ color analog display}
                je      @VgaPresent
  @NoVGA:
                mov     ax,3           {text mode}
                int     10h
                push    cs
                pop     ds
                lea     dx,@message
                mov     ah,9
                int     21h            {print $ terminated string}
                mov     ax,4c00h
                int     21h            {terminate}
  @message:     db      'Sorry, but you need a VGA to see this!',10,13,24h
  @VgaPresent:  {pop     es}
  {... After here is where your VGA code can execute}
end;  {OnlyVGA}

VAR   n : byte;               {sprite number}
      hx,hy,i,j,k,np : integer;
BEGIN  {PROGRAM}
 {Get text from command line and convert into a number}
 Val(ParamStr(1), Population, Code);
 if (Code <> 0)    {writeln('Bad number at position: ', Code);}
   OR (Population <1) OR (Population > maxsprites) then
   Population := maxsprites;    {default}
 if ParamStr(1) = '?' then
   begin
    writeln('Howard International, P.O. Box 34633, NKC, MO 64116 USA');
    writeln('1994 Freeware Sprite Game v1.2');
    writeln('Syntax:  spritegame.exe  [number]');
    writeln('         optional number is the total population of sprites (1 to 128)');
    halt;
   end;

 {CharColor := Population;}
 OnlyVGA;
 SetMode($13);                  {320x200x256x1 plane}
 Randomize;
 vidscr := Ptr($A000,0);
 New(virscr); cls(virscr); New(bgscr); cls(bgscr);
 np := 128 div Population;
 for i := 0 to Population-1 do
  begin  {Define moire background pattern}
   case i mod 6 of
    0:begin
       hx := 23;       hy := i*np;       n := 0;
      end;
    1:begin
       hx := i*np;     hy := 23;         n := 0;
      end;
    2:begin
       hx := i*np;     hy := 0;          n := 23;
      end;
    3:begin
       hx := 23;       hy := 0;          n := i*np;
      end;
    4:begin
       hx := 0;        hy := 23;         n := i*np;
      end;
    5:begin
       hx:= 0;         hy:= i*np;        n := 23;
      end;
   end;
   for j := 0 to np-1 do
    begin
     k := j shr 1;
     SetPal(np*i+j+1, k+hx, k+hy, k+n);
    end;
  end;

 for i := 1 to 127 do SetPal(127+i, i div 3, 20+i div 5, 20+i div 7);
 for i := 0 to pxsize-1 do     {jh bug!  Reduce to legal screen limits}
   for j := 0 to pysize-1 do
     bgscr^[j,i] := 128+ ABS(i*i - j*j) and 127;
(*
 flip(bgscr, vidscr);               {copy background to video}
 {SetPal(?,r,g,b)}                  {force a visible text palette entry}
 writeln('Sprite Game v1.2 ');      {modify video}
 flip(vidscr, bgscr);               {copy video to background}
*)
 hx := xsize shr 1;
 hy := ysize shr 1;
 for n := 1 to Population do
  begin
   with sprite[n] do
    begin
     x := 20+ random(280 - xsize);
     y := 20+ random(160 - ysize);
     xspd := random(6) - 3;
     yspd := random(6) - 3;
     energy := random(10);         {punishes liberals}
     if xspd=0 then
       begin
        xspd := 1;
        energy := random(20);      {average life expectancy}
       end;
     if yspd=0 then
       begin
        yspd := 1;
        energy := random(40);      {rewards conservatives}
       end;
     New(buf);
     for i := 0 to xsize-1 do
      for j := 0 to ysize-1 do
       begin
        k := (i-hx) * (i-hx) + (j-hy) * (j-hy);
        if (k< hx*hx) and (k> hx*hx div 16)
        then buf^[j,i] := k mod np  + np * (n-1)
        else buf^[j,i] := 0;       {CRT color "Black" is transparent}
       end;
    end; {with}
  end; {for}

  {jh Can store your own bitmap image in any sprite[n].buf^[j,i] such as: }
  for i := 0 to xsize-1 do
    for j := 0 to ysize-1 do
      begin
        sprite[1].buf^[j,i] := j;           {first sprite.  Horizontal bars}
        sprite[Population].buf^[j,i] := i;  {last sprite.  Vertical bars}
      end;

  {jh Get characters from default font and attach to sprites}
  for i := 1 to CharRows do
    for j := 1 to CharRows do
      begin
        for n := 1 to Population do
          begin
            {first hex digit for current sprite}
            if (CharSet[ord(HexDigits[n SHR 4]),i] shr (8-j) and 1 = 1) then
              sprite[n].buf^[i,j] := n       {CharColor}
            else
              sprite[n].buf^[i,j] := 0;      {transparent}
            {second hex digit for current sprite}
            if (CharSet[ord(HexDigits[n AND $F]),i] shr (8-j) and 1 =1) then
              sprite[n].buf^[i,j+CharRows] := n   {CharColor}
            else
              sprite[n].buf^[i,j+CharRows] := 0;  {transparent}
          end;
(* {mark last sprite 'Z'}
   sprite[Population].buf^[i,j] := CharSet[ord('Z'),i] shr (8-j) and 1; *)
      end;

  {jh Keep track of the last dead sprite and how old it was. }
  StartTimer;
  while not (KeyPressed or (dead=Population)) do
  begin
  flip(bgscr, virscr);
  retrace;
  dead := 0;                         {reset the sentinel}
  for n := 1 to Population do
    with sprite[n] do
    begin
      if energy > 0 then PutSprite(sprite[n], virscr)     {show(n)}
      { else if energy < 0 then hide(n) }
      else inc(dead);
      inc(x,xspd);
      if (x<10) or (x > (310 - xsize)) then
      begin
        xspd := -xspd;
        energy := energy - 1;
      end;
      inc(y,yspd);
      if (y<10) or (y > (190 - ysize)) then
      begin
        yspd := -yspd;
        energy := energy - 1;
      end;
    end; {with}
  flip(virscr, vidscr);
  end; {while}

  StopTimer;
  survivor := 0;
  for n := 1 to Population do
    begin                           {find last dead sprite with zero energy}
      if sprite[n].energy = 0 then survivor := n;
      Dispose(sprite[n].buf);
    end;
  Dispose(virscr);  Dispose(bgscr);
  SetMode($3);      {resume text video mode 3h= 80x25x16 color}
  writeln('Last dead sprite was # ', survivor, ' of ', Population);
  writeln('Time of death was ', trunc(StopClock));
  writeln('Life span was ', mins:2, ' Minute and ', secs:2, ' Seconds');
END.   {PROGRAM}

[Back to GRAPHICS SWAG index]  [Back to Main SWAG index]  [Original]