/* 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] 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> 1); Speed=3; Update(); for (i=0; i= 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; }