Posted July 02, 2023 by Diduz
#Tandy Model 100 #Olivetti M10 #basic
ENGLISH
I had postponed Pacuvia's Tandy Model 100 version, because I knew it could turn out a programming nightmare. I couldn't ditch that port though: the Italian version of Tandy Model 100, my dear Olivetti M10, is the first home computer I've ever used in my life. The machine is considered the first REALLY portable laptop ever produced, and mine still works after 40 years! Unfortunately, the original system couldn't address more than 32Kb RAM, and I couldn't get my hands on a legal version of the only BASIC compiler ever produced, RBASIC from King Computer Services. So, I had to squeeze the original C64 code into that amount of memory, and I was forced to run the game in interpreted BASIC mode.
I decided to cut the whole conversation system going on through the empty yogurt cup. Removing that interaction allowed me to get rid of many text strings, not to mention all the code which handled the cup itself. To compensate for the loss, I reworked one of Calindro's responses as a readable briefing already present in your inventory. Needless to say, there was no RAM left to show graphics or to play sound: their absence is due to memory management, because - as strange as it sounds - the Tandy M100 has specific BASIC commands to create monochromatic lines and boxes, as well as beeps and musical notes!
Of course, I didn't ever bother to create my dreaded status bar: Tandy M100's display is only 8-lines high, so a status bar felt too invasive in that tiny screen (I also had to split longer description in several panels, for the same reason).
1) Running the game in interpreted BASIC was hard as hell. First of all, Tandy M100's BASIC requires mandatory line numbers instead of labels: this difference alone makes the code less readable and cryptic.
2) Also, when you're not compiling the BASIC code into machine code, the BASIC script must be optimized to avoid the waste of memory: for this reason I removed all the unnecessary spaces and all the REM comments. The resulting crammed code would already be pretty confusing like that, but - wait - there's more!
3) BASIC 1.0 on the M100 doesn't recognize more than two characters for variable names! You can still use long names, but the system ignores all the characters after the first two. So, you could theoretically name a variable "LaserGun", but the system would only see "LA". The remaining characters would just be junk bytes. I decided to get rid of them and rename my variables with new two-characters names. I freed some more RAM, but the code became even more (!) ambiguous and obscure (especially because I didn't write the new names down: "Come on, I can remember this stuff!" Turns out I can not :-DDD ). Bugs galore ensued.
4) And now for the final blow: BASIC 1.0 doesn't feature nested conditions! No "ENDIF" available!!! Argh. The only way to circumvent this problem is creating additional GOSUB / RETURN subroutines.
Now, take a breath, use your imagination to apply all these restrictions to the original QBASIC-like code. Have fun:
ORIGINAL QBASIC_LIKE CODE
IF INSTR(i$, "opened") > 0 THEN GOSUB CODETOOPENTHINGS
[...]
CODETOOPENTHINGS:
IF INSTR(i$, "briefcase") > 0 AND L + BRIEF = 2 THEN GOSUB BRIEFCASEOPENED: RETURN
IF INSTR(i$, "gate") > 0 AND L = 1 THEN PRINT "Locked from the inside, keylock out of reach. Maybe I could pick the lock, but I needed a less exposed method of break-in.":RETURN
IF INSTR(i$, "lassic") > 0 AND L = 1 THEN PRINT "That wasn't the right time to leave. I had a mission!": RETURN
IF INSTR(i$, " pen") > 0 AND L = 4 THEN
IF GATE = 3 THEN PRINT "The pen was already open.":RETURN
IF GATE = 0 THEN PRINT "I tried and move it. Was it failing?": GATE=1:RETURN
IF GATE = 1 THEN PRINT "It moved again. Yes, it WAS failing!": GATE=2:RETURN
IF GATE = 2 THEN PRINT "Finally! The little pen gate swung open!": GATE=3: SCORE = SCORE + 5:RETURN
END IF
PRINT "I wanted to open something... but what?"
RETURN
M100 BASIC 1.0 CODE
695 IFINSTR(I$,"opened ")>0THENGOSUB1305:RETURN
[...]
1305 IFINSTR(I$,"briefcase")>0ANDL+BF=2THENGOSUB1205:RETURN
1310 IFINSTR(I$,"gate")>0ANDL=1THENPRINT"Locked from the inside, keylock out of reach. Maybe I could pick the lock, but I needed a less exposed method of break-in.":RETURN
1315 IFINSTR(I$,"classic")>0ANDL=1THENGOSUB4145:RETURN
1320 IFINSTR(I$," pen")>0ANDL=4THENGOSUB1355:RETURN
1350 PRINT "I wanted to open something... but what?":RETURN
1355 IFGA=3THENPRINT"The pen was already open.":RETURN
1360 IFGA=0THENPRINT"I tried and move it. Was it failing?":GA=1:RETURN
1365 IFGA=1THENPRINT"It moved again. Yes, it WAS failing!":GA=2:RETURN
1370 IFGA=2THEN PRINT"Finally! The little gate swung open!":GA=3:SC=SC+5:RETURN
Keep in mind I chose the "open" example to keep things simple in this article. If you check the code, you'll see how handling more complex commands such as "examine" turned into a convoluted mess of GOSUB/RETURN subs.
I was afraid the interpreted code would turn out too slow to be playable on the machine, but I was pleasantly surprised: those many subroutines didn't slow down the execution so much, maybe because Tandy M100 Intel 80c85 CPU runs at 2.4Mhz against the C64's 1Mhz 6510 CPU. The difference seems to compensate for the lack of a compiled version.
Phew. That was insane.
ITALIANO
Avevo rimandato la versione di Pacuvia per l'Olivetti M10, perché sapevo che poteva rivelarsi un incubo di programmazione. Non potevo però rinunciarvi: il mio caro Olivetti M10 è stato il primo home computer che abbia mai usato in vita mia. La macchina è considerata il primo laptop VERAMENTE portatile mai prodotto, e il mio funziona ancora dopo 40 anni! Sfortunatamente, il sistema originale non poteva gestire più di 32Kb di RAM, né ho potuto mettere le mani su una versione legale dell'unico compilatore BASIC mai prodotto, l'RBASIC della King Computer Services. Quindi ho dovuto spremere il codice originale per C64 in quella quantità di memoria, e sono stato costretto a distribuire il gioco in puro BASIC interpretato.
Ho deciso di stroncare l'intera conversazione che nel gioco ha luogo tramite il barattolo di yogurt vuoto. Rimuovere quell'interazione mi ha permesso di liberarmi di parecchie stringhe di testo, per non parlare di tutto il codice che gestiva il barattolo. Per compensare il taglio, ho rielaborato una delle risposte di Calindro come briefing già presente in inventario. Inutile dire che non mi è rimasta RAM per mostrare grafica o riprodurre sonoro: la loro assenza si deve alla gestione della memoria, perché - per quanto possa far sorridere - l'Olivetti M10 ha comandi specifici BASIC per creare linee e rettangoli monocromatici, così come beep e note musicali! Naturalmente, non ho nemmeno preso in considerazione la creazione della mia temuta status bar: il display dell'M10 è alto solo 8 righe, una status bar sarebbe stata troppo invasiva su quel piccolo schermo (per questa ragione ho dovuto persino dividere le descrizioni più lunghe in più pannelli).
1) Far girare il gioco in BASIC interpretato è stato molto difficile. Prima di tutto, il BASIC dell'Olivetti M10 richiede obbligatoriamente l'uso dei numeri di linea, al posto delle più comode label: solo questa differenza rende il codice meno leggibile.
2) Quando il BASIC non è compilato in linguaggio macchina, lo script dev'essere ottimizzato per non sprecare memoria: per questa ragione ho rimosso tutti gli spazi inutili, così come ogni commento REM. Il risultante codice, così compresso, sarebbe già stato abbastanza confuso così, ma ora arriva il peggio.
3) Il BASIC 1.0 dell'M10 non riconosce più di due caratteri per i nomi delle variabili! Puoi comunque usare nomi lunghi, ma il sistema ignora tutti i caratteri dopo i primi due. Potresti teoricamente nominare una variabile "LaserGun", ma il sistema vedrebbe solo "LA", gli altri caratteri sarebbero solo byte sprecati. Ho deciso di liberarmene e di rinominare le mie variabili con nuovi nomi costituiti da due caratteri soli. Ho liberato altra RAM, ma il codice è diventato ancora più ambiguo e oscuro (specialmente perché non mi sono appuntato i nuovi nomi: "Ma dai, tanto me li ricordo!" E invece no! :-DDD ). Non vi dico i bug che ho generato.
4) E ora il colpo di grazia: il BASIC 1.0 non gestisce le istruzioni condizionali annidate! Non esiste l'ENDIF!!! Argh. L'unico modo di ovviare a questo problema era creare ulteriori sottoroutine GOSUB / RETURN.
Ora, fate un bel respiro, usate la vostra immaginazione per applicare tutte queste restrizioni al codice stile QBASIC originale. Divertitevi!
CODICE ORIGINALE STILE QBASIC
IF INSTR(i$, "aprii") > 0 THEN GOSUB APRI
[...]
APRI:
IF INSTR(i$, "valigia") > 0 AND L + VALIGIA = 2 THEN GOSUB VALIGIAAPERTA: RETURN
IF INSTR(i$, "gate") > 0 AND L = 1 THEN PRINT "Chiusa dall'interno, serratura fuori portata. Forse potevo scassinare la serratura, ma avevo bisogno di un metodo di effrazione meno allo scoperto.":RETURN
IF INSTR(i$, "apecar") > 0 AND L = 1 THEN PRINT "Non era il momento giusto per andarmene, avevo una missione!":RETURN
IF INSTR(i$, "recinto") > 0 AND L = 4 THEN
IF RECINTO = 3 THEN PRINT "Il recinto era già aperto.":RETURN
IF RECINTO = 0 THEN PRINT "Provai a muoverlo. Stava cedendo?": RECINTO=1:RETURN
IF RECINTO = 1 THEN PRINT "Si mosse ancora. Sì, stava cedendo!": RECINTO=2:RETURN
IF RECINTO = 2 THEN PRINT "Finalmente! La porta del piccolo recinto si spalancò!": RECINTO=3: PUNTI=PUNTI+5:RETURN
END IF
PRINT "Volevo aprire qualcosa... ma cosa?"
RETURN
CODICE BASIC 1.0 PER L'OLIVETTI M10
695 IFINSTR(I$,"aprii ")>0THENGOSUB1305:RETURN
[...]
1305 IFINSTR(I$,"valigia")>0ANDL+VA=2THENGOSUB1205:RETURN
1310 IFINSTR(I$,"recinto")>0ANDL=1THENPRINT"Locked from the inside, keylock out of reach. Maybe I could pick the lock, but I needed a less exposed method of break-in.":RETURN
1315 IFINSTR(I$,"apecar")>0ANDL=1THENGOSUB4145:RETURN
1320 IFINSTR(I$,"recinto")>0ANDL=4THENGOSUB1355:RETURN
1350 PRINT "Volevo aprire qualcosa... ma cosa?":RETURN
1355 IFRE=3THENPRINT"Il recinto era già aperto.":RETURN
1360 IFRE=0THENPRINT"Provai a muoverlo. Stava cedendo?":RE=1:RETURN
1365 IFRE=1THENPRINT"Si mosse ancora. Sì, stava cedendo!":RE=2:RETURN
1370 IFRE=2THEN PRINT"Finalmente! La porta del piccolo recinto si spalancò!":RE=3:SC=SC+5:RETURN
Tenete presente che ho scelto l'esempio legato al verbo "apri" per rendere le cose più semplici in questo articolo. Se darete un'occhiata al codice, vi renderete conto di quanto comandi come "esamina" abbiano generato un contorto casino di sottoroutine GOSUB/RETURN.
Avevo paura che il codice interpretato in tempo reale si sarebbe rivelato troppo lento per essere giocabile, ma sono stato piacevolmente sorpreso: tutte quelle sottoroutine non hanno rallentato troppo l'esecuzione, forse perché la CPU 80c85 a 2.4Mhz dell'Olivetti M10 è più efficiente della 6510 a 1Mhz del C64. La differenza ha compensato l'assenza di una versione compilata.
Mamma, un vero delirio!