Increase MAX_STATIC_DATA
[bazic.git] / script.h
1 array about_script -->
2         "About baZic"
3         "cls"
4         "print:print:print"
5         "print ~baZic is a downright scary implementation of ~;"
6         "print ~Basic for the Z-machine. It features proper dynamic ~;"
7         "print ~memory allocation, mark-sweep garbage collection, ~;"
8         "print ~fully tokenised program storage, a built-in program ~;"
9         "print ~editor (cough, cough) and is almost entirely useless. ~;"
10         "print ~It is complete enough to play Hunt the Wumpus on, and ~;"
11         "print ~a copy is provided.~"
12         "print"
13         "print ~The language is not complete. I gave up after a certain ~;"
14         "print ~point when I realised that Basic is so crappy a language ~;"
15         "print ~that it's not fun to implement, just annoying. I am now ~;"
16         "print ~even more impressed with the authors of things like 8kB ~;"
17         "print ~Microsoft Basic and BBC Basic; impressive work.~"
18         "print"
19         "print ~The main lacks to baZic are string operations, proper arrays, and ~;"
20         "print ~subroutines. The bulk of the string code is in there --- the ~;"
21         "print ~scary garbage collector --- but I haven't done the string ~;"
22         "print ~operators themselves. Arrays are sort of implemented, but they're ~;"
23         "print ~done by munging the variable name with the index. (See the Wumpus ~;"
24         "print ~program for an example.) Subroutines just haven't been done.~"
25         "print"
26         "print ~If you're interested in the innards of the program, you can do ~;"
27         "print ~'list -1' to list the stored Basic program with byte-code, or ~;"
28         "print ~'list -2' to view the variables in memory. If you do this while ~;"
29         "print ~an array is in use, odd things will happen.~"
30         "print"
31         "print ~baZic is licensed under the MIT public license. For more information, contact ~;"
32         "print ~dg@@64cowlark.com.~"
33         "print:print"
34         0;
35         
36 array higherlower_script -->
37         "Higher / Lower"
38         "new"
39         "10print ~Higher, Lower~"
40         "15print"
41         "20target = rnd(100)"
42         "30tries = 1"
43         "40input ~What is your guess? ~; guess"
44         "50guess = val(guess)"
45         "60if guess < target then print ~Too low!~"
46         "70if guess > target then print ~Too high!~"
47         "80if guess = target then goto 110"
48         "90tries = tries + 1"
49         "100goto 40"
50         "110print ~You got it!~"
51         "120print ~In only~, tries, ~tries, too.~"
52         0;
53
54 array wumpus_script -->
55         "Hunt the Wumpus"
56         "new"
57         "10cls"
58         "20print ~Hunt the Wumpus --- loading data~"
59         "30cave1(0)=1:cave2(0)=4:cave3(0)=7"
60         "40cave1(1)=0:cave2(1)=2:cave3(1)=9"
61         "50cave1(2)=1:cave2(2)=3:cave3(2)=11"
62         "60cave1(3)=2:cave2(3)=4:cave3(3)=13"
63         "70cave1(4)=0:cave2(4)=3:cave3(4)=5"
64         "80cave1(5)=4:cave2(5)=6:cave3(5)=14"
65         "90cave1(6)=5:cave2(6)=7:cave3(6)=16"
66         "100cave1(7)=0:cave2(7)=6:cave3(7)=8"
67         "110cave1(8)=7:cave2(8)=9:cave3(8)=17"
68         "120cave1(9)=1:cave2(9)=8:cave3(9)=10"
69         "130cave1(10)=9:cave2(10)=11:cave3(10)=18"
70         "140cave1(11)=2:cave2(11)=10:cave3(11)=12"
71         "150cave1(12)=11:cave2(12)=13:cave3(12)=19"
72         "160cave1(13)=3:cave2(13)=12:cave3(13)=14"
73         "170cave1(14)=5:cave2(14)=13:cave3(14)=15"
74         "180cave1(15)=14:cave2(15)=16:cave3(15)=19"
75         "190cave1(16)=6:cave2(16)=15:cave3(16)=17"
76         "200cave1(17)=8:cave2(17)=16:cave3(17)=18"
77         "210cave1(18)=10:cave2(18)=17:cave3(18)=19"
78         "220cave1(19)=12:cave2(19)=15:cave3(19)=18"
79         "225print:input ~Do you want instructions? (y/n) ~; i$"
80         "226if i$ <> ~y~ then goto 1000"
81         "230cls"
82         "240print ~Welcome to HUNT THE WUMPUS!~"
83         "250print:print ~The wumpus lives in a cave of twenty rooms. ~;"
84         "260print ~Each room has three tunnels leading to other rooms. ~;"
85         "270print ~Two rooms have bottomless pits --- don't fall on. ~;"
86         "280print ~Two more contain Alien Space Bats. Disturb them, ~;"
87         "290print ~and they will whisk you away to some other room. ~;"
88         "300print:print:print ~Naturally, the wumpus is immune to all hazards. ~;"
89         "310print ~Usually, he's asleep: he'll wake up if he hears you ~;"
90         "320print ~shooting an arrow, or if you walk in on him. ~;"
91         "330print ~Once awake, he'll move around most turns (1 in 4 ~;"
92         "340print ~probability). If *he* walks in on *you*, he'll eat yer. ~;"
93         "350print:print:print ~Your only defence is your arrows. These arrows, ~;"
94         "360print ~which contain a Z-machine microcontroller, can be ~;"
95         "370print ~programmed to follow a certain course for up to five ~;"
96         "380print ~rooms. If they can't go where you told them, they'll ~;"
97         "390print ~move randomly. Did I mention they'll kill you, too, ~;"
98         "400print ~if you program them incorrectly? ~;"
99         "410print:print:print ~The wumpus has smelly feet; you can smell him in the ~;"
100         "420print ~next room. The bats rustle, you can hear them; the pits are ~;"
101         "430print ~drafty, and you can feel that.~"
102         "1000print:print ~Placing objects in maze...~"
103         "1010wumpus=rnd(20):player=rnd(20):pit1=rnd(20):pit2=rnd(20)"
104         "1020bat1=rnd(20):bat2=rnd(20)"
105         "1030if wumpus = player then goto 1000"
106         "1040if wumpus = pit1 then goto 1000"
107         "1050if wumpus = pit2 then goto 1000"
108         "1060if wumpus = bat1 then goto 1000"
109         "1070if wumpus = bat2 then goto 1000"
110         "1080if player = pit1 then goto 1000"
111         "1090if player = pit2 then goto 1000"
112         "1100if player = bat1 then goto 1000"
113         "1110if player = bat2 then goto 1000"
114         "1120if pit1 = pit2 then goto 1000"
115         "1130if pit1 = bat1 then goto 1000"
116         "1140if pit1 = bat2 then goto 1000"
117         "1150if pit2 = bat1 then goto 1000"
118         "1160if pit2 = bat2 then goto 1000"
119         "1170if bat1 = bat2 then goto 1000"
120         "1180awake=0"
121         "2000print"
122         "2010print ~You are in room number ~; player; ~. Exits lead off to rooms ~;"
123         "2020print cave1(player); ~, ~; cave2(player); ~ and ~; cave3(player); ~. ~"
124         "2030if cave1(player) = wumpus then goto 2070"
125         "2040if cave2(player) = wumpus then goto 2070"
126         "2050if cave3(player) = wumpus then goto 2070"
127         "2060goto 2080"
128         "2070print ~You can smell the wumpus!~"
129         "2080if (cave1(player) = pit1) or (cave1(player) = pit2) then goto 2120"
130         "2090if (cave2(player) = pit1) or (cave2(player) = pit2) then goto 2120"
131         "2100if (cave3(player) = pit1) or (cave3(player) = pit2) then goto 2120"
132         "2110goto 2121"
133         "2120print ~You feel a draught!~"
134         "2121if (cave1(player) = bat1) or (cave1(player) = bat2) then goto 2125"
135         "2122if (cave2(player) = bat1) or (cave2(player) = bat2) then goto 2125"
136         "2123if (cave3(player) = bat1) or (cave3(player) = bat2) then goto 2125"
137         "2124goto 2130"
138         "2125print ~You hear rustling!~"
139         "2130input ~Which room do you want to go to (or -1 to fire an arrow)? ~; i$"
140         "2135dest = val(i$)"
141         "2140if dest = -1 then goto 3000"
142         "2150if (cave1(player) = dest) or (cave2(player) = dest) or (cave3(player) = dest) then goto 2200"
143         "2160print:print ~You can't go that way.~"
144         "2170goto 2130"
145         "2200print"
146         "2210if dest=wumpus then goto 2600"
147         "2220if (dest=pit1) or (dest=pit2) then print ~*** AAAAAAaaaaaah ***~:print:print ~You have fallen down a pit.~:goto 5000"
148         "2230if (dest=bat1) or (dest=bat2) then print ~You have been abducted by alien space bats.~:dest=rnd(20)"
149         "2240player=dest"
150         "2500if awake=0 then goto 2000"
151         "2510i = rnd(4)"
152         "2520if i<>0 then goto 2000"
153         "2530print ~You hear the patter of tiny feet as the wumpus moves.~"
154         "2540i = rnd(3)"
155         "2550if i=0 then wumpus = cave1(wumpus)"
156         "2560if i=1 then wumpus = cave2(wumpus)"
157         "2570if i=2 then wumpus = cave3(wumpus)"
158         "2580goto 2000"
159         "2600player=dest"
160         "2210if awake=1 then print ~*** CRUNCH ***~:print:print ~You have been eaten by the wumpus.~:goto 5000"
161         "2620awake=1"
162         "2630print ~The wumpus is here! Asleep, though it won't stay like that for long.~"
163         "2640goto 2000"
164         "3000print"
165         "3005arrow=player"
166         "3010for i=1 to 5"
167         "3020input ~Please enter the next room for the arrow to go to: ~; i$"
168         "3025j = val(i$)"
169         "3030if (j = cave1(arrow)) or (j = cave2(arrow)) or (j = cave3(arrow)) then arrow=j:goto 3071"
170         "3040j = rnd(3)"
171         "3050if j = 0 then arrow = cave1(arrow)"
172         "3060if j = 1 then arrow = cave2(arrow)"
173         "3070if j = 2 then arrow = cave3(arrow)"
174         "3071if j = wumpus then print:print ~You hear a distant scream... the wumpus is dead! Now you just have to deal with the RSPCA lawyers.~:goto 5010"
175         "3080if j = player then print:print ~You have just been impaled on one of your own arrows.~:goto 5000"
176         "3090next"
177         "3095awake=1"
178         "3100goto 2500"
179         "5000print:input ~You have died. Play again? (y/n) ~; i$:goto 5020"
180         "5010print:input ~You have won. Play again? (y/n) ~; i$"
181         "5020if i$=~y~ then goto 1000"
182         "5030print:print ~Bye bye!~"
183         0;
184
185 array scripts -->
186         about_script
187         higherlower_script
188         wumpus_script
189         0;
190 constant NUM_SCRIPTS 3;
191
192 global script_id = 0;
193 global script_lineno = 0;
194
195 ! List the available scripts.
196
197 [ script_list  i;
198         print "Available scripts:^";
199         i = 0;
200         while (scripts-->i)
201         {
202                 print "  ", i, ": ", (string) scripts-->i-->0, "^";
203                 i++;
204         }
205         return ESTATE_NORMAL;
206 ];
207
208 ! Invoke a script.
209
210 [ script_invoke i;
211         if ((i < 0) || (i >= NUM_SCRIPTS))
212         {
213                 error("Script ID out of range");
214                 return ESTATE_ERROR;
215         }
216
217         print "Invoking script ~", (string) scripts-->i-->0, "~...^";
218         script_id = i;
219         script_lineno = 1;
220
221         do {
222                 store_init(heap, heap+HEAP_SIZE);
223                 do {
224                         i = command_loop(script_reader);
225                 } until ((i == ESTATE_QUIT) || (i == ESTATE_NEW));
226         } until (i == ESTATE_QUIT);
227
228         print "Script finished.^";
229         return ESTATE_NORMAL;
230 ];
231
232 ! Read in a command from a script into the parse buffer.
233
234 [ script_reader  buf in l;
235         buf = mem_alloc(255);
236         if (buf == 0)
237                 return -2;
238
239         ! Get the compressed data.
240
241         l = scripts-->script_id-->script_lineno;
242         if (l == 0)
243                 l = "quit";
244         else
245                 script_lineno++;
246
247         ! Decompress it into the temporary buffer. 
248
249         buf-->0 = 255;
250         @output_stream 3 buf;
251         print (string) l;
252         @output_stream -3;
253
254         ! Ensure the string is zero-terminated.
255
256         in = buf+2;
257         in->(buf-->0) = 0;
258
259         ! Tokenise the stream.
260
261         in = tokenise_stream(in, parsebuffer);
262
263         mem_free(buf);
264         return in;
265 ];
266