[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]