mirror of https://github.com/wwarthen/RomWBW.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1284 lines
28 KiB
1284 lines
28 KiB
##
|
|
## This is Daimler's 350-point "Adventure" (circa June 1990, according
|
|
## to Russel Dalenberg). Its version information lists
|
|
##
|
|
## -Conversion to BDS C by J. R. Jaeger
|
|
## -Unix standardization by Jerry D. Pohl.
|
|
## -OS/2 Conversion by Martin Heller
|
|
## -Conversion to TurboC 2.0 by Daimler
|
|
##
|
|
## It contains Jerry Pohl's original ADVENT.DOC (dated 12 JUNE 1984),
|
|
## plus comments from Martin Heller (dated 30-Aug-1988). Strangely for
|
|
## an expansion, Daimler's version actually introduces a number of typos
|
|
## into the data files, and disables a handful of inessential verbs
|
|
## (READ, EAT, FILL) with the comment that there is "no room" for them
|
|
## (presumably in the PC's limited memory).
|
|
## -------------------------------------------------------------------
|
|
## Adapted for HiTech C Z80 under CP/M by Ladislau Szilagyi, Oct. 2023
|
|
## Uncommented Daimler's disabled verbs - game is complete again !
|
|
## Added a new pseudo-random number generator (Xorshift)
|
|
## Adapted to Cowgol language by Ladislau Szilagyi, Feb. 2024
|
|
|
|
@decl sub get_dbugflg(): (ret: uint8) @extern("get_dbugflg");
|
|
@decl sub move(obj: uint16, where: int16) @extern("move");
|
|
|
|
# some utilities --------------------------------------------------------------
|
|
|
|
sub exit() @extern("exit") is
|
|
@asm "rst 0";
|
|
end sub;
|
|
|
|
sub get_char(): (c: uint8) @extern("get_char") is
|
|
@asm "ld c, 1";
|
|
@asm "call 5";
|
|
@asm "ld (", c, "), a";
|
|
end sub;
|
|
|
|
# expands LF to CR,LF
|
|
sub print_char(c: uint8) @extern("print_char") is
|
|
if c == 10 then
|
|
@asm "ld e, 13";
|
|
@asm "ld c, 2";
|
|
@asm "call 5";
|
|
end if;
|
|
@asm "ld a, (", c, ")";
|
|
@asm "ld e, a";
|
|
@asm "ld c, 2";
|
|
@asm "call 5";
|
|
end sub;
|
|
|
|
sub print(ptr: [uint8]) @extern("print") is
|
|
loop
|
|
var c := [ptr];
|
|
if c == 0 then
|
|
return;
|
|
end if;
|
|
print_char(c);
|
|
ptr := ptr + 1;
|
|
end loop;
|
|
end sub;
|
|
|
|
sub print_nl() @extern("print_nl") is
|
|
print_char('\n');
|
|
end sub;
|
|
|
|
# get up to 80 chars , ended with CR
|
|
sub get_line(p: [uint8]) @extern("get_line") is
|
|
var n: uint8;
|
|
var ch: uint8;
|
|
|
|
n := 0;
|
|
while n < 80 loop
|
|
ch := get_char();
|
|
if ch == '\r' then
|
|
print_nl();
|
|
[p] := 0;
|
|
return;
|
|
end if;
|
|
[p] := ch;
|
|
p := p + 1;
|
|
n := n + 1;
|
|
end loop;
|
|
[p] := 0;
|
|
end sub;
|
|
|
|
var pbuf: [uint8] := " ";
|
|
|
|
sub itoa(i: int16): (pbuf: [uint8]) @extern("itoa") is
|
|
var sign: uint8 := 0;
|
|
|
|
if i < 0 then
|
|
sign := 1;
|
|
end if;
|
|
|
|
pbuf := pbuf + 11; # points to terminating zero
|
|
[pbuf] := 0;
|
|
|
|
loop
|
|
pbuf := pbuf - 1;
|
|
[pbuf] := '0' + ((i % 10) as uint8);
|
|
i := i / 10;
|
|
if i == 0 then break; end if;
|
|
end loop;
|
|
|
|
if sign == 1 then
|
|
pbuf := pbuf - 1;
|
|
[pbuf] := '-';
|
|
end if;
|
|
end sub;
|
|
|
|
sub ltoa(i: int32): (pbuf: [uint8]) @extern("ltoa") is
|
|
var sign: uint8 := 0;
|
|
|
|
if i < 0 then
|
|
sign := 1;
|
|
end if;
|
|
|
|
pbuf := pbuf + 11; # points to terminating zero
|
|
[pbuf] := 0;
|
|
|
|
loop
|
|
pbuf := pbuf - 1;
|
|
[pbuf] := '0' + ((i % 10) as uint8);
|
|
i := i / 10;
|
|
if i == 0 then break; end if;
|
|
end loop;
|
|
|
|
if sign == 1 then
|
|
pbuf := pbuf - 1;
|
|
[pbuf] := '-';
|
|
end if;
|
|
end sub;
|
|
|
|
sub isdigit(ch: uint8): (ret: uint8) @extern("isdigit") is
|
|
if ch >= '0' and ch <= '9' then
|
|
ret := 1;
|
|
else
|
|
ret := 0;
|
|
end if;
|
|
end sub;
|
|
|
|
sub atoi(p: [uint8]): (ret: int16) @extern("atoi") is
|
|
var sign: uint8 := 0;
|
|
|
|
ret := 0;
|
|
if [p] == '-' then
|
|
sign := 1;
|
|
p := p + 1;
|
|
end if;
|
|
while [p] != 0 loop
|
|
if isdigit([p]) == 1 then
|
|
ret := ret * 10 + (([p] - '0') as int16); p := p + 1;
|
|
else
|
|
ret := -1; return;
|
|
end if;
|
|
end loop;
|
|
if sign == 1 then
|
|
ret := -ret;
|
|
end if;
|
|
end sub;
|
|
|
|
sub atol(p: [uint8]): (ret: int32) @extern("atol") is
|
|
var sign: uint8 := 0;
|
|
|
|
ret := 0;
|
|
while [p] != 0 loop
|
|
if isdigit([p]) == 1 then
|
|
ret := ret * 10 + (([p] - '0') as int32); p := p + 1;
|
|
else
|
|
ret := -1; return;
|
|
end if;
|
|
end loop;
|
|
if sign == 1 then
|
|
ret := -ret;
|
|
end if;
|
|
end sub;
|
|
|
|
# Fatal error routine
|
|
sub bug(n: uint8) @extern("bug") is
|
|
print("Fatal error number ");
|
|
print(itoa(n as int16));
|
|
print_nl();
|
|
exit();
|
|
end sub;
|
|
|
|
sub strcpy(dest: [uint8], src: [uint8]) @extern("strcpy") is
|
|
while [src] != 0 loop
|
|
[dest] := [src]; dest := dest + 1; src := src + 1;
|
|
end loop;
|
|
[dest] := 0;
|
|
end sub;
|
|
|
|
sub strcmp(s1: [uint8], s2: [uint8]): (ret: int8) @extern("strcmp") is
|
|
loop
|
|
if [s1] < [s2] then
|
|
ret := -1; return;
|
|
elseif [s1] > [s2] then
|
|
ret := 1; return;
|
|
elseif [s1] == 0 then
|
|
ret := 0; return;
|
|
end if;
|
|
s1 := s1 + 1;
|
|
s2 := s2 + 1;
|
|
end loop;
|
|
end sub;
|
|
|
|
sub strlen(s: [uint8]): (ret: uint16) @extern("strlen") is
|
|
ret := 0;
|
|
while [s] != 0 loop
|
|
ret := ret + 1;
|
|
s := s + 1;
|
|
end loop;
|
|
end sub;
|
|
|
|
sub strcat(dest: [uint8], src: [uint8]) @extern("strcat") is
|
|
dest := dest + strlen(dest);
|
|
while [src] != 0 loop
|
|
[dest] := [src]; dest := dest + 1; src := src + 1;
|
|
end loop;
|
|
[dest] := 0;
|
|
end sub;
|
|
|
|
sub rindex(str: [uint8], ch: uint8): (ret: [uint8]) @extern("rindex") is
|
|
loop
|
|
if [str] == ch then
|
|
ret := str;
|
|
return;
|
|
end if;
|
|
str := str + 1;
|
|
if [str] == 0 then
|
|
ret := 0 as [uint8];
|
|
return;
|
|
end if;
|
|
end loop;
|
|
end sub;
|
|
|
|
sub MemSet(buf: [uint8], byte: uint8, len: uint16) @extern("MemSet") is
|
|
var bufend := buf + len;
|
|
loop
|
|
if buf == bufend then
|
|
return;
|
|
end if;
|
|
[buf] := byte;
|
|
buf := buf + 1;
|
|
end loop;
|
|
end sub;
|
|
|
|
var argv_pointer: [uint8];
|
|
|
|
sub ArgvInit() @extern("ArgvInit") is
|
|
argv_pointer := 0x81 as [uint8];
|
|
[argv_pointer + [0x80 as [uint8]] as intptr] := 0;
|
|
end sub;
|
|
|
|
# Returns null is there's no next argument.
|
|
sub ArgvNext(): (arg: [uint8]) @extern("ArgvNext") is
|
|
# No more arguments?
|
|
|
|
if argv_pointer == (0 as [uint8]) then
|
|
arg := argv_pointer;
|
|
return;
|
|
end if;
|
|
|
|
# Skip leading whitespace.
|
|
|
|
var c: uint8;
|
|
loop
|
|
c := [argv_pointer];
|
|
if c != ' ' then
|
|
break;
|
|
end if;
|
|
argv_pointer := argv_pointer + 1;
|
|
end loop;
|
|
|
|
arg := argv_pointer;
|
|
|
|
# Skip to end of word and terminate.
|
|
|
|
loop
|
|
c := [argv_pointer];
|
|
if (c == ' ') or (c == '\n') or (c == 0) then
|
|
break;
|
|
end if;
|
|
argv_pointer := argv_pointer + 1;
|
|
end loop;
|
|
[argv_pointer] := 0;
|
|
|
|
if c == ' ' then
|
|
argv_pointer := argv_pointer + 1;
|
|
else
|
|
argv_pointer := 0 as [uint8];
|
|
end if;
|
|
end sub;
|
|
|
|
# file I/O support ---------------------------------------------------------
|
|
|
|
record CpmFCB is
|
|
dr: uint8;
|
|
f: uint8[11];
|
|
ex: uint8;
|
|
s1: uint8;
|
|
s2: uint8;
|
|
rc: uint8;
|
|
d: uint8[16];
|
|
cr: uint8;
|
|
r: uint16;
|
|
r2: uint8;
|
|
end record;
|
|
|
|
record FCB is
|
|
bufferptr: uint8; # byte just read
|
|
dirty: uint8;
|
|
cpm: CpmFCB;
|
|
buffer: uint8[128];
|
|
end record;
|
|
|
|
sub file_i_init(fcb: [FCB], filename: [uint8]) is
|
|
sub fill(dest: [uint8], src: [uint8], len: uint8): (srcout: [uint8]) is
|
|
loop
|
|
var c := [src];
|
|
if (c < 32) or (c == '.') then
|
|
c := ' ';
|
|
elseif (c == '*') then
|
|
c := '?';
|
|
else
|
|
src := src + 1;
|
|
end if;
|
|
if (c >= 'a') and (c <= 'z') then
|
|
c := c - ('a' - 'A');
|
|
end if;
|
|
[dest] := c;
|
|
dest := dest + 1;
|
|
|
|
len := len - 1;
|
|
if len == 0 then
|
|
break;
|
|
end if;
|
|
end loop;
|
|
srcout := src;
|
|
end sub;
|
|
|
|
MemSet(fcb as [uint8], 0, @bytesof FCB);
|
|
MemSet(&fcb.cpm.f[0] as [uint8], ' ', 11);
|
|
filename := fill(&fcb.cpm.f[0], filename, 8);
|
|
|
|
var c: uint8;
|
|
loop
|
|
c := [filename];
|
|
if (c < 32) or (c == '.') then
|
|
break;
|
|
end if;
|
|
filename := filename + 1;
|
|
end loop;
|
|
|
|
if c == '.' then
|
|
filename := fill(&fcb.cpm.f[8], filename+1, 3);
|
|
end if;
|
|
|
|
fcb.cpm.r := 0xffff;
|
|
fcb.bufferptr := 127;
|
|
end sub;
|
|
|
|
sub fcb_i_gbpb(fcb: [FCB], c: uint8) is
|
|
var cpmfcb := &fcb.cpm;
|
|
var dma := &fcb.buffer[0];
|
|
|
|
@asm "ld c, 26"; # SET DMA
|
|
@asm "ld de, (", dma, ")";
|
|
@asm "call 5";
|
|
|
|
@asm "ld a, (", c, ")";
|
|
@asm "ld c, a";
|
|
@asm "ld de, (", cpmfcb, ")";
|
|
@asm "call 5";
|
|
end sub;
|
|
|
|
sub fcb_i_blockin(fcb: [FCB]) is
|
|
MemSet(&fcb.buffer[0], 0, 128);
|
|
fcb_i_gbpb(fcb, 33); # READ RANDOM
|
|
fcb.dirty := 0;
|
|
end sub;
|
|
|
|
sub fcb_i_blockout(fcb: [FCB]) is
|
|
if fcb.dirty != 0 then
|
|
fcb_i_gbpb(fcb, 34); # WRITE RANDOM
|
|
fcb.dirty := 0;
|
|
end if;
|
|
end sub;
|
|
|
|
sub fcb_i_changeblock(fcb: [FCB], newblock: uint16) is
|
|
if newblock != fcb.cpm.r then
|
|
fcb_i_blockout(fcb);
|
|
fcb.cpm.r := newblock;
|
|
fcb_i_blockin(fcb);
|
|
end if;
|
|
end sub;
|
|
|
|
sub fcb_a_to_error() is
|
|
@asm "cp 0xff";
|
|
@asm "ld a, 0";
|
|
@asm "ret nz";
|
|
@asm "inc a";
|
|
end sub;
|
|
|
|
sub FCBOpenIn(fcb: [FCB], filename: [uint8]): (errno: uint8) @extern("FCBOpenIn") is
|
|
file_i_init(fcb, filename);
|
|
|
|
var cpmfcb := &fcb.cpm;
|
|
@asm "ld c, 15"; # OPEN_FILE
|
|
@asm "ld de, (", cpmfcb, ")";
|
|
@asm "call 5";
|
|
@asm "call", fcb_a_to_error;
|
|
@asm "ld (", errno, "), a";
|
|
end sub;
|
|
|
|
sub FCBOpenUp(fcb: [FCB], filename: [uint8]): (errno: uint8) is
|
|
(errno) := FCBOpenIn(fcb, filename);
|
|
end sub;
|
|
|
|
sub FCBOpenOut(fcb: [FCB], filename: [uint8]): (errno: uint8) is
|
|
file_i_init(fcb, filename);
|
|
|
|
var cpmfcb := &fcb.cpm;
|
|
@asm "ld c, 19"; # DELETE_FILE
|
|
@asm "ld de, (", cpmfcb, ")";
|
|
@asm "call 5";
|
|
|
|
@asm "ld c, 22"; # CREATE_FILE
|
|
@asm "ld de, (", cpmfcb, ")";
|
|
@asm "call 5";
|
|
@asm "call", fcb_a_to_error;
|
|
@asm "ld (", errno, "), a";
|
|
end sub;
|
|
|
|
sub FCBClose(fcb: [FCB]): (errno: uint8) @extern("FCBClose") is
|
|
fcb_i_blockout(fcb);
|
|
|
|
var cpmfcb := &fcb.cpm;
|
|
@asm "ld c, 16"; # CLOSE_FILE
|
|
@asm "ld de, (", cpmfcb, ")";
|
|
@asm "call 5";
|
|
@asm "call", fcb_a_to_error;
|
|
@asm "ld (", errno, "), a";
|
|
end sub;
|
|
|
|
sub FCBSeek(fcb: [FCB], pos: uint32) @extern("FCBSeek") is
|
|
pos := pos - 1; # seek to *previous* character
|
|
var newblock := (pos >> 7) as uint16;
|
|
var newptr := (pos as uint8) & 127;
|
|
fcb_i_changeblock(fcb, newblock);
|
|
fcb.bufferptr := newptr;
|
|
end sub;
|
|
|
|
sub FCBPos(fcb: [FCB]): (pos: uint32) is
|
|
pos := (((fcb.cpm.r as uint32) << 7) | (fcb.bufferptr as uint32)) + 1;
|
|
end sub;
|
|
|
|
sub FCBExt(fcb: [FCB]): (len: uint32) is
|
|
var oldblock := fcb.cpm.r;
|
|
var cpmfcb := &fcb.cpm;
|
|
|
|
@asm "ld c, 16"; # CLOSE_FILE (actually flushing it to disk)
|
|
@asm "ld de, (", cpmfcb, ")";
|
|
@asm "call 5";
|
|
|
|
@asm "ld c, 35"; # COMPUTE FILE SIZE
|
|
@asm "ld de, (", cpmfcb, ")";
|
|
@asm "call 5";
|
|
|
|
len := ([&fcb.cpm.r as [uint32]] & 0x00ffffff) << 7;
|
|
fcb.cpm.r := oldblock;
|
|
end sub;
|
|
|
|
sub fcb_i_nextchar(fcb: [FCB]) is
|
|
fcb.bufferptr := fcb.bufferptr + 1;
|
|
if fcb.bufferptr == 128 then
|
|
fcb_i_changeblock(fcb, fcb.cpm.r + 1);
|
|
fcb.bufferptr := 0;
|
|
end if;
|
|
end sub;
|
|
|
|
sub FCBGetChar(fcb: [FCB]): (c: uint8) @extern("FCBGetChar") is
|
|
fcb_i_nextchar(fcb);
|
|
c := fcb.buffer[fcb.bufferptr];
|
|
end sub;
|
|
|
|
sub FCBPutChar(fcb: [FCB], c: uint8) is
|
|
fcb_i_nextchar(fcb);
|
|
fcb.buffer[fcb.bufferptr] := c;
|
|
fcb.dirty := 1;
|
|
end sub;
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
var fd1: FCB;
|
|
var fd2: FCB;
|
|
var fd3: FCB;
|
|
var fd4: FCB;
|
|
|
|
sub closefiles() @extern("closefiles") is
|
|
var sts: uint8;
|
|
sts := FCBClose(&fd1);
|
|
sts := FCBClose(&fd2);
|
|
sts := FCBClose(&fd3);
|
|
sts := FCBClose(&fd4);
|
|
end sub;
|
|
|
|
# Open advent?.txt files
|
|
sub opentxt() @extern("opentxt") is
|
|
var sts: uint8;
|
|
|
|
sts := FCBOpenIn(&fd1, "advent1.txt");
|
|
if sts != 0 then
|
|
print("Sorry, I can't open advent1.txt...\n");
|
|
exit();
|
|
end if;
|
|
sts := FCBOpenIn(&fd2, "advent2.txt");
|
|
if sts != 0 then
|
|
print("Sorry, I can't open advent2.txt...\n");
|
|
exit();
|
|
end if;
|
|
sts := FCBOpenIn(&fd3, "advent3.txt");
|
|
if sts != 0 then
|
|
print("Sorry, I can't open advent3.txt...\n");
|
|
exit();
|
|
end if;
|
|
sts := FCBOpenIn(&fd4, "advent4.txt");
|
|
if sts != 0 then
|
|
print("Sorry, I can't open advent4.txt...\n");
|
|
exit();
|
|
end if;
|
|
end sub;
|
|
|
|
const MAXLOC := 140;
|
|
|
|
var idx1: uint32[MAXLOC] := {
|
|
3,160,304,367,448,
|
|
507,564,689,855,980,
|
|
1086,1333,1385,1567,1694,
|
|
2033,2083,2224,2332,2415,
|
|
2472,2496,2525,2647,2770,
|
|
2894,2963,3029,3125,3164,
|
|
3274,3282,3314,3490,3547,
|
|
4023,4151,4229,4335,4477,
|
|
4574,4733,4793,4853,4913,
|
|
4973,4986,4999,5012,5072,
|
|
5132,5192,5252,5312,5325,
|
|
5385,5398,5581,5594,5691,
|
|
5863,5977,6045,6058,6270,
|
|
6398,6557,6892,7187,7242,
|
|
7302,7447,7512,7532,7688,
|
|
7744,7803,7896,7953,8065,
|
|
8125,8139,8153,8213,8273,
|
|
8287,8301,8361,8516,8589,
|
|
8643,8818,9043,9096,9154,
|
|
9364,9499,9698,9944,10149,
|
|
10283,10357,10504,10769,10834,
|
|
10888,11197,11262,11328,11802,
|
|
12278,12486,12553,12884,12899,
|
|
13652,14160,14346,14427,14494,
|
|
14561,14628,14722,14818,15026,
|
|
15215,16503,16733,16843,16980,
|
|
17180,17247,17312,17379,17446,
|
|
17511,17576,17641,17708,17773
|
|
};
|
|
|
|
var idx2: uint32[MAXLOC] := {
|
|
3,35,62,89,110,
|
|
131,152,184,209,237,
|
|
265,292,344,372,404,
|
|
433,483,519,554,586,
|
|
644,668,697,736,760,
|
|
784,853,919,1015,1054,
|
|
1164,1172,1204,1224,1281,
|
|
1310,1339,1417,1523,1554,
|
|
1651,1692,1752,1812,1872,
|
|
1932,1946,1960,1974,2034,
|
|
2094,2154,2214,2274,2288,
|
|
2348,2362,2390,2404,2501,
|
|
2538,2575,2643,2657,2689,
|
|
2817,2850,2889,2914,2969,
|
|
3029,3077,3142,3162,3214,
|
|
3270,3329,3422,3479,3591,
|
|
3651,3665,3679,3739,3799,
|
|
3813,3827,3887,3918,3991,
|
|
4045,4091,4117,4170,4228,
|
|
4265,4290,4319,4347,4370,
|
|
4398,4424,4452,4479,4544,
|
|
4598,4623,4688,4715,4745,
|
|
4775,4809,4876,4902,4917,
|
|
4954,4991,5024,5057,5124,
|
|
5191,5258,5291,5316,5345,
|
|
5386,5421,5457,5491,5528,
|
|
5556,5623,5688,5755,5822,
|
|
5887,5952,6017,6084,6149
|
|
};
|
|
|
|
const MAXOBJ := 100;
|
|
|
|
var idx3: uint32[MAXOBJ] := {
|
|
3,63,153,208,274,
|
|
355,436,524,636,770,
|
|
833,889,981,1110,1200,
|
|
1377,1469,1473,1477,1522,
|
|
1640,1668,1693,1709,2151,
|
|
2315,2335,2424,2518,2541,
|
|
2557,2780,3020,3196,3250,
|
|
3451,3643,3674,3821,3924,
|
|
3952,3956,3960,3964,3968,
|
|
3972,3976,3980,3984,3988,
|
|
4062,4112,4166,4223,4269,
|
|
4329,4444,4509,4733,4812,
|
|
4891,4957,5072,5120,0,
|
|
0,0,0,0,0,
|
|
0,0,0,0,0,
|
|
0,0,0,0,0,
|
|
0,0,0,0,0,
|
|
0,0,0,0,0,
|
|
0,0,0,0,0,
|
|
0,0,0,0,0
|
|
};
|
|
|
|
const MAXMSG := 201;
|
|
|
|
var idx4: uint32[MAXMSG] := {
|
|
3,485,537,655,716,
|
|
760,785,810,842,884,
|
|
959,1073,1119,1148,1194,
|
|
1301,1376,1427,1465,1580,
|
|
1631,1796,1832,1891,1924,
|
|
1950,2060,2113,2152,2180,
|
|
2276,2298,2318,2371,2398,
|
|
2427,2458,2487,2520,2545,
|
|
2571,2666,2687,2698,2735,
|
|
2790,2855,2886,2947,2979,
|
|
3033,4327,4342,4359,4366,
|
|
4397,4485,4609,4659,4781,
|
|
4809,4819,4860,5032,5394,
|
|
5717,5810,5842,5874,6040,
|
|
6067,6104,6138,6268,6306,
|
|
6401,6444,6492,6517,6531,
|
|
6546,6717,6921,7054,7171,
|
|
7312,7372,7385,7398,7411,
|
|
7424,7493,7566,7613,7665,
|
|
7708,7780,7820,7854,7900,
|
|
7990,8033,8097,8170,8214,
|
|
8248,8306,8345,8382,8408,
|
|
8434,8488,8565,8630,8733,
|
|
8804,8874,8991,9059,9129,
|
|
9197,9267,9328,9391,9592,
|
|
9688,9825,9892,10117,10254,
|
|
10373,10503,10712,10986,11202,
|
|
11294,11474,11518,11577,11649,
|
|
11685,11741,13063,13100,13156,
|
|
13229,13270,13293,13333,13418,
|
|
13474,13542,13605,13672,13793,
|
|
13807,13937,14078,14222,14291,
|
|
14332,14382,14619,14759,14830,
|
|
14889,14950,15008,15134,15178,
|
|
15210,15242,15272,15333,15368,
|
|
15395,15442,15509,15564,15737,
|
|
15780,15800,15870,16064,16101,
|
|
16236,16564,16636,16719,16820,
|
|
16873,16945,17067,17195,17238,
|
|
17274,17335,17433,17502,17612,
|
|
17637
|
|
};
|
|
|
|
const EOF := 0x1A;
|
|
|
|
# Function to scan a file up to a specified
|
|
# point and either print or return a string.
|
|
sub rdupto(fdi: [FCB], uptoc: uint8, print: uint8, str: [uint8]) is
|
|
var ch: uint8;
|
|
ch := FCBGetChar(fdi);
|
|
while ch != uptoc loop
|
|
if ch == EOF or ch == 0 then
|
|
return;
|
|
# elseif ch == '\n' then
|
|
# ch := FCBGetChar(fdi);
|
|
# continue;
|
|
elseif print == 1 then
|
|
print_char(ch);
|
|
else
|
|
[str] := ch; str := str + 1;
|
|
end if;
|
|
ch := FCBGetChar(fdi);
|
|
end loop;
|
|
if print == 0 then
|
|
[str] := 0;
|
|
end if;
|
|
end sub;
|
|
|
|
# Function to read a file skipping
|
|
# a given character a specified number
|
|
# of times, with or without repositioning
|
|
# the file.
|
|
sub rdskip(fdi: [FCB], skipc: uint8, n: uint16, rewind: uint8) is
|
|
var ch: uint8;
|
|
if rewind == 1 then
|
|
FCBSeek(fdi, 0);
|
|
end if;
|
|
while n > 0 loop
|
|
ch := FCBGetChar(fdi);
|
|
while ch != skipc loop
|
|
if ch == EOF or ch == 0 then
|
|
bug(32);
|
|
end if;
|
|
ch := FCBGetChar(fdi);
|
|
end loop;
|
|
n := n - 1;
|
|
end loop;
|
|
end sub;
|
|
|
|
# Print a location description from "advent4.txt"
|
|
sub rspeak(msg: uint8) @extern("rspeak") is
|
|
if msg == 54 then
|
|
print("ok.\n");
|
|
else
|
|
if get_dbugflg() == 1 then
|
|
print("Seek loc msg #");
|
|
print(itoa(msg as int16));
|
|
print(" @ ");
|
|
print(ltoa(idx4[msg - 1] as int32));
|
|
end if;
|
|
FCBSeek(&fd4, idx4[msg - 1]);
|
|
rdupto(&fd4, '#', 1, 0);
|
|
end if;
|
|
end sub;
|
|
|
|
# Print an item message for a given state from "advent3.txt"
|
|
sub pspeak(item: uint8, state: int8) @extern("pspeak") is
|
|
FCBSeek(&fd3, idx3[item - 1]);
|
|
rdskip(&fd3, '/', (state+2) as uint16, 0);
|
|
rdupto(&fd3, '/', 1, 0);
|
|
end sub;
|
|
|
|
# Print a long location description from "advent1.txt"
|
|
sub desclg(loc: uint8) @extern("desclg") is
|
|
FCBSeek(&fd1, idx1[loc - 1]);
|
|
rdupto(&fd1, '#', 1, 0);
|
|
end sub;
|
|
|
|
# Print a short location description from "advent2.txt"
|
|
sub descsh(loc: uint8) @extern("descsh") is
|
|
FCBSeek(&fd2, idx2[loc - 1]);
|
|
rdupto(&fd2, '#', 1, 0);
|
|
end sub;
|
|
|
|
record wac is
|
|
aword: [uint8];
|
|
acode: uint16;
|
|
end record;
|
|
|
|
# Adventure vocabulary & encryption
|
|
const MAXWC := 301;
|
|
var wc: wac[] :=
|
|
{
|
|
{"spelunker today",1016},
|
|
{"?", 3051},
|
|
{"above", 29},
|
|
{"abra", 3050},
|
|
{"abracadabra", 3050},
|
|
{"across", 42},
|
|
{"ascend", 29},
|
|
{"attack", 2012},
|
|
{"awkward", 26},
|
|
{"axe", 1028},
|
|
{"back", 8},
|
|
{"barren", 40},
|
|
{"bars", 1052},
|
|
{"batteries", 1039},
|
|
{"battery", 1039},
|
|
{"beans", 1024},
|
|
{"bear", 1035},
|
|
{"bed", 16},
|
|
{"bedquilt", 70},
|
|
{"bird", 1008},
|
|
{"blast", 2023},
|
|
{"blowup", 2023},
|
|
{"bottle", 1020},
|
|
{"box", 1055},
|
|
{"break", 2028},
|
|
{"brief", 2026},
|
|
{"broken", 54},
|
|
{"building", 12},
|
|
{"cage", 1004},
|
|
{"calm", 2010},
|
|
{"canyon", 25},
|
|
{"capture", 2001},
|
|
{"carpet", 1040},
|
|
{"carry", 2001},
|
|
{"catch", 2001},
|
|
{"cave", 67},
|
|
{"cavern", 73},
|
|
{"chain", 1064},
|
|
{"chant", 2003},
|
|
{"chasm", 1032},
|
|
{"chest", 1055},
|
|
{"clam", 1014},
|
|
{"climb", 56},
|
|
{"close", 2006},
|
|
{"cobblestone", 18},
|
|
{"coins", 1054},
|
|
{"continue", 2011},
|
|
{"crack", 33},
|
|
{"crap", 3079},
|
|
{"crawl", 17},
|
|
{"cross", 69},
|
|
{"d", 30},
|
|
{"damn", 3079},
|
|
{"damnit", 3079},
|
|
{"dark", 22},
|
|
{"debris", 51},
|
|
{"depression", 63},
|
|
{"descend", 30},
|
|
{"describe", 57},
|
|
{"detonate", 2023},
|
|
{"devour", 2014},
|
|
{"diamonds", 1051},
|
|
{"dig", 3066},
|
|
{"discard", 2002},
|
|
{"disturb", 2029},
|
|
{"dome", 35},
|
|
{"door", 1009},
|
|
{"down", 30},
|
|
{"downstream", 4},
|
|
{"downward", 30},
|
|
{"dragon", 1031},
|
|
{"drawing", 1029},
|
|
{"drink", 2015},
|
|
{"drop", 2002},
|
|
{"dump", 2002},
|
|
{"dwarf", 1017},
|
|
{"dwarves", 1017},
|
|
{"e", 43},
|
|
{"east", 43},
|
|
{"eat", 2014},
|
|
{"egg", 1056},
|
|
{"eggs", 1056},
|
|
{"emerald", 1059},
|
|
{"enter", 3},
|
|
{"entrance", 64},
|
|
{"examine", 57},
|
|
{"excavate", 3066},
|
|
{"exit", 11},
|
|
{"explore", 2011},
|
|
{"extinguish", 2008},
|
|
{"fee", 2025},
|
|
{"fee", 3001},
|
|
{"feed", 2021},
|
|
{"fie", 2025},
|
|
{"fie", 3002},
|
|
{"fight", 2012},
|
|
{"figure", 1027},
|
|
{"fill", 2022},
|
|
{"find", 2019},
|
|
{"fissure", 1012},
|
|
{"floor", 58},
|
|
{"foe", 2025},
|
|
{"foe", 3003},
|
|
{"follow", 2011},
|
|
{"foo", 2025},
|
|
{"foo", 3004},
|
|
{"food", 1019},
|
|
{"forest", 6},
|
|
{"fork", 77},
|
|
{"forward", 7},
|
|
{"free", 2002},
|
|
{"fuck", 3079},
|
|
{"fum", 2025},
|
|
{"fum", 3005},
|
|
{"get", 2001},
|
|
{"geyser", 1037},
|
|
{"giant", 27},
|
|
{"go", 2011},
|
|
{"gold", 1050},
|
|
{"goto", 2011},
|
|
{"grate", 1003},
|
|
{"gully", 13},
|
|
{"h2o", 1021},
|
|
{"hall", 38},
|
|
{"headlamp", 1002},
|
|
{"help", 3051},
|
|
{"hill", 2},
|
|
{"hit", 2012},
|
|
{"hocus", 3050},
|
|
{"hole", 52},
|
|
{"hours", 2031},
|
|
{"house", 12},
|
|
{"ignite", 2023},
|
|
{"in", 19},
|
|
{"info", 3142},
|
|
{"information", 3142},
|
|
{"inside", 19},
|
|
{"inventory", 2020},
|
|
{"inward", 19},
|
|
{"issue", 1016},
|
|
{"jar", 1020},
|
|
{"jewel", 1053},
|
|
{"jewelry", 1053},
|
|
{"jewels", 1053},
|
|
{"jump", 39},
|
|
{"keep", 2001},
|
|
{"key", 1001},
|
|
{"keys", 1001},
|
|
{"kill", 2012},
|
|
{"knife", 1018},
|
|
{"knives", 1018},
|
|
{"lamp", 1002},
|
|
{"lantern", 1002},
|
|
{"leave", 11},
|
|
{"left", 36},
|
|
{"light", 2007},
|
|
{"lock", 2006},
|
|
{"log", 2032},
|
|
{"look", 57},
|
|
{"lost", 3068},
|
|
{"low", 24},
|
|
{"machine", 1038},
|
|
{"magazine", 1016},
|
|
{"main", 76},
|
|
{"message", 1036},
|
|
{"ming", 1058},
|
|
{"mirror", 1023},
|
|
{"mist", 3069},
|
|
{"moss", 1040},
|
|
{"mumble", 2003},
|
|
{"n", 45},
|
|
{"ne", 47},
|
|
{"nest", 1056},
|
|
{"north", 45},
|
|
{"nothing", 2005},
|
|
{"nowhere", 21},
|
|
{"nugget", 1050},
|
|
{"null", 21},
|
|
{"nw", 50},
|
|
{"off", 2008},
|
|
{"office", 76},
|
|
{"oil", 1022},
|
|
{"on", 2007},
|
|
{"onward", 7},
|
|
{"open", 2004},
|
|
{"opensesame", 3050},
|
|
{"oriental", 72},
|
|
{"out", 11},
|
|
{"outdoors", 32},
|
|
{"outside", 11},
|
|
{"over", 41},
|
|
{"oyster", 1015},
|
|
{"passage", 23},
|
|
{"pause", 2030},
|
|
{"pearl", 1061},
|
|
{"persian", 1062},
|
|
{"peruse", 2027},
|
|
{"pillow", 1010},
|
|
{"pirate", 1030},
|
|
{"pit", 31},
|
|
{"placate", 2010},
|
|
{"plant", 1024},
|
|
{"plant", 1025},
|
|
{"platinum", 1060},
|
|
{"plover", 71},
|
|
{"plugh", 65},
|
|
{"pocus", 3050},
|
|
{"pottery", 1058},
|
|
{"pour", 2013},
|
|
{"proceed", 2011},
|
|
{"pyramid", 1060},
|
|
{"quit", 2018},
|
|
{"rations", 1019},
|
|
{"read", 2027},
|
|
{"release", 2002},
|
|
{"reservoir", 75},
|
|
{"retreat", 8},
|
|
{"return", 8},
|
|
{"right", 37},
|
|
{"road", 2},
|
|
{"rock", 15},
|
|
{"rod", 1005},
|
|
{"rod", 1006},
|
|
{"room", 59},
|
|
{"rub", 2016},
|
|
{"rug", 1062},
|
|
{"run", 2011},
|
|
{"s", 46},
|
|
{"save", 2030},
|
|
{"say", 2003},
|
|
{"score", 2024},
|
|
{"se", 48},
|
|
{"secret", 66},
|
|
{"sesame", 3050},
|
|
{"shadow", 1027},
|
|
{"shake", 2009},
|
|
{"shard", 1058},
|
|
{"shatter", 2028},
|
|
{"shazam", 3050},
|
|
{"shell", 74},
|
|
{"shit", 3079},
|
|
{"silver", 1052},
|
|
{"sing", 2003},
|
|
{"slab", 61},
|
|
{"slit", 60},
|
|
{"smash", 2028},
|
|
{"snake", 1011},
|
|
{"south", 46},
|
|
{"spelunker", 1016},
|
|
{"spice", 1063},
|
|
{"spices", 1063},
|
|
{"stairs", 10},
|
|
{"stalactite", 1026},
|
|
{"steal", 2001},
|
|
{"steps", 1007},
|
|
{"steps", 34},
|
|
{"stop", 3139},
|
|
{"stream", 14},
|
|
{"strike", 2012},
|
|
{"surface", 20},
|
|
{"suspend", 2030},
|
|
{"sw", 49},
|
|
{"swim", 3147},
|
|
{"swing", 2009},
|
|
{"tablet", 1013},
|
|
{"take", 2001},
|
|
{"tame", 2010},
|
|
{"throw", 2017},
|
|
{"toss", 2017},
|
|
{"tote", 2001},
|
|
{"touch", 57},
|
|
{"travel", 2011},
|
|
{"treasure", 1055},
|
|
{"tree", 3064},
|
|
{"trees", 3064},
|
|
{"trident", 1057},
|
|
{"troll", 1033},
|
|
{"troll", 1034},
|
|
{"tunnel", 23},
|
|
{"turn", 2011},
|
|
{"u", 29},
|
|
{"unlock", 2004},
|
|
{"up", 29},
|
|
{"upstream", 4},
|
|
{"upward", 29},
|
|
{"utter", 2003},
|
|
{"valley", 9},
|
|
{"vase", 1058},
|
|
{"velvet", 1010},
|
|
{"vending", 1038},
|
|
{"view", 28},
|
|
{"volcano", 1037},
|
|
{"w", 44},
|
|
{"wake", 2029},
|
|
{"walk", 2011},
|
|
{"wall", 53},
|
|
{"water", 1021},
|
|
{"wave", 2009},
|
|
{"west", 44},
|
|
{"xyzzy", 62},
|
|
{"y2", 55}
|
|
};
|
|
|
|
# binary search
|
|
sub binary(w: [uint8], wctable: [wac], maxwc: uint16): (ret: int16) is
|
|
var lo: uint16;
|
|
var mid: uint16;
|
|
var hi: uint16;
|
|
var check: int8;
|
|
var pwc: [wac];
|
|
|
|
lo := 0;
|
|
hi := maxwc - 1;
|
|
while lo <= hi loop
|
|
mid := (lo + hi) / 2;
|
|
pwc := wctable + 4 * mid;
|
|
check := strcmp(w, [pwc].aword);
|
|
|
|
if check == -1 then
|
|
hi := mid - 1;
|
|
elseif check == 1 then
|
|
lo := mid + 1;
|
|
else
|
|
ret := mid as int16;
|
|
return;
|
|
end if;
|
|
end loop;
|
|
ret := -1;
|
|
end sub;
|
|
|
|
# look-up vocabulary word in lex-ordered table. words may have
|
|
# two entries with different codes. if minimum acceptable value
|
|
# = 0, then return minimum of different codes. last word CANNOT
|
|
# have two entries(due to binary sort).
|
|
# word is the word to look up.
|
|
# val is the minimum acceptable value,
|
|
# if != 0 return %1000
|
|
sub vocab(word: [uint8], val: uint16): (ret: int16) @extern("vocab") is
|
|
var v1: int16;
|
|
var v2: int16;
|
|
|
|
v1 := binary(word, &wc[0], MAXWC);
|
|
|
|
if v1 >= 0 then
|
|
v2 := binary(word, &wc[0], MAXWC-1);
|
|
if v2 < 0 then
|
|
v2 := v1;
|
|
end if;
|
|
if val == 0 then
|
|
if wc[v1 as uint16].acode < wc[v2 as uint16].acode then
|
|
ret := wc[v1 as uint16].acode as int16;
|
|
else
|
|
ret := wc[v2 as uint16].acode as int16;
|
|
end if;
|
|
else
|
|
if val <= wc[v1 as uint16].acode then
|
|
ret := (wc[v1 as uint16].acode % 1000) as int16;
|
|
elseif val <= wc[v2 as uint16].acode then
|
|
ret := (wc[v2 as uint16].acode % 1000) as int16;
|
|
else
|
|
ret := -1;
|
|
end if;
|
|
end if;
|
|
else
|
|
ret := -1;
|
|
end if;
|
|
end sub;
|
|
|
|
sub tolower(ch:uint8): (ret: uint8) @extern("tolower") is
|
|
@asm "cp 'A'";
|
|
@asm "ret c";
|
|
@asm "cp 'Z'+1";
|
|
@asm "ret nc";
|
|
@asm "or 20H";
|
|
@asm "ld (", ret, "),a";
|
|
end sub;
|
|
|
|
# output adventure word list (motion/0xxx & verb/2xxx) only
|
|
# 6 words/line pausing at 20th line until keyboard active
|
|
sub outwords() @extern("outwords") is
|
|
var i: uint16;
|
|
var j: uint16;
|
|
var line: uint16;
|
|
var ch: uint8;
|
|
|
|
j := 0;
|
|
line := 0;
|
|
|
|
i := 0;
|
|
while i < 301 loop
|
|
if (wc[i].acode < 1000) or ((wc[i].acode < 3000) and (wc[i].acode > 1999)) then
|
|
print(wc[i].aword);
|
|
print_char(' ');
|
|
j := j + 1;
|
|
if (j == 6) or (i == 300) then
|
|
j := 0;
|
|
print_nl();
|
|
line := line + 1;
|
|
if line == 20 then
|
|
line := 0;
|
|
print("\nHit any key to continue...");
|
|
ch := get_char();
|
|
end if;
|
|
end if;
|
|
end if;
|
|
i := i + 1;
|
|
end loop;
|
|
end sub;
|
|
|
|
# Routine true x% of the time.
|
|
sub pct(x: uint16): (ret: uint8) @extern("pct") is
|
|
var v: uint16;
|
|
|
|
@asm "call _xrnd";
|
|
@asm "ld (", v, "),hl";
|
|
|
|
if v % 100 < x then
|
|
ret := 1;
|
|
else
|
|
ret := 0;
|
|
end if;
|
|
end sub;
|
|
|
|
# Routine to request a yes or no answer to a question.
|
|
sub yes(msg1: uint8, msg2: uint8, msg3: uint8): (ret: uint8) @extern("yes") is
|
|
var answer: uint8[80];
|
|
var n: uint8;
|
|
var ch: uint8;
|
|
|
|
if msg1 > 0 then
|
|
rspeak(msg1);
|
|
end if;
|
|
print_char('>');
|
|
get_line(&answer[0]);
|
|
if answer[0] == 'n' or answer[0] == 'N' then
|
|
if msg3 == 1 then
|
|
rspeak(msg3);
|
|
end if;
|
|
ret := 0;
|
|
end if;
|
|
if msg2 == 1 then
|
|
rspeak(msg2);
|
|
end if;
|
|
ret := 1;
|
|
end sub;
|
|
|
|
# Routine to analyze a word.
|
|
sub analyze(word: [uint8]): (valid: uint8, type: int16, value: int16) @extern("analyze") is
|
|
var wordval: int16;
|
|
var msg: uint8;
|
|
var v: uint16;
|
|
|
|
@asm "call _xrnd";
|
|
@asm "ld (", v, "),hl";
|
|
|
|
# make sure I understand
|
|
wordval := vocab(word, 0);
|
|
|
|
if wordval == -1 then
|
|
case (v % 3) is
|
|
when 0:
|
|
msg := 60;
|
|
when 1:
|
|
msg := 61;
|
|
when else:
|
|
msg := 13;
|
|
end case;
|
|
rspeak(msg);
|
|
valid := 0;
|
|
type := -1;
|
|
value := -1;
|
|
else
|
|
valid := 1;
|
|
type := wordval/1000;
|
|
value := wordval%1000;
|
|
end if;
|
|
end sub;
|
|
|
|
# Routine to destroy an object
|
|
sub dstroy(obj: uint16) @extern("dstroy") is
|
|
move(obj, 0);
|
|
end sub;
|
|
|
|
# Juggle an object, currently a no-op
|
|
sub juggle(loc: uint16) @extern("juggle") is
|
|
end sub;
|
|
|
|
# routine to move an object and return a
|
|
# value used to set the negated prop values
|
|
# for the repository.
|
|
sub put(obj: uint16, where: int16, pval: int16): (ret: int16) @extern("put") is
|
|
move(obj, where);
|
|
ret := -pval-1;
|
|
end sub;
|
|
|
|
const WATER := 21;
|
|
const OIL := 22;
|
|
|
|
# Convert 0 to WATER
|
|
# 1 to nothing
|
|
# 2 to OIL
|
|
sub liq2(pbottle: uint16): (ret: uint16) @extern("liq2") is
|
|
ret := (1 - pbottle) * WATER + (pbottle >> 1) * (WATER + OIL);
|
|
end sub;
|
|
|
|
record trav is
|
|
tdest: int16;
|
|
tverb: int16;
|
|
tcond: int16;
|
|
end record;
|
|
const MAXTRAV := 16+1;
|
|
|
|
# Routine to copy a travel array
|
|
sub copytrv(trav1: [trav], trav2: [trav]) @extern("copytrv") is
|
|
var i: uint8;
|
|
|
|
i := 0;
|
|
while i < MAXTRAV loop
|
|
[trav2].tdest := [trav1].tdest;
|
|
[trav2].tverb := [trav1].tverb;
|
|
[trav2].tcond := [trav1].tcond;
|
|
trav1 := @next trav1;
|
|
trav2 := @next trav2;
|
|
i := i + 1;
|
|
end loop;
|
|
end sub;
|
|
|