--- title: "Roberts Labs BBS" id: 55088 type: "computer_media" slug: "roberts-labs-bbs" url: "http://localhost/computer_media/roberts-labs-bbs/" markdown_url: "http://localhost/computer_media/roberts-labs-bbs.md" published_at: "2024-06-14T10:58:49+00:00" modified_at: "2026-04-01T09:19:11+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "A fully functional modem-driven bulletin board system with machine code I/O routines, multi-message storage, sysop chat, and tape-based message persistence." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" indiv: - name: "Kenneth Roberts" slug: "kenneth-roberts" taxonomy: "indiv" url: "http://localhost/indiv/kenneth-roberts/" genre: - name: "BBS" slug: "bbs" taxonomy: "genre" url: "http://localhost/type/bbs/" media_type: "Program" programmers: - name: "Kenneth Roberts" slug: "kenneth-roberts" taxonomy: "indiv" url: "http://localhost/indiv/kenneth-roberts/" download_url: "https://archive.org/download/timex-sinclair-software-archive/Roberts%20Labs%20BBS%20%28198x%29%28Roberts%2C%20Kenneth%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "198x" related_products: - id: 40286 title: "TINYBOARD" type: "product" url: "http://localhost/product/tinyboard/" media_type_tags: "BBS" --- Roberts Labs BBS is a bulletin board system program that enables remote callers to connect via modem, read and leave messages, enter chat mode with the sysop, and access daily specials and system data. The system stores up to 40 messages (CODE “(“) of 564 characters each in a two-dimensional string array, with message counts and indices persisted to tape as separate DATA files. Three machine code routines are POKEd into RAM at addresses 65000–65212: a modem status checker, a receive (input) routine, and a transmit (output) routine, all communicating through I/O port 119 (hex 77). Line numbers are stored as variables using VAL “number” throughout, and GO TO/GO SUB targets are resolved through these named variables (e.g., `read`, `quit`, `menu`), making the flow table-driven and easily reconfigurable. The sysop menu allows reading, deleting, and entering messages locally, toggling chat availability and password protection, saving the message base to tape, and editing the logon bulletin and daily special. *** ## Program Analysis ### Program Structure The program is organized into distinct functional blocks identified by line-number ranges, with all major entry points stored as numeric variables initialized in the setup block around lines 9009–9011. This means `GO TO read`, `GO TO quit`, `GO TO menu`, etc., are not labels but variable references resolved at runtime, allowing the entire routing table to be changed in one place. | Line Range | Function | | --- | --- | | 1000–1020 | Auto-answer / idle loop (awaiting call) | | 2001–2070 | Logon sequence and main menu dispatcher | | 3000–3060 | Read messages | | 4010–4070 | Leave a message | | 4500–4620 | Message log viewer | | 5000–5130 | Quit / disconnect sequence | | 6000–6040 | Logon bulletin display (subroutine) | | 6500–6630 | New logon bulletin / daily special input | | 7000–7162 | Chat mode with sysop | | 7500–7570 | Numeric input subroutine (`innum`) | | 7600–7650 | Access code verification (`incode`) | | 8001–8020 | Name/string input subroutine (`inname`) | | 8100–8175 | Send string / CR subroutines | | 8200–8210 | Password management | | 8500–8599 | Sysop (local) menu | | 8600–8810 | View/edit logon text and systems data | | 9004–9100 | Initialization and variable setup | | 9510–9540 | Machine code loader | | 9992–9993 | Timer subroutine | | 9995–9999 | Save routines and stop | ### Machine Code Routines Three Z80 machine code routines are loaded via `READ`/`POKE` loops in the subroutine starting at line 9510. All three communicate with the modem through I/O port 119 (0x77). | Address | Size (bytes) | Purpose | Variable | | --- | --- | --- | --- | | 65000 | 9 | Modem status check — returns 0 (tx ready), 1 (rx ready), or 2 (both) | `statchk` | | 65100 | 33 | Blocking receive: waits for rx-ready, reads a byte from port 115 | `input` | | 65200 | 13 | Transmit-ready check (used as boolean via `USR output`) | `output` | The status routine at 65000 decodes the low two bits of port 119: bit 0 = TX ready, bit 1 = RX ready, returning a composite value. The receive routine at 65100 polls until RX ready, then reads from port 115 (`CODE "s"`). The transmit check at 65200 is used inline throughout as a boolean guard: `IF USR output THEN : OUT CODE "s",...`. The data bytes for the routines (lines 9515, 9525, 9535) decode as follows for the status checker: `XOR A / IN A,(119) / AND 3 / LD C,A / LD B,0 / RET` — returning the two status bits as a small integer to BASIC via the BC register pair. ### Variable-as-Line-Number Idiom All subroutine and branch targets are stored in numeric variables at initialization time (lines 9009–9011). For example, `LET quit=VAL "5000"`, `LET menu=VAL "2006"`, `LET read=VAL "3000"`. Every subsequent `GO TO quit` or `GO SUB cr` resolves through the variable rather than a literal line number. This is an intentional design choice that centralizes routing and reduces the cost of reorganizing the program, as only the initialization block need be updated. ### Message Storage Messages are stored in the two-dimensional string array `m$()`, dimensioned as `DIM m$(CODE "(", VAL "564")` — that is, 40 messages (`CODE "(" = 40`) of 564 characters each. Each message uses a fixed internal layout: - Characters 1–4: “TO: ” header - Characters 5–32 (approx): addressee name - Characters 33 (`CODE "!"`) to 38 (`CODE "&"`): “FROM: ” header - Characters 39 (`CODE "'"`) to 64 (`CODE "@"`): sender’s username (`u$`) - Characters 65 (`CODE "A"`) onward: message body, terminated by `CHR$ PI` (null/zero) The message counter `y1` wraps at 40, implementing a circular buffer. The counter and the array are saved to tape separately: `SAVE "mbase" DATA m$()` and `SAVE "msctr" DATA y()`, where `y()` is a 1×1 numeric array used purely to persist `y1`. ### ON ERR Usage `ON ERR GO TO quit` and `ON ERR GO TO inputcom` appear at several points (lines 2037, 4020, 7515, 7610). These act as timeout or disconnect handlers — if the remote end drops carrier mid-input, the USR call or I/O operation will error and the program jumps cleanly to the quit or menu routine rather than halting. ### Timer Implementation The timer subroutine (lines 9992–9993) reads the system frame counter from addresses 23672–23674 (the three-byte ticker), divides by `CODE "<" = 60` to convert to seconds, then extracts hours and minutes. It formats the result into the 5-character string `x$` by printing to line 21 and reading back with `SCREEN$`. Line 2036 checks whether the elapsed time exceeds 30 minutes (`VAL x$(4 TO SQR EXP PI) > VAL "30"`), enforcing a session time limit. ### Chat Mode Chat mode (lines 7000–7162) first pages the sysop with beeps and a dash-progress indicator. If the sysop does not respond within 128 iterations, a “not available” message is sent and the caller returns to the menu. Once the sysop responds, a full-duplex polling loop runs: the status routine at 65000 is called each iteration; if RX ready, a byte is received and displayed with the receive routine; if TX ready and a local key is pressed, the key is transmitted via `OUT CODE "s"`. The sysop exits chat by pressing the key whose code matches `CODE "NOT "` (Sinclair NOT token, entered via Symbol Shift+S). ### Sysop Local Menu The sysop menu (lines 8500–8599) is accessible from the idle screen via the NOT keypress and provides local-only functions unavailable to callers: - Read any message by number with full field display - Delete a message (replaces content with “NO MESSAGE FOUND…………”) - Leave a message locally via direct keyboard entry - Toggle password protection (`o` flag) and chat availability (`b` flag) - Save the message base to tape - Edit the logon bulletin (`t$`) and daily special (`h$`) - Enter systems data string (`z$`) - View current logon and daily special text ### Notable Techniques and Idioms - `SGN PI` is used throughout as a constant 1 (since PI > 0), and `NOT PI` as 0 (since PI is nonzero, NOT returns 0). `INT PI` = 3, `SQR EXP PI` = 5, `PI*PI` = ~9 are used similarly as compact numeric literals. - `CODE "w"`, `CODE "s"`, etc., provide port numbers as character codes (119, 115), avoiding magic numbers in the source while remaining readable. - `POKE VAL "23692", CODE " COPY "` appears before each character output to reset the FRAMES counter used for the BREAK key mechanism, effectively suppressing BREAK during modem I/O. - The `DIM l$(VAL "564")` blank template at line 4011 is reused to clear message slots: `LET m$(x) = l$` efficiently fills an entire row with spaces. - Line 8530’s sysop message-read function prints three slices of `m$(x)` using slice notation to display the TO, FROM, and body fields separately on screen. ### Anomalies and Points of Interest - Line 8011: `IF CODE v$ = VAL "13" THEN GO TO menu` inside the `inname` subroutine — pressing Enter during name input silently jumps to the menu rather than returning to the caller, which could cause unexpected flow if `inname` is called from contexts other than logon. - Line 9009 sets `LET z$="\''"`` — but `z$` is also used as the “systems data” string (set by line 8800 `INPUT ... LINE z$`). The initialization value appears to be a placeholder block graphic character. - Line 2004: `IF o = SGN PI` skips code verification when `o = 1`, but `o` is initialized to `NOT PI = 0` and incremented in line 8200 — the password toggle logic uses `o` as both a flag and a counter, which could cause the bypass condition to be reached after two password changes. - Line 7006 has a structural ambiguity: the `NEXT x` appears on the same line as two `IF` tests and a `BEEP`, meaning `NEXT x` only executes when `INKEY$ = ""`, effectively terminating the loop early if any key is pressed — this is the intended paging mechanism. - Line 9100 unconditionally does `GO TO quit` immediately after initialization completes, so the very first action after setup is always to execute the disconnect/reset sequence, which then jumps to `autoans` (line 1000) to begin waiting for calls. ## Source Code ``` 3 REM SYMBL SHIFT S "NOT" ENDS CHAT MODE FOR SYSOP. 5 REM SYMBL SHIFT 2 "@" SAVES MESSAGE FOR SYSOP. 10 GO TO VAL "9000" 1000 PRINT "AWAITING A CALL" 1001 OUT VAL "119",VAL "34" 1002 OUT VAL "119",NOT PI 1010 PRINT AT VAL "4",NOT PI;"CHAT IS ";b$ 1011 PRINT AT VAL "10",NOT PI;"CODE ENTRY IS ";s$ 1012 PRINT AT PI+PI,NOT PI;"CALLS RECEIVED ";s 1014 PRINT AT VAL "8",NOT PI;"MESSAGES ";w 1015 LET a=IN CODE "w" 1016 IF CODE INKEY$=CODE "NOT " THEN GO TO edit 1020 IF a=VAL "5" THEN GO TO ansloop 1070 OUT CODE "w",VAL "2" 1080 OUT CODE "w",VAL "34" 1090 PAUSE VAL "300" 2001 OUT CODE "w",CODE "@": OUT CODE "w",CODE "{": OUT CODE "w",CODE "7": POKE VAL "23674",NOT PI: POKE VAL "23673",NOT PI: POKE VAL "23672",NOT PI 2003 PAUSE CODE "x": CLS : GO SUB logonbull: LET x=IN CODE "s": LET p$="Full NAME: ": GO SUB send: GO SUB inname: LET u$=y$:: LPRINT u$ 2004 IF o=SGN PI THEN GO TO VAL "2006" 2005 LET f=NOT PI: LET f1=f: LET p$="Code Input: ": GO SUB send: GO SUB incode 2006 LET y=f: RESTORE VAL "2007" 2007 DATA "--------------------------------"," *>*> EXECUTIVE MAIN MENU <*<*","ead Messages eave Message","hat Mode ime On","aily Special ystems Data","essage Log oodbye","--------------------------------","Choice?: " 2008 GO SUB cr:: IF USR output THEN : OUT CODE "s",CODE " ": PRINT 2020 FOR p=SGN PI TO VAL "8": PRINT : IF USR output THEN : OUT CODE "s",VAL "13" AND pVAL "30" THEN LET f1=SGN PI: GO TO quit 2037 ON ERR GO TO quit: LET c$=CHR$ USR input: PRINT c$: PRINT 2038 IF c$="d" OR c$="D" THEN LET p$=h$: OUT CODE "s",VAL "13": GO SUB send: PAUSE CODE "x": GO TO inputcom 2039 IF c$="s" OR c$="S" THEN LET p$=z$: OUT CODE "s",VAL "13": GO SUB send: PAUSE CODE "x": GO TO inputcom 2040 IF c$="r" OR c$="R" THEN FOR x=SGN PI TO SQR PI: GO SUB cr:: NEXT x: GO TO read 2041 IF c$="t" OR c$="T" THEN GO SUB timer: LET p$="Connect Time ": LET p$=p$+x$: GO SUB scr::: GO TO menu 2043 IF c$="M" OR c$="m" THEN GO TO VAL "4500" 2045 IF c$="c" OR c$="C" THEN GO TO chat 2047 IF c$="g" OR c$="G" THEN PAUSE VAL "30": GO TO quit 2050 IF c$="l" OR c$="L" THEN GO TO leave 2070 GO TO inputcom 3000 LET p$="Message Number? ": GO SUB send: GO SUB innum 3015 LET y=numin 3018 IF m$(y,SGN PI)=" " THEN LET p$(SGN PI TO VAL "28")="No message Found............": LET p$=p$(SGN PI TO VAL "28")+CHR$ PI: GO SUB scr::: GO TO inputcom 3019 PRINT AT VAL "21",NOT PI;" ": PRINT AT VAL "21",NOT PI;y: LET c$=SCREEN$ (VAL "21",NOT PI): LET c$=c$+SCREEN$ (VAL "21",SGN PI): LET p$="MESSAGE NUMBER: "+c$: GO SUB cr: GO SUB scr 3024 FOR v=SGN PI TO VAL "563": POKE VAL "23692",CODE " COPY " 3025 IF CODE m$(y,v)=INT PI THEN LET v=VAL "564": NEXT v: PAUSE CODE "<": GO TO VAL "3036" 3030 PRINT m$(y,v);: IF USR output THEN : OUT CODE "s",CODE m$(y,v) 3031 IF v>CODE "@" THEN NEXT v 3032 IF (v>CODE " " AND CODE m$(y,v)=VAL "13") THEN LET v=CODE "@": GO SUB cr: 3033 IF (vCODE "(" THEN LET y1=SGN PI 4011 DIM l$(VAL "564"): LET m$(y1)=l$ 4012 GO SUB cr: LET p$="To Whom? : ": GO SUB send: ON ERR GO TO inputcom: LET m$(y1,SGN PI TO VAL "4")="TO: ": FOR x=SQR EXP PI TO CODE " ": LET m$(y1,x)=CHR$ USR input: PRINT m$(y1,x); 4013 IF CODE m$(y1,x)=VAL "13" THEN LET x=CODE " " 4014 NEXT x 4015 LET m$(y1,CODE "!" TO CODE "&")="FROM: ": LET m$(y1,CODE "'" TO CODE "@")=u$ 4018 GO SUB cr: LET p$="Input Message (500 chars Max)..Type To Save...": GO SUB scr: 4019: FOR x=SGN PI TO SQR PI: GO SUB cr: NEXT x 4020 ON ERR GO TO quit: FOR v=CODE "A" TO VAL "563": POKE VAL "23692",CODE " COPY ": LET m1=USR input 4050 LET m$(y1,v)=CHR$ m1: PRINT m$(y1,v);: IF m1=INT PI THEN LET v=VAL "564": NEXT v: LET w=w+SGN PI: LET p$="SAVED...": GO SUB cr: GO SUB scr: PAUSE VAL "30": GO TO inputcom 4053 IF CODE m$(y1,v)CODE "z" THEN LET m$(y1,v)=CHR$ PI: LET v=VAL "564": NEXT v: GO TO inputcom 4054 IF CODE m$(y1,v)>=VAL "24" AND CODE m$(y1,v)<=VAL "31" THEN LET m$(y1,v)=CHR$ PI: LET v=VAL "564": NEXT v: GO TO inputcom 4055 NEXT v 4070 GO TO inputcom 4500 FOR q=SGN PI TO CODE "(" 4510 IF m$(q,1)="T" THEN GO SUB VAL "4600" 4520 NEXT q 4530 LET p$="END OF MESSAGE LOG -" 4535 GO SUB scr: GO TO inputcom 4600 PRINT AT VAL "21",NOT PI;" ": PRINT AT VAL "21",NOT PI;q: LET c$=SCREEN$ (VAL "21",NOT PI): LET c$=c$+SCREEN$ (VAL "21",SGN PI): LET p$="MESSAGE NUMBER: "+c$: GO SUB cr: GO SUB scr 4610 LET p$=m$(q,SGN PI TO VAL "28") 4620 GO SUB send: GO SUB cr: RETURN 5000 LET n$="\d\i\s\c\oN\n\e\c\t": BORDER NOT PI: CLS 5001 ON ERR RESET 5105 CLS : PAUSE PI*PI 5110 LET p$="*****Thank You For Calling!*****"+q$+" >>ROBERTS LABS. B.B.S.<< "+q$+" Goodbye - " 5112 IF f=SGN PI THEN LET p$(SGN PI TO VAL "28")="YOU ENTERED AN IMPROPER CODE" 5113 IF f1=SGN PI THEN LET p$(SGN PI TO VAL "28")="SORRY - YOUR TIME IS UP....." 5115 PAUSE VAL "30": CLS : IF USR output THEN : OUT CODE "s",VAL "28": IF USR output THEN : OUT CODE "s",VAL "31" 5120 GO SUB send 5121 PAUSE CODE "x" 5125 OUT CODE "w",CODE "@": OUT CODE "w",NOT PI: OUT CODE "w",NOT PI 5130 PAUSE CODE "x": CLS : GO TO autoans 6000 LET s=s+SGN PI 6001 PAUSE CODE "<": FOR x=SGN PI TO VAL "30": IF USR output THEN : OUT CODE "s",NOT PI: NEXT x 6002 IF IN CODE "w""" THEN GO TO VAL "7008" 7006 IF INKEY$="" THEN PRINT "-";: IF USR output THEN : OUT CODE "s",CODE ".": BEEP VAL ".1",PI*PI: NEXT x 7007 LET p$="The SYSOP is NOT AVAILABLE.....": GO SUB send: FOR x=SGN PI TO PI*PI: BEEP VAL ".1",SGN PI: NEXT x: GO SUB cr: GO TO menu 7008 GO SUB cr: LET p$="YOU ARE NOW IN CHAT MODE:": GO SUB send: FOR X=SGN PI TO PI*PI: BEEP VAL ".1",SGN PI: NEXT X: GO SUB cr 7009 CLS : PRINT "You are in chat with ";u$: PRINT : PRINT "SYMBL SHIFT/NOT TO ESCAPE..." 7010 IF CODE INKEY$=CODE "NOT " THEN GO TO inputcom 7011 POKE VAL "23692",CODE " COPY " 7020 LET rxrdy=NOT PI: LET txrdy=NOT PI 7100 LET a=USR VAL "65000": LET txrdy=SGN PI AND (a=SGN PI OR a=INT PI): LET rxrdy=SGN PI AND (a=VAL "2" OR a=INT PI) 7130 IF rxrdy THEN LET k=USR VAL "65100": PRINT CHR$ k;: IF k=VAL "13" THEN PRINT ">"; 7140 IF txrdy AND INKEY$<>"" THEN GO SUB VAL "7160" 7150 GO TO VAL "7010" 7160 IF txrdy THEN LET i$=INKEY$: PRINT i$;: OUT CODE "s",CODE i$: FOR x=SGN PI TO SQR EXP PI: NEXT x: IF CODE i$=VAL "13" THEN PRINT ">"; 7161 IF INKEY$<>"" THEN GO TO VAL "7161" 7162 RETURN 7500 DIM g$(2): LET u=SGN PI: GO SUB sendv 7515 ON ERR GO TO inputcom 7520 LET v$=CHR$ USR input: IF CODE v$>CODE "/" AND CODE v$CODE "9" THEN GO TO VAL "7500" 7525 LET g$(u)=v$: IF uVAL "2" THEN GO TO VAL "7550" 7540 GO TO VAL "7520" 7550 LET numin=VAL g$ 7560 IF numinCODE "(" THEN LET numin=SGN PI 7570 RETURN 7600 LET f=NOT PI 7610 ON ERR GO TO quit 7630 GO SUB sendv: GO SUB inname: LET x$=y$: PRINT x$ 7640 IF x$=o$ THEN RETURN 7650 LET f=SGN PI: GO TO quit 8001 DIM y$(CODE " "): LET u=SGN PI: GO SUB sendv 8005 ON ERR GO TO quit: LET v$=CHR$ USR input: PRINT v$; 8010 LET y$(u)=v$ AND uEAD MESSAGES","

ASSWORD ";s$;AT VAL "4",NOT PI;"ELETE MESSAGES";AT VAL "6",NOT PI;"EAVE MESSAGES";AT VAL "8",NOT PI;"UIT MENU"," HAT IS ";b$;AT VAL "10",NOT PI;"AVE MESSAGE BASE";AT VAL "12",NOT PI;"EW LOGON BULLETIN";AT VAL "14",NOT PI;"NPUT DAILY SPECIAL";AT VAL "16",NOT PI;"NTER SYSTEMS DATA";AT VAL "18",NOT PI;"IEW LOGON & SPECIAL" 8520 LET i$=INKEY$ 8521 IF I$="n" THEN GO TO VAL "6500" 8522 IF i$="q" THEN GO TO quit 8523 IF i$="i" THEN GO TO VAL "6600" 8524 IF i$="v" THEN GO TO VAL "8600" 8525 IF i$="" THEN GO TO VAL "8520" 8526 IF i$="s" THEN GO TO VAL "9999" 8527 IF i$="e" THEN GO TO VAL "8800" 8528 IF i$="p" THEN GO TO VAL "8200" 8529 IF i$="c" THEN LET b=b+SGN PI: GO TO VAL "8505" 8530 IF i$="r" THEN INPUT ;"MESSAGE #?: ";x: CLS : PRINT "MESSAGE # ";x: PRINT m$(x)(SGN PI TO CODE " ")'m$(x)(CODE "!" TO CODE "@")'m$(x)(CODE "A" TO ): PRINT "PRESS ENTER TO CONTINUE": PAUSE NOT PI: GO TO edit 8540 IF i$="d" THEN INPUT "message #?: ";x: PRINT "message # ";x;" deleted.": LET m$(x)=l$: LET m$(x,SGN PI TO VAL "28")="NO MESSAGE FOUND............": PAUSE NOT PI: GO TO edit 8550 IF i$="l" THEN LET y1=y1+SGN PI: CLS : PRINT "message # ";y1: PRINT : GO SUB VAL "8700": FOR x=SGN PI TO VAL "564": LET m$(y1,x)=w$(x): PRINT m$(y1,x); 8551 IF m$(y1,x)="@" THEN LET m$(y1,x)=CHR$ PI: LET x=VAL "600": PRINT "SAVED...": PAUSE CODE "<": GO TO VAL "8500" 8554 IF i$="l" THEN IF CODE INKEY$=CODE "NOT " THEN LET m$(y1,x)=CHR$ PI: GO TO edit 8560 IF i$="l" THEN NEXT x: PAUSE NOT PI: GO TO edit 8599 CLS : GO TO edit 8600 CLS : PRINT "LOGON"'t$: PAUSE NOT PI 8610 CLS : PRINT "DAILY"'h$: PAUSE NOT PI 8620 GO TO VAL "8500" 8700 INPUT AT VAL "22",NOT PI;AT SQR PI,NOT PI; LINE w$ 8710 RETURN 8800 INPUT AT VAL "22",NOT PI;AT NOT PI,NOT PI; LINE z$ 8810 GO TO VAL "8500" 9004 PAPER NOT PI: BORDER NOT PI: INK VAL "7": CLS 9005 CLEAR VAL "64999": GO SUB VAL "9500" 9006 LET c$="": LET u$="": LET z$="": LET f1=NOT PI: DIM y(SGN PI,SGN PI): LET y1=NOT PI: DIM l$(VAL "564"): DIM m$(CODE "(",VAL "564"): FOR x=SGN PI TO CODE "(": LET m$(x)="NO MESSAGES FOUND..."+CHR$ PI: NEXT x: FOR x=SGN PI TO PI: BEEP VAL ".1",EXP PI: NEXT x: PRINT '"Do you wish to LOAD a message base?": INPUT x$: IF x$="y" OR x$="Y" THEN PRINT '"Start MESSAGE BASE tape... (2 part LOAD...)": LOAD "" DATA m$(): LOAD "" DATA y(): LET y1=y(SGN PI,SGN PI) 9007 LET q$=" ": LET t$=" ROBERTS LABS. B.B.S. "+q$+q$: LET j$=" For PROFESSIONAL use only. ": FOR x=SGN PI TO PI: BEEP VAL ".1",EXP PI: NEXT x: PRINT '"Do You wish to load a logon bulletin?": INPUT x$: IF x$="y" THEN PRINT '"Start bulletin Tape...": LOAD "" DATA t$() 9008 PRINT '" from most modes will exit to SYSOP mode.": PAUSE CODE "TAN " 9009 LET f=NOT PI: LET y=NOT PI: LET edit=VAL "8500": LET timer=VAL "9990": LET innum=VAL "7500": LET z$="\''" 9010 LET sendv=VAL "8175": LET scr=VAL "4620": LET cr=VAL "8150": LET chat=VAL "7000": LET menu=VAL "2006": LET warmstart=VAL "2000": LET logonbull=VAL "6000": LET statchk=VAL "65000": LET input=VAL "65100": LET output=VAL "65200": LET ansloop=VAL "1010": LET inputcom=VAL "2006": LET autoans=VAL "1000": LET read=VAL "3000": LET leave=VAL "4000": LET quit=VAL "5000" 9011 LET send=VAL "8100": LET inname=VAL "8000": LET incode=VAL "7600": LET h$="No new daily message": LET b$="ON ": LET w=NOT PI: LET s=w: LET b=w: LET o$=".": LET s$="ON": LET o=w 9012 PRINT '''" "; FLASH SGN PI;"Now going to autoans mode": PAUSE CODE "TAN ": CLS 9100 GO TO quit 9510 RESTORE VAL "9515": FOR x=VAL "65000" TO VAL "65008": READ x1: POKE x,x1: NEXT x 9515 DATA 175,219,119,230,3,79,6,0,201 9520 RESTORE VAL "9525": FOR x=VAL "65100" TO VAL "65132": READ x1: POKE x,x1: NEXT x 9525 DATA 219,119,230,128,200,175,219,119,230,2,40,244,219,115,6,0,79,219,119,230,128,200,175,219,119,230,1,40,244,121,211,115,201 9530 RESTORE VAL "9535": FOR x=VAL "65200" TO VAL "65212": READ x1: POKE x,x1: NEXT x 9535 DATA 219,119,230,128,200,175,219,119,230,1,40,244,201 9540 RETURN 9992 DIM x$(SQR EXP PI): LET time=INT ((PEEK VAL "23672"+VAL "256"*PEEK VAL "23673"+VAL "256"*VAL "256"*PEEK VAL "23674")/CODE "<"): LET hr=INT (time/CODE "<"/CODE "<"): LET min=INT ((time-(hr*CODE "<"*CODE "<"))/CODE "<"): PRINT AT VAL "21",EXP INT PI;"0" AND hr