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