hadeishi@husc4.harvard.edu (mitsuharu hadeishi) (10/14/86)
Here's the program, in ASCII format. Run AmigaBasic, type "clear,170000" or so, and load the program. When you save it, save it with 'save "AmigaVenture",b'. The ",b" saves it in binary encoded format which loads much more quickly than the ASCII version. Do NOT use the Save command from the menu, because it will save it in the same format in which it was loaded (i.e., ASCII). After you save it once in binary form, it will always load and save in binary form. A few hints: reposition the LIST window so it takes up the full width of the screen and leaves about 4 lines or so of the RUN window underneath. You can use the RUN window to get to various sections of the program with the "list label-" command. The Quick Reference Guide contains a list of important program labels; with this method you can navigate around the program rapidly. Also: NEVER use Trace (it crashes). NEVER close the AmigaBasic window in the middle of a save (it stops the save halfway through.) ALWAYS make backup copies of your work. AmigaBasic is fairly reliable if you avoid these pitfalls. Enjoy! (Note: AmigaBasic runs under V1.1 or V1.2 beta 7 and above. AmigaBasic will NOT run under V1.2 beta 1-6.) This is NOT a shell archive. Just cut and run. -------[ cut cut cut cut cut cut cut cut cut cut cut cut here ]--------- DEFINT a-z game$ = "AmigaVenture 1.17" ' Version number of game dataformat$ = "AmigaVenture 1.1X" ' Version number for load/save only ' ' AmigaVenture Kernal 1.17 ' ' Core routines for writing an Adventure of your own ' In Microsoft AmigaBasic ' ' by Mitsu Hadeishi 7/15/86 ' 1460 W. 182nd Street ' Gardena CA 90248 ' ' Written for the Winner's Circle Amiga User's Group ' '--------------------------------------------------------------------------- ' Permission is given to freely distribute this code in full or in part ' provided this notice is copied IN FULL. ' ' AmigaVenture Kernal Copyright (c) 1986 by Mitsu Hadeishi ' This code may not be used in part or in full in any commercial ' product, nor may this code in part or in full be sold intentionally ' to make a profit, without an explicit written agreement with the author. '--------------------------------------------------------------------------- ' ' Please write to me if you have plans to distribute a significantly ' modified version of the *kernal*. ' Feel free to distribute *adventures* written with this kernal without ' contacting me, but please! give credit where credit is due. ' ' Updates and enhancements may be obtained from: ' ' Mitsu Hadeishi ' hadeishi@husc4.UUCP ' or hadeishi%husc4.harvard.edu ' 3 Sacramento Street ' Cambridge, MA 02138 ' ' All variables are, unless otherwise indicated, short integers. ' GOTO Initialize Messages: ' Message subroutines/subprograms Cannot: IF n$(1) = "" THEN PRINT"You can't "v$" "nn$(0)"! ELSE PRINT"You can't "v$" "nn$(0)" "p$" "nn$(1)"! END IF RETURN SUB CantSee(nn$) STATIC PRINT"I don't see what you're referring to. END SUB SUB DontHave(nn$) STATIC PRINT"You don't have "nn$"! END SUB SUB CantGetAt(nn$) STATIC PRINT"You can't get at "nn$"!" END SUB Absurd: ON RND(1)*2+1 GOTO Absurd1,Absurd2 Absurd1: PRINT"Don't be absurd.":RETURN Absurd2: PRINT"Don't talk nonsense.":RETURN Mystery: PRINT"I can't see what you're referring to. RETURN ' Prints a list of alternatives for the player to select from ' If all the choices are positionally referenced, then "that" is ' returned as 1 SUB AskAmbig(choice(2),num,that) STATIC SHARED adj$(),par(),rel(),prepn$() PRINT"Which do you mean:" num = ABS(num) FOR i = 1 TO num IF i = num THEN PRINT"or "; c=choice(i,0) CALL NameNoun(c,n$,nn$) IF c > 0 AND adj$(c) <> "" THEN PRINT"the "adj$(c)" "n$; that=-1 ELSE PRINT nn$; END IF IF c > 0 AND adj$(c) = "" AND par(c) <> 0 THEN PRINT" that's "prepn$(rel(c)+1)" "; IF that <> -1 THEN that=1 CALL NameNoun(par(c),n$,nn$) PRINT nn$; END IF IF i = num THEN PRINT"?" ELSE PRINT", "; NEXT i IF that = -1 THEN that=0 END SUB Calc: ' ' Calculation subprograms follow ' ' Visible() determines whether noun code 'code' is visible or not. ' If type is 1, then only checks to see if visible on the player, ' if 2, then only checks to see if visible in room (but not on player). ' Returns truth value in vis SUB Visible(code,vis,type) STATIC SHARED par(),rel(),opaque(),closed(),lo(),l a = type obj = code IF obj < 0 THEN vis=1:EXIT SUB vis = 0 IF a = 1 THEN IF lo(obj) <> 1 THEN EXIT SUB IF a = 2 THEN IF lo(obj) <> l THEN EXIT SUB IF a = 0 THEN IF lo(obj) <> 1 AND lo(obj) <> l THEN EXIT SUB vis = -1 WHILE (vis = -1) IF par(obj) < 2 THEN vis = 1 ELSEIF (opaque(rel(obj),par(obj)) = 1) AND (rel(obj) = 0 AND closed(par(obj)) <> 0) THEN vis = 0 ELSE obj = par(obj) END IF WEND END SUB ' Avail() determines whether noun code 'code' is available or not. ' If the object is available, but you couldn't get it out from where ' it is, returns -1 ' See Visible, above, for explanation of 'type' ' Returns truth value in ava SUB Avail(code,ava,type) STATIC SHARED par(),rel(),closed(),lo(),l,opening(),size(),holdwater() a = type IF a = 0 THEN a = 3 obj = code IF obj < 0 THEN ava=1:EXIT SUB ava = 0 IF a = 1 THEN IF lo(obj) <> 1 THEN EXIT SUB IF a = 2 THEN IF lo(obj) <> l THEN EXIT SUB IF a = 0 THEN IF lo(obj) <> 1 AND lo(obj) <> l THEN EXIT SUB siz = size(code):IF holdwater(code) = 2 THEN siz = 0 WHILE (1) IF par(obj)<2 THEN IF ava <> -1 THEN ava = 1 EXIT SUB ELSEIF closed(par(obj)) <> 0 AND (rel(obj) < 2) THEN ava = 0 EXIT SUB ELSEIF opening(rel(obj),par(obj)) < siz THEN ava = -1 END IF obj = par(obj) WEND END SUB '*** CheckLight() should be modified for your own program's way '*** of casting light and shadow on the situation. Returns 0 '*** for total darkness, 1 for lamp light, 2 for moonlight/nighttime, '*** 3 for twilight, 4 for daylight SUB CheckLight(light) STATIC SHARED l,lamp,lampon,day,flag(),Llight(),Lon() light = 0 IF Lon(l) THEN light = Lon(l):EXIT SUB IF Llight(l) = 1 AND flag(day) <> 0 THEN light = flag(day):EXIT SUB CALL Visible(lamp,vis,0) IF (flag(lampon) = 1) AND (vis = 1) THEN light = 1 END SUB ' NameNoun() returns appropriate strings in n$ and nn$, where ' n$ is the class word for the noun code, and nn$ is "the " + n$, ' unless the noun is abstract (negative code) in which case nn$ = n$ SUB NameNoun(n,n$,nn$) STATIC SHARED word$(),abstract$() IF n > 0 THEN n$ = word$(n) nn$ = "the " + n$ ELSE n$ = abstract$(-n) nn$ = n$ END IF END SUB Calc2: ' Places in array() siblings starting with object obj and children ' which are underneath all objects in the list. ' Starts the list at array(count + 1) (this allows you to call this ' routine multiple times and list several lists) This routine ' is used by the interpreter to list objects SUB ListSib(obj,array(2),count(1),nn) STATIC SHARED cc(),opaque(),right(),first() ll = 1 cc(1) = obj cc(0) = 0 ListSib1: WHILE (ll > 0) WHILE (cc(ll)) count(nn) = count(nn) + 1 array(nn,count(nn)) = cc(ll) IF first(3,cc(ll)) <> 0 AND opaque(3,cc(ll)) = 0 THEN ll = ll + 1 cc(ll) = first(3,cc(ll-1)) GOTO ListSib1 END IF cc(ll) = right(cc(ll)) WEND ll = ll - 1 cc(ll) = right(cc(ll)) WEND END SUB ' Determines if c1 is a descendant of c2 (inside, on, etc.) ' Returns truth value in ins SUB Inside(c1,c2,ins,rel) STATIC SHARED par() ins = 0 c = c1 WHILE (c) IF par(c) = c2 THEN ins = 1:rel = rel(c):EXIT SUB c = par(c) WEND END SUB ' EvalCond evaluates a condition on the flag() array; ret is the truth ' value returned. The condition tested depends on the value of b; ' it is whether or not flag(a) < c, flag(a) = c, or flag(a) > c, ' depending on whether b = -1, 0, or 1, respectively. This function ' is used to evaluate the conditionals in the map and the descriptions. ' (see Go:, Look:, and map:). SUB EvalCond(a,b,c,ret) STATIC SHARED flag(),random IF a = random THEN CALL RollDice IF b = 0 THEN ret = (flag(a) = c) ELSEIF b = 1 THEN ret = (flag(a) > c) ELSE ret = (flag(a) < c) END IF END SUB SUB RollDice STATIC SHARED flag(),random flag(random) = RND(1) * 100 END SUB ' List all bottles in the player's possession ' Starts at array(0), returns count in a SUB ListBottles(array(1),a) STATIC SHARED bottles(),lo(),nbot a = 0 FOR i = 0 TO nbot IF lo(bottles(i)) = 1 THEN CALL Avail(bottles(i),ava,1) IF ava THEN array(a) = bottles(i) a = a + 1 END IF END IF NEXT END SUB Lists: ' The following subprograms handle the linked lists of objects, ' parents, children, siblings ' Contents() prints a list of obj and all siblings and children ' If sing = 1, then just prints what's in it, ' not siblings SUB Contents(obj,indent,sing) STATIC SHARED cc(),mc(),mrel,pre$(),word$(),closed(),opaque(),right(),worn() SHARED folded(),fold$(),first() ll = 1 mc(1) = 0 cc(1) = obj WHILE (ll > 0) WHILE (cc(ll) <> 0) Contents1: c = cc(ll) mode = mc(ll) IF mode = 0 AND (sing = 0 OR ll > 1) AND c > 1 THEN PRINT TAB(indent);pre$(c)" "word$(c); IF folded(c) THEN PRINT" ("fold$(folded(c))")" ELSE PRINT END IF END IF IF first(mode,c) <> 0 AND (opaque(mode,c) = 0 OR (mode = 0 AND closed(c) = 0)) THEN nn$ = "the " + word$(c) PRINT TAB(indent); IF sing = 2 THEN ' *** Don't print anything ELSEIF mode = 0 THEN IF c = 1 THEN PRINT"You are wearing:" ELSE IF sing THEN PRINT FNcap$(nn$); ELSE PRINT nn$; PRINT" contains:" END IF ELSEIF mode = 1 THEN IF c = 1 THEN PRINT"You are carrying:" ELSE IF sing THEN PRINT"W"; ELSE PRINT"w"; PRINT"rapped by "nn$", you see:" END IF ELSEIF mode = 2 THEN IF sing THEN PRINT"L"; ELSE PRINT"l"; PRINT"ying on "nn$", you see:" ELSEIF mode = 3 THEN IF sing THEN PRINT"U"; ELSE PRINT"u"; PRINT"nder "nn$", you see:" END IF ll = ll + 1 cc(ll) = first(mode,c) mc(ll) = 0 indent = indent + 3 GOTO Contents1 END IF mc(ll) = mc(ll) + 1 IF mc(ll) > mrel THEN IF sing THEN IF ll = 1 THEN EXIT SUB cc(ll) = right(c) mc(ll) = 0 END IF WEND ll = ll - 1 indent = indent - 3 mc(ll) = mc(ll) + 1 IF mc(ll) > mrel THEN IF sing THEN IF ll = 1 THEN EXIT SUB cc(ll) = right(cc(ll)) mc(ll) = 0 END IF WEND END SUB ' Removes object from list and places it in limbo SUB Remove(obj) STATIC SHARED par(),right(),left(),rel(),first(),last() SHARED Lfirst(),Llast(),lo(),totw(),totb(),bulk(),size() ri = right(obj) le = left(obj) right(le) = ri left(ri) = le IF par(obj) = 0 THEN lc = lo(obj) IF Llast(lc) = obj THEN Llast(lc) = le IF Lfirst(lc) = obj THEN Lfirst(lc) = ri ELSE pa = par(obj) IF last(rel(obj),pa) = obj THEN last(rel(obj),pa) = le IF first(rel(obj),pa) = obj THEN first(rel(obj),pa) = ri c = obj w = totw(c):b = totb(c) IF rel(c) = 2 THEN bulk(rel(c),pa) = bulk(rel(c),pa) - size(c) WHILE (pa) IF rel(c) < 3 THEN totw(pa) = totw(pa) - w ELSE w = 0 IF rel(c) <> 2 THEN bulk(rel(c),pa) = bulk(rel(c),pa) - b IF rel(c) = 1 OR rel(c) = 2 THEN totb(pa) = totb(pa) - b ELSE b = 0 c = par(c) pa = par(c) WEND END IF par(obj) = 0 left(obj) = 0 right(obj) = 0 lo(obj) = 0 rel(obj) = 0 END SUB ' Inserts object into relation to object "into". If into is negative ' or zero, the routine will insert it into the room number -into. ' The relation is determined by "mode". This is 0 for in, 1 for wrapped, ' 2 for on top of, and 3 for underneath (like under a table, NOT like ' under something stacked on top of the object.) ' NOTE: this routine assumes that the object has already been "Removed" ' (see above.) The routine does not do any checking for weight, capacity, ' or mode violations. This must be done by the calling routine, using the ' totw() and totb() arrays, which are updated by this routine. SUB Insert(obj,into,mode) STATIC SHARED par(),rel(),mrel,right(),left(),first(),last() SHARED Lfirst(),Llast(),lo(),totw(),totb(),bulk(),size() IF mode < 0 OR mode > mrel THEN EXIT SUB right(obj) = 0 IF into > 0 THEN par(obj) = into IF first(mode,into) = 0 THEN first(mode,into) = obj left(obj) = last(mode,into) right(last(mode,into)) = obj last(mode,into) = obj rel(obj) = mode pa = into c = obj w = totw(c):b = totb(c) IF rel(c) = 2 THEN bulk(rel(c),pa) = bulk(rel(c),pa) + size(c) WHILE (pa) IF rel(c) < 3 THEN totw(pa) = totw(pa) + w ELSE w = 0 IF rel(c) <> 2 THEN bulk(rel(c),pa) = bulk(rel(c),pa) + b IF rel(c) = 1 OR rel(c) = 2 THEN totb(pa) = totb(pa) + b ELSE b = 0 c = par(c) pa = par(c) WEND CALL Setloc(obj,lo(into),1) ELSE into = -into par(obj) = 0 rel(obj) = 0 IF Lfirst(into) = 0 THEN Lfirst(into) = obj left(obj) = Llast(into) right(Llast(into)) = obj Llast(into) = obj CALL Setloc(obj,into,1) END IF END SUB ' Sets the location of obj and all its descendants recursively ' If sing is 0, then all siblings are set to location l as well, ' otherwise, only obj is set SUB Setloc(obj,l,sing) STATIC SHARED mrel,cc(),mc(),first(),right(),lo() lo(obj) = l ll = 1 mc(1) = 0 cc(1) = obj WHILE (ll > 0) WHILE (cc(ll) <> 0) Setloc1: c = cc(ll) mode = mc(ll) lo(c) = l IF (first(mode,c) <> 0) THEN ll = ll + 1 cc(ll) = first(mode,c) GOTO Setloc1 END IF mc(ll) = mc(ll) + 1 IF mc(ll) > mrel THEN IF sing THEN IF ll = 1 THEN EXIT SUB cc(ll) = right(cc(ll)) mc(ll) = 0 END IF WEND ll = ll - 1 mc(ll) = mc(ll) + 1 IF mc(ll) > mrel THEN IF sing THEN IF ll = 1 THEN EXIT SUB cc(ll) = right(cc(ll)) mc(ll) = 0 END IF WEND END SUB ' Removes the list of objects related to "code" in the relationship ' "mode" (0 - in, 1 - wrapped, 2 - on, 3 - underneath). ' Returns the first object in the list in "head". ' ***WARNING***: ' This routine DOES NOT set the location pointers, to speed up routines ' that set the location pointers themselves. Therefore the list is ' unlinked (it won't show up in a "look" or "examine", etc.) but if you ' ask whether or not the objects are visible or accessibile (with ' Visible() and Avail()) they will still be "there" in the room. ' To send them to limbo, call Setloc(head,0,0) after RemList. SUB RemList(code,mode,head) STATIC SHARED par(),rel(),right(),first(),last(),Lfirst(),Llast() SHARED totw(),totb(),bulk(),size() IF code > 0 THEN head = first(mode,code) first(mode,code) = 0 last(mode,code) = 0 ELSE code = -code head = Lfirst(code) Lfirst(code) = 0 Llast(code) = 0 END IF c = head WHILE (c) pa = par(c) d = c w = totw(c):b = totb(c) IF rel(c) = 2 THEN bulk(rel(c),pa) = bulk(rel(c),pa) - size(c) WHILE (pa) IF rel(c) < 3 THEN totw(pa) = totw(pa) - w ELSE w = 0 IF rel(c) <> 2 THEN bulk(rel(c),pa) = bulk(rel(c),pa) - b IF rel(d) = 1 OR rel(d) = 2 THEN totb(pa) = totb(pa) - b ELSE b = 0 d = par(d) pa = par(d) WEND par(c) = 0 rel(c) = 0 c = right(c) WEND END SUB ' Concat concatenates the list of objects beginning with "head" into ' relationship with "code" in the manner "mode". If code is ' positive, it is an object, if negative, it is a location. ' This routine typically called after RemList. SUB Concat(head,code,mode) STATIC SHARED lo(),par(),rel(),left(),right(),first(),last(),Lfirst(),Llast() SHARED totw(),totb(),bulk(),size() IF head = 0 THEN EXIT SUB into = code IF code <= 0 THEN mode = 0:into = 0 totw = 0:totb = 0 c = head WHILE (c) rel(c) = mode par(c) = into pa = into d = c w = totw(c):b = totb(c) IF rel(c) = 2 THEN bulk(rel(c),pa) = bulk(rel(c),pa) + size(c) WHILE (pa) IF rel(c) < 3 THEN totw(pa) = totw(pa) + w ELSE w = 0 IF rel(c) <> 2 THEN bulk(rel(c),pa) = bulk(rel(c),pa) + b IF rel(d) = 1 OR rel(d) = 2 THEN totb(pa) = totb(pa) + b ELSE b = 0 d = par(d) pa = par(d) WEND tail = c c = right(c) WEND IF code > 0 THEN left(head) = last(mode,code) right(last(mode,code)) = head IF first(mode,code) = 0 THEN first(mode,code) = head last(mode,code) = tail lc = lo(code) ELSE code = -code left(head) = Llast(code) right(Llast(code)) = head IF Lfirst(code) = 0 THEN Lfirst(code) = head Llast(code) = tail lc = code END IF CALL Setloc(head,lc,0) END SUB WaterLists: ' Fill() fills the obj with the specified about of water. Returns ' the actual amount filled in wat. SUB Fill(obj,wat) STATIC SHARED totw(),totb(),bulk(),par(),rel(),cap(),size() IF obj < 0 THEN EXIT SUB IF wat = 0 THEN EXIT SUB c=obj IF cap(0,c)=-1 THEN RETURN 'Infinite capacity (river, lake, etc.) ' Check for overflow/underflow IF wat + bulk(0,c) > cap(0,c) THEN wat = cap(0,c) - bulk(0,c) IF wat < 0 THEN wat = 0:EXIT SUB ELSEIF wat + bulk(0,c) <= 0 THEN wat = -bulk(0,c) CALL Empty(obj) EXIT SUB END IF c = obj IF par(c+1) = 0 THEN ' No current water object inside c totw(c+1) = wat totb(c+1) = wat size(c+1) = wat CALL Insert(c+1,c,0) EXIT SUB ELSE ' Must modify bulk, weight in c totw(c+1) = totw(c+1) + wat totb(c+1) = totw(c+1) + wat size(c+1) = size(c+1) + wat bulk(0,c) = bulk(0,c) + wat WHILE (c) totw(c) = totw(c) + wat IF rel(c) < 3 THEN c = par(c) ELSE c = 0 WEND END IF END SUB ' Empties the water from object "obj". This routine DOES ' check to make sure the object IS a container SUB Empty(obj) STATIC SHARED holdwater(),par(),cap(),size(),totw(),totb() IF obj < 0 THEN EXIT SUB IF cap(0,obj)=-1 THEN RETURN 'Infinite capacity (river, lake, etc.) IF holdwater(obj) <> 1 THEN EXIT SUB IF par(obj+1) = 0 THEN EXIT SUB CALL Remove(obj+1) size(obj+1) = 0 totw(obj+1) = 0 totb(obj+1) = 0 END SUB ' The Tumble routine takes all objects that are stacked on top of ' the object obj and makes them siblings of obj SUB Tumble(obj) STATIC SHARED cc(),c1(),c2(),lo(),par(),first(),right() ll = 1 cc(1) = first(2,obj) IF cc(1) = 0 THEN EXIT SUB tum = 0 c1(tum) = obj PRINT c1(tum) WHILE (ll > 0) WHILE (cc(ll) <> 0) Tumble1: c = cc(ll) IF (first(2,c) <> 0) THEN tum = tum + 1 c1(tum) = c ll = ll + 1 cc(ll) = first(2,c) GOTO Tumble1 END IF cc(ll) = right(cc(ll)) WEND ll = ll - 1 cc(ll) = right(cc(ll)) WEND FOR i = 0 TO tum CALL RemList(c1(i),2,c2(i)) NEXT i lc = par(obj) IF lc = 0 THEN lc = -lo(obj) FOR i = 0 TO tum CALL Concat(c2(i),lc,0) NEXT i END SUB ' ' Interpreter subprograms follow ' Interpreter: ' GetVerb() returns a verb code in v and a verb string in v$, ' and returns cmd$ starting with the first word following the verb phrase SUB GetVerb(cmd$,v,v$) STATIC SHARED verb$() IF cmd$ = "" THEN EXIT SUB cc(3) = -1 FOR i = 2 TO 0 STEP -1 cc(i) = INSTR(cc(i+1)+2,cmd$," ") - 1 NEXT i FOR i = 0 TO 2 '*** Search 3-word, 2-word, then 1-word verb lists IF cc(i) < 0 THEN GetVerb1 c$ = "," + LEFT$(cmd$,cc(i)) + "," c = INSTR(verb$(i),c$) IF c <> 0 THEN vl = i:i = 2 GetVerb1: NEXT i IF c = 0 THEN EXIT SUB ELSE v$ = MID$(c$,2,LEN(c$) - 2) lv = LEN(v$) v = VAL(MID$(verb$(vl),c + lv + 2)) cmd$ = MID$(cmd$,lv + 2) WHILE (MID$(cmd$,1,1) = " ") cmd$ = MID$(cmd$,2) WEND END IF END SUB ' ExNoun() returns an array of noun code choices and a count ' Returns 0 in nch if no noun is found ' Returns -1 if inconsistent nouns are found (like "diamond sandwich", etc.) ' Returns 1 in "that" if a "that" clause is identified ' Note: this routine exits immediately after ambiguity is resolved. ' This routine truncates cmd$ SUB ExNoun(cmd$,choice(2),nch,that) STATIC SHARED mhom,nnoun,noun$,nindex(),nhom(),ncode() ll = 0 ExNoun1: IF cmd$ = "" THEN ExNoun2 c$ = ","+LEFT$(cmd$,INSTR(cmd$," ")-1)+"," c = INSTR(noun$,c$) IF c = 0 THEN ExNoun2 ln = LEN(c$) - 2 i = VAL(MID$(noun$,c + ln + 2)) cmd$ = MID$(cmd$,ln + 2) WHILE (MID$(cmd$,1,1) = " ") cmd$ = MID$(cmd$,2) WEND IF ncode(nindex(i)) = -14 THEN that = 1:GOTO ExNoun2 ' Found "that" IF ncode(nindex(i)) = -15 THEN ' "what's" == "everything that" IF nch THEN nch = -1:EXIT SUB choice(1,0) = -11:nch = 1:that = 1 CALL SkipNoun(cmd$) EXIT SUB END IF IF (nhom(i) = 0) THEN ExNoun1 '*** Null word, get next word IF (nch = 0) THEN '*** Empty context FOR j = 1 TO nhom(i) '*** Ambiguous code = ncode(nindex(i) + j - 1) nch = nch + 1 choice(nch,ll) = ncode(nindex(i) + nch -1) NEXT j ll = 1 - ll GOTO ExNoun1 ELSE '*** Try to resolve ambiguity within old context newnch = 0 FOR j = 1 TO nch FOR k = 1 TO nhom(i) code = ncode(nindex(i)+k-1) IF choice(j,1-ll) = code THEN newnch = newnch + 1 choice(newnch,ll) = code k = mhom END IF NEXT k NEXT j IF newnch = 0 THEN nch = -1:REM inconsistent nouns EXIT SUB END IF nch = newnch ll = 1 - ll GOTO ExNoun1 END IF ExNoun2: IF ll = 0 THEN FOR i = 1 TO nch choice(i,0) = choice(i,1) NEXT i END IF END SUB ' Skip noun (skips nouns without looking at meaning) SUB SkipNoun(cmd$) STATIC SHARED noun$ ll = 0 SkipNoun1: IF cmd$ = "" THEN EXIT SUB c$ = ","+LEFT$(cmd$,INSTR(cmd$," ")-1)+"," c = INSTR(noun$,c$) IF c = 0 THEN EXIT SUB cmd$ = MID$(cmd$,LEN(c$)) WHILE (MID$(cmd$,1,1) = " ") cmd$ = MID$(cmd$,2) WEND GOTO SkipNoun1 END SUB ' GetNoun() uses ExNoun to return all possible noun code choices, ' and tries to resolve the ambiguity by calling ChooseVisible to ' see if the object is in the room or on the player. If this ' fails, then tries using the vtype1 flag, and then the vtype2 ' flag (see ChooseVisible for explanation of vtype.) (vtype1 is ' nounat(verb) and vtype2 is noundef(verb) (see Commands for ' explanation of nounat and noundef.)) ' Returns ch = -1 for inconsistent nouns ' Returns ch = -2 for ambiguity not resolved by visual check ' Returns that = 1 if a "that" clause follows ' See ExNoun() and ChooseVisible() SUB GetNoun(cmd$,choice(2),ch,n,vtype1,vtype2,that) STATIC SHARED c1() z = 0 c1(0) = 0:c1(1) = vtype1:c1(2) = vtype2 IF vtype1 <> c1(z) THEN z = z + 1:c1(z) = vtype1 IF vtype2 <> c1(z) THEN z = z + 1:c1(z) = vtype2 och = ch CALL ExNoun(cmd$,choice(),ch,that) IF that THEN IF ch = och THEN EXIT SUB IF ch = 1 THEN n = choice(1,0) ELSEIF ch = -1 THEN EXIT SUB ELSE '*** Try to resolve ambiguity FOR i = 0 TO z CALL ChooseVisible(choice(),ch,c1(i)) IF ch = 1 THEN 'Found it n = choice(1,0) EXIT SUB ELSEIF ch < -1 AND i = 0 THEN 'Can't see anywhere ch = -2 EXIT SUB ELSEIF ch <= 0 THEN 'Return last step's ambiguity ch = -ch EXIT SUB END IF NEXT i END IF END SUB ' Get preposition SUB GetPrep(cmd$,p) STATIC SHARED prep$,prepn$() WHILE (1) IF cmd$ = "" THEN EXIT SUB c$ = ","+LEFT$(cmd$,INSTR(cmd$," ")-1)+"," c = INSTR(prep$,c$) IF c = 0 THEN EXIT SUB lp = LEN(c$) - 2 p = VAL(MID$(prep$,c + lp + 2)) cmd$ = MID$(cmd$,lp + 2) WHILE (MID$(cmd$,1,1) = " ") cmd$ = MID$(cmd$,2) WEND WEND END SUB ' Routine scans the choice array and returns an array with only ' visible items. Returns the same array with a negative ' nchoice if none of the items are visible. ' If vtype is 1, then only checks to see if object is visible on the ' player, and if 2, then only checks if objects is visible in room, ' but not carried by player. If 0, checks both places. SUB ChooseVisible(choice(2),nchoice,vtype) STATIC SHARED mhom IF nchoice < 2 THEN EXIT SUB newnchoice = 0 FOR i = 1 TO nchoice CALL Visible(choice(i,0),vis,vtype) IF (vis) THEN newnchoice = newnchoice + 1 choice(newnchoice,1) = choice(i,0) END IF NEXT i IF newnchoice = 0 THEN nchoice = -nchoice EXIT SUB ELSE nchoice = newnchoice FOR i = 1 TO nchoice choice(i,0) = choice(i,1) NEXT i END IF END SUB ' Parses the cmd$ string and returns the next preposition and ' noun (used in a sentence like "get the water that's *in the bottle*") ' Returns -1 in tp if player overrided command in an AskAmbig process ' Returns -2 in tp if player makes a fatal grammatical error SUB GetThatClause(cmd$,tp,tn) STATIC SHARED nchoice2() IF tp THEN GetThatClause1 tn = 0:tp = 0 CALL SkipNoun(cmd$) CALL GetPrep(cmd$,tp) GetThatClause1: IF tp < 1 OR tp > 4 THEN EXIT SUB nch = 0:ambig = 0:that = 0 GetThatClause2: CALL GetNoun(cmd$,nchoice2(),nch,tn,0,0,that) IF that THEN PRINT"Your language is too complex for me. Please restate." tp = -2 EXIT SUB END IF IF ambig = 1 AND nch = 0 THEN ' AskAmbig (see below) failed, so cmd$ = amb$ ' assume that the player overrided the old command, and tp = -1 ' return a -1 error flag EXIT SUB ELSE ambig = 0 ' Clear AskAmbig flag END IF IF nch = -1 THEN GOSUB Absurd:tp = -2:EXIT SUB IF nch = -2 THEN GOSUB Mystery:tp = -2:EXIT SUB IF nch > 1 THEN ' Ask player to resolve ambiguity CALL AskAmbig(nchoice2(),nch,that) IF that THEN PRINT"Wait a sec---I'm getting confused. Let's start over from the beginning.":EXIT SUB PRINT:LINE INPUT"> ";amb$:amb$ = amb$ + " ":PRINT cmd$ = amb$ + cmd$:ambig = 1 ' (see above) GOTO GetThatClause2 ' Try to resolve ambiguity END IF END SUB ' Skips a clause of the form preposition-noun SUB SkipThatClause(cmd$) STATIC CALL SkipNoun(cmd$) CALL GetPrep(cmd$,a) CALL SkipNoun(cmd$) END SUB ' Attempts to resolve ambiguity by choosing only those ' items in array(,0) that are related to tn by mode tr ' (i.e., only objects that are "in" the "bottle", "on" the "table", etc.) SUB ResolveThat(array(2),nch,n,tr,tn) STATIC SHARED par(),rel(),mrel IF tn<0 THEN EXIT SUB IF tr<0 OR tr>mrel THEN EXIT SUB nnch = 0 FOR i = 1 TO nch IF array(i,0) < 0 THEN nnch = nnch + 1 array(nnch,1) = array(i,0) ELSEIF par(array(i,0)) = tn AND rel(array(i,0)) = tr THEN nnch = nnch + 1 array(nnch,1) = array(i,0) END IF NEXT nch = nnch FOR i = 1 TO nch array(i,0) = array(i,1) ' Copy array to position zero NEXT IF nch = 1 THEN n = array(1,0) END SUB Initialize: CLS PRINT"Welcome to "game$"! PRINT"One moment please . . ." DEF FNcap$(a$) = CHR$(ASC(a$) AND 223) + MID$(a$,2) z$ = CHR$(8) ' Stack for routines which recursively search object lists ' (Maximum stack depth 30) mdepth = 30 DIM cc(mdepth),mc(mdepth) ' General storage arrays for subroutines mlist = 50 DIM c1(mlist),c2(mlist) ' Read abstract descriptions RESTORE abstract READ mabs 'Maximum # of abstract nouns DIM abstract$(mabs),abstract(mabs) READ a WHILE (a <> 0) READ abstract$(a) READ a IF a > nabs THEN nabs = a WEND ' Read "folded" state RESTORE fold READ mfold DIM fold$(mfold) nfold = 0 READ f$ WHILE (f$ <> "") nfold = nfold + 1 fold$(nfold) = f$ READ f$ WEND ' Read verbs RESTORE Verbs DIM verb$(2) nverb = 0 FOR i = 0 TO 2 v = 1 WHILE (v <> 0) READ v$,v verb$(i) = verb$(i) + "," + v$ + "," + STR$(v) IF v > nverb THEN nverb = v WEND NEXT i ' Read verb attributes (verbs must be in order!) RESTORE Commands DIM reqnoun(1,nverb),defprep(nverb),nounat(1,nverb) DIM noundef(1,nverb),nounpl(1,nverb) FOR i = 1 TO nverb READ reqnoun(0,i),reqnoun(1,i),defprep(i),nounat(0,i),nounat(1,i) READ noundef(0,i),noundef(1,i),nounpl(0,i),nounpl(1,i) NEXT i '*** Set the null verb's "attributes" nounpl(0,0) = 2:nounpl(1,0) = 2 ' Read nouns RESTORE Nouns READ mnouns,mcode DIM nindex(mnouns),nhom(mnouns),ncode(mcode) noun$ = "" nnoun = 0 mhom = 0:REM maximum number of homonyms for any noun nbase = 0:REM start at base of ncode table code = 0 READ n$ WHILE (n$ <> "") noun$ = noun$ + "," + n$ + "," + STR$(nnoun) hom = 0 nindex(nnoun) = nbase READ code WHILE (code <> 0) ncode(nbase) = code nbase = nbase + 1 hom = hom + 1 READ code WEND nhom(nnoun) = hom IF hom > mhom THEN mhom = hom nnoun = nnoun + 1 READ n$ WEND ' Read prepositions RESTORE Prepositions prep$ = "" nprep = 0 READ p$ WHILE (p$ <> "") READ p nprep = nprep + 1 prep$ = prep$ + "," + p$ + "," + STR$(p) READ p$ WEND ' Read preposition names RESTORE Prepnames DIM prepn$(nprep) READ p$ nprepn = -1 WHILE (p$ <> "") nprepn = nprepn + 1 prepn$(nprepn) = p$ READ p$ WEND imap: ' Read map (see Locations: for details) PRINT"I am reading the map . . ." RESTORE map READ mloc,avdes,mmcond,mfcond,avfcond DIM map(mloc,9),Llight(mloc),Lon(mloc) DIM dindex(mloc),des$(mloc * avdes) DIM mcond(4,mloc),mmes$(mloc) DIM findex(mloc),fcond(5,mfcond),fdes$(mfcond * avfcond) REM N,NE,E,SE,S,SW,W,NW,U,D, water, light, lighton? nloc = 1:ndes = 0:nmcond = 0:nfcond = 0:nfcdes = 0 READ l WHILE (l <> 0) nloc = nloc + 1 IF nloc <> l THEN PRINT"MAP IS IN BAD FORMAT AT LOC"nloc:STOP cmcond = 0 ' Count the number of map cond. in this location FOR i = 0 TO 9 READ n IF (n < 0) AND (n > -99) THEN n = -n IF n > cmcond THEN cmcond = n map(l,i) = -nmcond - n ELSE map(l,i) = n END IF NEXT i READ Llight(l),Lon(l) FOR j = 1 TO cmcond ' Read map conditionals (if there are any) nmcond = nmcond + 1 FOR k = 0 TO 4 READ mcond(k,nmcond) NEXT k READ mmes$(nmcond) NEXT j dindex(l) = ndes READ des$(ndes) ' First line is short description (can be NULL) WHILE (des$(ndes) <> "") ' Succeeding lines are long descriptions ndes = ndes + 1 READ des$(ndes) WEND READ a,b,c,d findex(l) = nfcond + 1 WHILE (a <> -1) ' Read a flag conditional nfcond = nfcond + 1 fcond(0,nfcond) = a:fcond(1,nfcond) = b:fcond(2,nfcond) = c fcond(3,nfcond) = d:fcond(4,nfcond) = nfcdes READ fdes$(nfcdes) WHILE (fdes$(nfcdes) <> "") nfcdes = nfcdes + 1 READ fdes$(nfcdes) WEND READ a,b,c,d WEND READ l WEND dindex(nloc+1) = ndes:fcond(4,nfcond+1) = nfcdes ' Mark end of description lists findex(nloc+1) = nfcond + 1 ' and mark end of flag lists ' Read flags ' Flag 1 is lamp on/off, flag 2 is daytime/nighttime RESTORE Flags READ mflag nflag = 0 DIM flag(mflag) READ f WHILE (f) IF f>nflag THEN nflag = f READ flag(f),f WEND iobj: ' Read objects DIM Lfirst(nloc),Llast(nloc),seen(nloc) RESTORE Objects READ mobj,mrel,mbot DIM pre$(mobj),word$(mobj),adj$(mobj),long$(mobj) DIM lo(mobj),par(mobj),rel(mobj) DIM first(mrel,mobj),last(mrel,mobj),left(mobj),right(mobj) DIM size(mobj),opening(mrel,mobj),cap(mrel,mobj),opaque(mrel,mobj) DIM closed(mobj),openable(mobj) DIM folded(mobj),foldable(mobj),locked(mobj),holdwater(mobj) DIM worn(mobj),wearable(mobj),soft(mobj),food(mobj),immobile(mobj) DIM totw(mobj),totb(mobj),bulk(mrel,mobj) DIM bottles(mbot) nbot = -1 ' Keep a list of bottles ' Read objects nobj = 0 READ n WHILE (n <> 0) IF (n > nobj) THEN nobj = n READ pre$(n),word$(n),adj$(n),long$(n) READ lo(n),par(n),rel(n) READ size(n),wei FOR i = 0 TO mrel READ opening(i,n) NEXT i anycap = 0 FOR i = 0 TO mrel READ cap(i,n) anycap = anycap OR cap(i,n) NEXT i FOR i = 0 TO mrel READ opaque(i,n) NEXT i READ closed(n),openable(n),folded(n),foldable(n),locked(n) READ holdwater(n),worn(n),wearable(n),soft(n),food(n),immobile(n) IF holdwater(n) THEN nbot = nbot + 1:bottles(nbot) = n totw(n) = wei totb(n) = size(n) IF par(n) <> 0 OR immobile(n) = 0 OR anycap <> 0 THEN IF par(n) THEN CALL Insert(n,par(n),rel(n)) ELSE CALL Insert(n,-lo(n),0) END IF END IF READ n: REM next object WEND Arrays: ' Arrays hold homonyms for ambiguity resolution DIM nchoice(mhom + 2,1),nchoice2(mhom + 2,1) ' Arrays hold lists of nouns and objects DIM lnoun(1,mlist),nlnoun(1),ncount(1),olnoun(mlist) DIM mnoun(1,mlist),mlnoun(1),mcount(1) ' Commands can be superseded temporarily by other commands (e.g., ' if you say "wear hat" you must first "take" it; the program will ' automatically do this) But for the sake of the multiple-noun ' sequences, etc., the command must be restored to its original ' form, even if it has been superseded. Thus, you use RecordCommand ' and RestoreCommand to store this activity on a "command stack". ' The Alias() subprogram does this automatically for you. mrlev = 10 ' Maximum ten (!) levels of command stack DIM vo(mrlev),po(mrlev),no(mrlev,1) DIM vo$(mrlev),po$(mrlev),no$(mrlev,1),nno$(mrlev,1) ' Arrays hold the direct object and indirect object DIM n(1),n$(1),nn$(1) Initvals: GOSUB Flags ' Set mnemonic variables fdindex = 4 ' internal use constant (see Look:) fseen = 5 ' internal use constant (see SaveGame: and Look:) ' Setup starting values l = 2:ol = 2:REM You start in room 2 t = flag(tim):REM time is kept by flag variable "tim" GOSUB ClearCommand:FOR z = 0 TO 1:ncount(z) = 0:nlnoun(z) = 0:NEXT v = 1:REM "Look" is the first command v$ = "look" Player: maxcap = 15:maxweight = 50:REM Player's capacity, total weight capacity maxgrab = 20:maxlift = 40:REM Maximum size, weight, player can lift (see Take:) fat = 20:REM Size of player while sitting (3*fat is size when lying down) GOTO PreProcess NewCommand: rlev = 0 ' Clear command stack GOSUB RecordCommand GOSUB ClearCommand GOSUB ClearList ncmd$ = "":GOTO InCommand ContCommand: rlev = 0 ' Clear command stack GOSUB RecordCommand ncmd$ = "":GOTO InCommand GetCommand: rlev = 0 ' Clear command stack IF nlnoun(1) THEN '*** take care of multiple indirect objects ncount(1) = ncount(1) + 1 IF ncount(1) <= nlnoun(1) THEN n(1) = lnoun(1,ncount(1)) CALL NameNoun(n(1),n$(1),nn$(1)) PRINT p$" "nn$(1)": "; GOTO Filter END IF END IF IF nlnoun(0) THEN '*** take care of multiple direct objects ncount(0) = ncount(0) + 1 IF ncount(0) <= nlnoun(0) THEN ncount(1) = 1 IF nlnoun(1) THEN n(0) = lnoun(1,1) n(0) = lnoun(0,ncount(0)) CALL NameNoun(n(0),n$(0),nn$(0)) PRINT nn$(0)": "; GOTO Filter END IF END IF GOSUB RecordCommand GOSUB ClearCommand GOSUB ClearList InCommand: PRINT IF ncmd$ = "" THEN LINE INPUT"> ";cmd$:PRINT:cmd$ = cmd$ + " " ELSE GOSUB waitforesc:IF a$ = CHR$(27) THEN NewCommand cmd$ = ncmd$ END IF Parse: ' Take care of grammatical quirks a = INSTR(cmd$,".") ' Periods IF (a) THEN ncmd$ = MID$(cmd$,a+1) WHILE (MID$(ncmd$,1,1) = " ") ncmd$ = MID$(ncmd$,2) WEND cmd$ = LEFT$(cmd$,a-1) + " " ELSE ncmd$ = "" END IF a = INSTR(cmd$,",and ") ' Replace commas WHILE (a) cmd$ = LEFT$(cmd$,a-1)+" and "+MID$(cmd$,a+5) a = INSTR(cmd$,",and ") WEND a = INSTR(cmd$,", and ") WHILE (a) cmd$ = LEFT$(cmd$,a-1)+" and "+MID$(cmd$,a+6) a = INSTR(cmd$,", and ") WEND a = INSTR(cmd$,",") WHILE (a) cmd$ = LEFT$(cmd$,a-1)+" and "+MID$(cmd$,a+1) a = INSTR(cmd$,",") WEND WHILE (MID$(cmd$,1,1) = " ") ' Get rid of excess spaces cmd$ = MID$(cmd$,2) WEND Interpret: ' nn is the noun number (0 = direct obj, 1 = indirect obj) IF cmd$ = "" THEN PRINT"Say what?":GOTO ContCommand nlnoun(0) = 0:nlnoun(1) = 0 '*** stop multiple noun loops ocmd$ = cmd$:locmd=LEN(ocmd$) IF noobj THEN v = 0 '*** See Filter: for origin of noobj flag CALL GetVerb(cmd$,v,v$) IF noobj THEN IF v <> 0 AND v <> vo THEN vo=v:vo$=v$ GOSUB ClearCommand '*** User can override old verb v=vo:v$=vo$ ELSE v=vo END IF END IF IF cmd$ = "" THEN PreProcess IF noobj THEN InPrep ambig=0:but=0:cand=0:nch=0:that=0:nn=0 InNoun: CALL GetNoun(cmd$,nchoice(),nch,n(nn),nounat(nn,v),noundef(nn,v),that) IF nch = -1 THEN PRINT"I don't understand what you're talking about.":GOTO NewCommand IF nch = -2 THEN GOSUB Mystery:GOTO NewCommand IF nn = 0 THEN IF cmd$<>"" AND nounpl(1,v) = 0 THEN ' default "that" clause? tn=0:c=0:CALL GetPrep(cmd$,c) IF c > 0 AND c < 8 THEN tp=c:that=1:GOTO InThatClause ELSE ' Message for InPrep not to scan again for a preposition trp=c END IF END IF END IF IF that THEN ' "that" clause tp=0:tn=0 InThatClause: IF nch = 0 THEN CALL SkipThatClause(cmd$) ELSE CALL GetThatClause(cmd$,tp,tn) IF tp = -1 THEN Parse IF tp = -2 THEN NewCommand IF ambig = 1 AND tn = 0 THEN 'Ambig resolution failed, so GOTO Parse ' assume player overrided old command and start over END IF IF tp < 0 OR tp > 4 OR tn = 0 THEN IF cmd$ <> "" THEN PRINT"I don't know what you mean by '"cmd$"'. GOTO NewCommand ELSE PRINT"That's . . . what?" ' Try to resolve ambiguity PRINT:LINE INPUT"> ";cmd$:cmd$=cmd$+" ":PRINT ambig=1:GOTO InThatClause END IF END IF CALL ResolveThat(nchoice(),nch,n(nn),tp-1,tn) IF nch = 0 THEN GOSUB Mystery:GOTO NewCommand END IF END IF IF ambig = 1 AND nch = 0 THEN ' AskAmbig (see below) failed, so cmd$=amb$ ' assume that the player overrided the old command, and GOTO Parse ' start over ELSE ambig = 0 ' Clear AskAmbig flag END IF IF nch > 1 THEN ' Ask player to resolve ambiguity that = 0:CALL AskAmbig(nchoice(),nch,that) PRINT:LINE INPUT"> ";amb$:amb$ = amb$ + " ":PRINT cmd$ = amb$ + cmd$:ambig = 1 ' (see above) GOTO InNoun ' Try to resolve ambiguity END IF IF nch THEN IF n(nn) = -12 THEN ' Resolve pronoun ambiguity IF no(0,1) > 0 THEN ' Choose last noun referenced n(nn)=no(0,1) ELSEIF no(0,0) > 0 THEN n(nn)=no(0,0) ELSE n(nn)=0 END IF IF n(nn) <> 0 THEN CALL NameNoun(n(nn),n$,nn$) IF nn = 0 THEN PRINT"("nn$") ELSE PRINT"("p$" "nn$") END IF END IF END IF IF but = 0 THEN ' "and" clause IF n(nn) = -11 THEN ' this is the "all" noun na = noundef(nn,v):IF na = 0 THEN na = 3 IF that = 1 AND tp > 0 AND tn > 0 THEN ' everything that's in ... that = 0 CALL Visible(tn,vis,0) IF vis = 0 THEN GOSUB Mystery:GOTO NewCommand ' Place test particle in tn, relation tp-1, to see if ' stuff in there is visible or not lo(0)=lo(tn):par(0)=tn:rel(0)=tp-1 CALL Visible(0,vis,0) IF vis THEN ThatAgain: CALL ListSib(first(tp-1,tn),lnoun(),nlnoun(),nn) ELSE IF closed(tn) THEN PRINT"(opening the "word$(tn)" first): "; CALL Alias("open",8,(tn),0,0):GOSUB OpenIt GOSUB RestoreCommand lo(0)=lo(tn):par(0)=tn:rel(0)=tp-1 CALL Visible(0,vis,0) IF vis=0 THEN NewCommand ELSE GOTO ThatAgain ELSE GOSUB Mystery:GOTO NewCommand END IF END IF ELSE IF na AND 1 THEN CALL ListSib(first(1,1),lnoun(),nlnoun(),nn) IF na AND 2 THEN CALL ListSib(Lfirst(l),lnoun(),nlnoun(),nn) END IF IF nlnoun(nn) = 0 THEN n(nn) = 0 ELSE n(nn) = lnoun(nn,1) ELSEIF n(nn) = -13 THEN ' plural pronoun IF ncount(nn) = 0 THEN FOR i = 1 TO onlnoun nlnoun(nn) = nlnoun(nn) + 1 lnoun(nn,nlnoun(nn)) = olnoun(i) NEXT IF nlnoun(nn) = 0 THEN n(nn) = 0 ELSE n(nn) = lnoun(nn,1) END IF ELSEIF n(nn) <> 0 THEN nlnoun(nn) = nlnoun(nn) + 1 lnoun(nn,nlnoun(nn)) = n(nn) END IF ELSE '"but" clause IF n(nn) = -11 THEN PRINT"You humans have a strange way of speaking.":GOTO NewCommand IF n(nn) = -13 THEN ' plural pronoun FOR i = 1 TO onlnoun a = 0 FOR j = 1 TO nlnoun(nn) IF lnoun(nn,j) = olnoun(i) THEN a=1:nlnoun(nn)=nlnoun(nn)-1 IF a THEN lnoun(nn,i) = lnoun(nn,i+1) NEXT NEXT ELSE ' single word a = 0 FOR i = 1 TO nlnoun(nn) IF lnoun(nn,i) = n(nn) THEN a = 1:nlnoun(nn) = nlnoun(nn) - 1 IF a THEN lnoun(nn,i) = lnoun(nn,i+1) NEXT END IF IF nlnoun(nn) THEN n(nn) = lnoun(nn,1) ELSE n(nn) = 0 END IF ELSE IF cand = 1 THEN ncmd$ = cmd$+"."+ncmd$:cmd$ = "":GOTO PreProcess END IF IF cmd$ = "" THEN PreProcess InPrep: lcmd = LEN(cmd$) c = 0:IF trp THEN c=trp:trp=0 ELSE CALL GetPrep(cmd$,c) IF c = 0 THEN PreProcess IF c < 8 AND nn = 0 THEN p = c:ploc = locmd-lcmd ' Record prep location IF cmd$ = "" THEN PreProcess IF (c = 8 AND nn = 0 AND n(0) = 0) THEN ncmd$ = cmd$ + "." + ncmd$ cmd$ = "" GOTO PreProcess END IF IF c = 8 THEN cand = 1:nch = 0:that = 0:GOTO InNoun ' and ... IF c = 9 THEN but = 1:nch = 0:that = 0:GOTO InNoun ' but ... IF nn = 1 THEN ' What!? Insert a "that's" and start over IF warnthat < 3 THEN warnthat = warnthat + 1 PRINT"(Please use more specific language in the future, e.g., PRINT CHR$(34)LEFT$(ocmd$,ploc)"THAT'S "MID$(ocmd$,ploc+1)CHR$(8)CHR$(34)"-Ed.) END IF GOSUB ClearCommand:GOSUB ClearList cmd$ = LEFT$(ocmd$,ploc)+"that's "+MID$(ocmd$,ploc+1) ocmd$ = cmd$:locmd = LEN(ocmd$) GOTO Parse END IF nn = 1:but = 0:cand = 0:nch = 0:that = 0:GOTO InNoun 'Get indirect object PreProcess: nn = 0:p$ = prepn$(p) FOR i = 0 TO 1 IF n(i) <> 0 THEN CALL NameNoun(n(i),n$(i),nn$(i)) NEXT IF cmd$ <> "" THEN cmd$ = LEFT$(cmd$,LEN(cmd$) - 1) PRINT"I don't know what you mean by '"cmd$CHR$(8)"'. GOTO NewCommand END IF FOR i = 0 TO 1 IF nlnoun(i) = 1 THEN nlnoun(i) = 0 NEXT FOR i = 0 TO 1 IF nlnoun(i) THEN IF nounpl(i,v) < 2 THEN PRINT"You can't use multiple "; IF i = 1 THEN PRINT"indirect "; PRINT"objects with '"v$"'! GOTO NewCommand END IF END IF NEXT IF nlnoun(0) > 0 OR nlnoun(1) > 0 THEN GetCommand Filter: '*** grammatical replacements IF (n(0)<0) AND (n(0)>=-10) AND (v = 0) THEN v = 6: v$="go" IF v = 3 THEN IF n(1) <> 0 THEN v = 7 ' "drop xxx on yyy" == "put xxx on yyy" IF v = 0 AND n(0) = 0 AND n(1) = 0 THEN PRINT"I don't understand.":GOTO NewCommand FOR i = 0 TO 1 IF n(i) <> 0 AND nounpl(i,v) = 0 THEN PRINT"You can't use "; IF i = 1 THEN PRINT"indirect "; PRINT"objects with '"v$"'! GOTO NewCommand END IF NEXT IF v = 0 AND n(0) <> 0 THEN PRINT"What do you want to do with "nn$(0)"? GOTO ContCommand END IF IF v = 0 AND n(1) <> 0 THEN PRINT". . . "prepn$(p)" "nn$(1)"? GOTO ContCommand END IF FOR i = 0 TO 1 IF reqnoun(i,v) THEN na = noundef(i,v):IF na = 0 THEN na = 3 IF n(i) = 0 THEN IF na AND 1 THEN CALL ListSib(first(1,1),lnoun(),nlnoun(),i) IF na AND 2 THEN CALL Li