home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
SIMTEL
/
CPMUG
/
CPMUG048.ARK
/
RALLY.C
< prev
next >
Wrap
C/C++ Source or Header
|
1984-04-29
|
10KB
|
411 lines
/*
H19 RALLY Game, 5/80 Steve Ward
Works ONLY on Heathkit/Zenith H19/Z19 terminal
(or H89 computer)
Command format:
A>rally [-rn] [-b] [mapname] <cr>
where: "n" is an optional seed for the random number generator
(results in exactly the same minor track deviations each
time it is given with a particular track);
If "n" is omitted, then track deviations are totally
random for each session (but same for each run in any
single session.)
"-b" is a debugging option doing Steve-knows-what.
"mapname" specifies the map file to use for the track
(defaults to "rally.map").
*/
#include "bdscio.h" /* Get std console parameters */
#define CARY 16 /* Y position of car. */
#define IBAD 0
#define LSPEED 7 /* Line 25 label posns */
#define LMILES 20
#define MAXSPD 9
#define SPDSCL 128
#define TENTHS 10 /* Number of lines per mile. */
#define TICMIN 1920 /* Number of tics per minute. */
char Free[10000], *Freep;
char CRTFrz, CRTChr;
int Miles;
char Pavement, Freeze, BFlag;
char CurX, CurY, SignY;
int CarX, CarDX;
char RevFlg, AltFlg;
int Speed, Tenths;
char Image[CARY*80+80];
char *ImPtr, *ImEnd;
int Seed;
int Ranno;
char InBuf[BUFSIZ], SavChr;
int SpTime[MAXSPD+1];
struct Road {
struct Node *Next;
char active;
char Token;
int Windy;
int Curvy;
int Age;
int ToGo;
char Holes;
char X;
char dx;
char width; } Road1, Road2;
struct Sign {
struct Node *Next;
char key;
char text[0]; };
struct Fork {
struct Node *Next;
char key;
char *Branch; };
struct Dist {
struct Node *Next;
char key;
char wid, curve, wind;
int miles; };
union Node {
struct Dist;
struct Fork;
struct Sign; } *Tag[128];
/*
Write a character to the terminal, handling X-ON/X-OFF
protocol and not going into a busy loop if the terminal
isn't ready to send a character, but rather just returning
in that case to let the caller do more crunching and try
again later.
*/
putchar(c)
{ char stat, ch;
for(;;)
{ if ((CIMASK & (stat = inp(CSTAT))) == (CAHI ? CIMASK : 0))
switch(ch = (0177 & inp(CDATA))) {
case 'S'-64: CRTFrz=1; break;
case 'Q'-64: CRTFrz=0; break;
case 'C'-64: puts("\033z"); exit();
default: CRTChr=ch; }
if (CRTFrz) continue;
if ((stat & COMASK) == (CAHI ? COMASK : 0))
{ if (c) outp(CDATA,c); return; }
}
}
char *new(size)
{ char *rr;
rr = Freep; Freep += size; return rr; }
struct Dist *NRoad(widx, curv, windx, dist)
{ struct Dist *rr;
rr = new(sizeof *rr);
rr->key = 'D'; rr->Next = 0;
rr->miles = dist; rr->wid = widx;
rr->curve = curv; rr->wind = windx;
return rr; }
struct Sign *NSign(txt)
char *txt;
{ int leng; char *cc, *dd;
struct Sign *ss;
leng = sizeof *ss; leng++;
for (cc=txt; *cc++; leng++);
ss = new(leng); ss->key = 'S'; ss->Next = 0;
dd = &(ss->text); for (cc=txt; *dd++ = *cc++;);
return ss; }
struct Fork *NFork(kk)
{ struct Fork *ff;
ff = new(sizeof *ff); ff->key = kk;
ff->Next = 0; ff->Branch = 0;
return ff; }
PrNode(nn)
struct Node *nn;
{ printf("Node %x: %c -> %x \r\n", nn, nn->key, nn->Next); }
char rdc()
{ char ch;
if (ch = SavChr) { SavChr=0; return ch; };
return (getc(InBuf)); }
char pkc()
{ return (SavChr = rdc()); }
int rdn()
{ int ans, ch;
ans = 0;
while (isdigit(pkc())) ans = ans*10 + (rdc() - '0');
return ans; }
struct Dist *LRoad()
{ int w, c, iwid, dd;
char ch;
dd = rdn();
w = -1; c = -1; iwid = 20;
while (pkc() != '\n') switch(rdc())
{ case '~': c++; continue;
case 'W': iwid = rdn(); continue;
case '!': w++; continue;
default: continue; }
return NRoad(iwid, c, w, dd);
}
struct Dist *Load(name)
char *name;
{ char ch, buf[100], *cc;
struct Sign First, Ignore;
struct Node *it, *last;
puts("\033z");
SavChr = 0;
it = &First; First.key = '?';
if (fopen(name, InBuf) == -1)
{ printf("Can't read %s\r\n", name); exit(); }
while ((ch = rdc()) != 014) putchar(ch);
while ((ch = rdc()) != ('Z'-64))
{ last = it;
switch(ch)
{ case '=': Tag[rdc(InBuf)] = Freep; break;
case '|': while (rdc() != '\n'); break;
case '"': cc = buf;
while (((ch = rdc()) != '"') &&
(ch != '\n')) *cc++ = ch;
*cc = 0;
it->Next = NSign(buf); it = it->Next;
break;
case '#': it->Next = LRoad(); it = it->Next;
break;
case ':': it->Next = rdc();
case '.': it = &Ignore; break;
case '>': it->Next = NFork('R'); it = it->Next;
it->Branch = rdc();
break;
case '<': it->Next = NFork('L'); it = it->Next;
it->Branch = rdc();
break;
case ' ': case '\n': case '\r': case '\t':
case '\f': break;
default: puts("Illegal syntax: "); putchar(ch);
while ((ch = rdc(InBuf)) != '\n') putchar(ch);
puts("\n\r"); break; }}
NSign("Unbound label");
srand1("\033x1\033x5\033Y8 (type a character to start)");
if (!Seed) Seed = rand(); /* Do this only if "-r" option given
without any argument. */
bdos(1);
return First.Next; }
Exec(rr)
struct Road *rr;
{ int x, dir, tt, right, left;
union Node *nn;
nn = rr->Next; rr->Next = nn->Next;
x = rr->X; dir = -1;
switch (nn->key) {
case 'S': right = x+(rr->width); left = 78-right;
x = x>left? 0:right+2;
printf("\033Y%c%c\033G %s \033F",
SignY++, x+32, &(nn->text));
return;
case 'D': rr->Age = 0;
if (nn->wind != 255) rr->Windy = ~(-1 << nn->wind);
if (nn->curve != 255) rr->Curvy = nn->curve;
rr->ToGo = nn->miles;
if (nn->wid != 255) rr->width = nn->wid; return;
case 'L': dir = 1;
case 'R': if (!Freeze) fork(nn->Branch, dir); return;
}
}
MoveTo(x, y) { puts("\033Y"); putchar(y+32); putchar(x+32); }
SpeedL() { MoveTo(LSPEED, 24); putchar(Speed + '0'); }
label(val, posn)
{ printf("\033Y8%c%d ", posn+32, val); }
getchar()
{ char ch;
while (!(ch = CRTChr)) putchar(0);
CRTChr = 0; return ch; }
car(x)
{ puts("\033Y"); putchar(CARY+31); putchar(x+32);
puts(" "); }
roll()
{ puts("\033H\033L");
CurX=0; CurY=0;
if ((ImPtr += 80) == ImEnd) ImPtr = Image;
Pavement = ImPtr[CarX];
setmem(ImPtr, 80, IBAD); }
road(x, width, rdno)
{ char i, *cc;
puts("\033Y ");
putchar(32+x);
if (!RevFlg) { puts("\033p"); RevFlg=1; }
if (!AltFlg) { puts("\033F"); AltFlg=1; }
cc = &(ImPtr[x]);
for (i=width; i--;) { putchar('i'); *cc++ |= rdno; }}
/* Update a Road; returns 1 if finish line. */
UpRd(rr)
struct Road *rr;
{ int ddx, left, right, curve, act, rough; unsigned i;
if (!(act = rr->active)) return 0;
(rr->ToGo)--;
while ((rr->ToGo) <= 0)
{ if (i = (rr->Next))
{ if (i == '.') return 1;
if (i == '*') { rr->active = 0; return 0; }
if (i < 128)
{ rr->Next = Tag[i];
if (BFlag) { puts("\033H\033G");
putchar(i);
puts("\033F"); }}
Exec(rr); }
else { rr->active = 0; return 0; }}
if (Freeze) rough=0;
else rough=1;
if (++(rr->Age) > 24)
if (!(Pavement & (rr->Token)))
{ rr->active = 0; Freeze = 0; return 0; }
ddx = rr->dx;
left = rr->X; right = left+(rr->width);
if (left < 1) ddx = rough;
else if (right > 79) ddx = -rough;
else if ((!Freeze) && (!((rr->Windy) & Ranno)))
{ curve = rr->Curvy;
if (Ranno & 64) ddx += 1;
if (Ranno & 1024) ddx -= 1;
if ((ddx > curve) || (ddx < (-curve))) ddx = rr->dx; }
rr->dx = ddx;
rr->X += ddx;
road(rr->X, rr->width, rr->Token);
return 0; }
/* returns 2 iff end, 0 iff crash, 1 else. */
int Update()
{ int Eor;
SignY=32;
roll();
Eor = UpRd(&Road1) | UpRd(&Road2);
if (Eor) return 2;
Delay(SpTime[Speed]);
if ((CarX += CarDX) < 0) { CarX=0; CarDX=0; }
else if (CarX > 79) { CarX=79; CarDX=0; }
car(CarX);
if (Pavement == IBAD) return 0;
return 1; }
Delay(n)
{ char ch;
n |= 1;
while (n--)
{ putchar(0);
if (CRTChr)
{ ch = getchar();
switch(ch) {
case '4': CarDX--; break;
case '6': CarDX++; break;
case '5':
case '2': if (Speed>1) Speed--; Speed--;
case '8': if (++Speed > MAXSPD) Speed=MAXSPD;
SpeedL();
}}}}
fork(where, dir)
struct Node *where;
{ struct Road *r1, *r2, newx;
r1 = &Road1; r2 = &Road2;
if (!(r1->active)) { r1 = &Road2; r2 = &Road1; }
r1->dx = dir; r2->dx = -dir;
r2->X = r1->X;
r2->active = 1; r2->Age = 0;
r2->Windy = r1->Windy;
r2->Curvy = r1->Curvy;
r2->width = r1->width;
r2->Next = where; r2->ToGo = -1;
Freeze = 1; }
main(argc, argv)
char **argv;
{ int i, j, Mins, Hours, Tics;
char *arg, *MapNam;
struct Node *First;
Seed = 12345;
j = SPDSCL*MAXSPD;
for (i=1; i<= MAXSPD; i++) SpTime[i] = j/i - SPDSCL;
SpTime[MAXSPD] = 0;
BFlag = 0; MapNam = "RALLY.MAP";
for (i=1; i<argc; i++)
{ if (*(arg = argv[i]) == '-') switch(*++arg) {
case 'R': Seed = atoi(++arg);
continue;
case 'B': BFlag++; continue; }
else MapNam = arg; }
CRTFrz = CRTChr = 0;
Freep = Free;
for (i=0; i<128; i++) Tag[i] = 0;
First = Load(MapNam);
top: srand(Seed); Ranno = rand();
Freeze=0;
puts("\033H\033J\033G\033x5\033x1\033Y8 \033K\033p");
puts(" Speed 00 Miles 0 ");
puts("\033Y8X Rally 1.2 Steve Ward ");
setmem(Image,CARY*80,255);
ImPtr = Image; ImEnd = &(Image[CARY*80]);
Road1.Token=1; Road2.Token=2;
Road1.active = 1; Road1.Age = 0; Road1.ToGo = 0;
Road1.X = 20; Road1.dx = 0;
Road2.active = 0;
CarDX = 0;
RevFlg = 0; AltFlg = 0;
Road1.ToGo = 0; Road1.Next= First;
CarX = Road1.X + (Road1.width >> 1);
Speed=3;
Update();
for (i=0; i<CARY; i++) { Update(); SpeedL(); }
Miles=0; Tenths=0;
label(Miles, LMILES); Mins=0; Hours=0; Tics=0;
loop: Ranno = rand();
Tics += SpTime[Speed]+SPDSCL;
while (Tics >= TICMIN) { Tics -= TICMIN; Mins++; };
while (Mins >= 60) { Mins -= 60; Hours++; };
if (!(i = Update()))
{ puts("\033H CRASHED AFTER ");
done: printf("\033G %d Hours, %d Minutes\007!!! !!! !!! ", Hours, Mins);
delay(10000);
goto top; }
else if (i == 2)
{ puts("\033H YOU MADE IT IN ");
goto done; }
if (++Tenths >= 10)
{ label(++Miles, LMILES); Tenths=0; }
goto loop;
}