#330 – Coding a Text Adventure feat. DORFLEBEN

#330 – Coding a Text Adventure feat. DORFLEBEN

Westlich vom Haus. Du stehst auf einem freien Feld westlich von einem weißen Haus, dessen Haustür mit Brettern vernagelt ist. Hier ist ein kleiner Briefkasten.“

Ungefähr nach diesem Schema beginnen „Textadventures“ – eine nahezu ausgestorbene Gattung von Videospielen aus der EDV-Steinzeit!

Bild_1

Was kommt euch als erstes in den Sinn, wenn ihr an die „Urväter der Videospielgeschichte“ denkt? „Pong“? „Tennis for Two? „Spacewar!“? Alles korrekt, aber wer denkt heute schon noch an Textadventures? In grauer Vorzeit (also vor ca. 50 Jahren) wurden solche Spiele auf Mainframe-Systemen gespielt. Doch auch auf den deutlich später entwickelten PCs waren Textadventures lange Zeit (bevor sie von Grafik-Adventures abgelöst wurden) ein beliebtes Mittel zum Zeitvertreib. Gut geschriebene Textadventures fühlen sich wie interaktive Bücher an, welche dich zum aktiven Erkunden der Welt einladen. Gerade die Textadventures aus dem Hause Infocom gehören zur Crème de la Crème der literarischen, virtuellen Abenteuer.

Fun Fact: Ok – ich habe etwas übertrieben. Ganz vergessen sind Textadventures nicht, denn auch heute noch gibt es eine ganze Community, welche mit Hilfe verschiedener Programme moderne Textadventures erstellt. Selbst wenn man gute, bzw. komfortable Werkzeuge zur Verfügung hat, ist das ein aufwändiges Unterfangen. Ich würde mal mutmaßen, dass das die gleichen Leute sind, die auch Fan-Fiction verfassen. Absolute Nerds also! 😛

Bild_2

Kritiker sagen, dass Textadventures langweilig sind, weil man so viel Text lesen muss und es keine Bilder gibt. Da ist natürlich was dran. Wer nicht gerne liest, für den sind Textadventures sicherlich nichts. Andererseits gibt es – neben Büchern – wohl kaum ein Medium, in das man so tief eintauchen kann, wie in ein Textadventure. Da es keine grafische Ausgabe gibt, kann diese auch nicht veraltet sein und sich gar nicht mehr ansehen lassen (wie z.B. bei früher Spielen der 3D-Ära). Und ganz unabhängig davon darf man nicht vergessen, dass Textadventures mit dem besten Grafikchip der Welt laufen – der eigenen Vorstellungskraft! 😉

Bild_3

Genug Vorgeplänkel, um was geht es heute? Schon seit geraumer Zeit schwebt mir die Idee im Kopf herum, selbst ein Textadventure zu entwickeln. Die Frage nach dem „Warum?“ kann ich euch leider auch nicht beantworten. Es ist halt so eine Idee, also warum nicht? Doch wie macht man so etwas? Theoretisch lassen sich Textadventures mittlerweile relativ bequem mit Tools wie „Quest“ oder „Squiffy“ erstellen. Das sind Werkzeuge, mit welchen man menügesteuert interaktive Geschichten generieren kann. An und für sich ist das eine gute Sache, allerdings sind die daraus resultierenden Spiele meist an eine Plattform (bzw. die jeweilige Software als Laufzeitumgebung) gebunden und andererseits ist die Frage: Wo bleibt da die Challenge? 😛

Bild_4

Immerhin befinden wir uns hier auf dem „retrololo-Blog“, wo wir uns überwiegend mit „Retro-Themen“ (andere würden sagen altem Schrott) beschäftigen. Da können wir doch nicht einfach auf moderne Hilfsmittelchen zurückgreifen. Also – kein Quest, kein Squiffy und auch kein ChatGPT. Im Idealfall sollte unser Textadventure möglichst abwärtskompatibel sein und auch auf den Retro-PCs im Keller – also unter DOS – laufen. Entsprechend habe ich mich dafür entschieden, ein C-Programm zu schreiben. Oha! Aber das dann wenigstens mit einer modernen Entwicklungsumgebung wie Visual Studio Code oder Eclipse, oder? Natürlich nicht! 😛 Wenn schon hart, dann richtig. Als IDE verwenden wir heute die Software „Borland Turbo C++ 3.0“ von 1992!

Fun Fact: Noch krasser wäre, Assembler als Programmiersprache zu verwenden, aber dazu fehlt mir leider der Skill und wenn ich ehrlich bin, auch Zeit und Nerven! 😀 Ebenso gibt es für C bereits einige gute Beispiele, mit deren Hilfe wir unser Spiel hoffentlich hinbekommen sollten. Ich befürchte, dass das ganze Unterfangen auch ohne Assembler schon abgefahren genug wird…

Bild_5

Die nur ca. 10 MB große Entwicklungsumgebung ist schnell heruntergeladen und entpackt. Bevor wir loslegen können, müssen noch ein paar Pfade und Einstellungen angepasst werden.

Bild_6

Aus heutiger Sicht wirkt das alles schon recht archaisch und auch die DOSBox tut ihr nötigstes, um uns die Entwicklung schwer zu machen. Einige Sonderzeichen wie z.B. eckige oder geschweifte Klammern können nicht direkt, sondern nur per Tastenkombination (ALT + <Nummer>) eingegeben werden. Ich vermute, dass das am deutschen Tastaturlayout liegt, aber wenn ich ehrlich bin, will ich auch gar nicht zu viel Zeit und Energie in die Analyse von „Umgebungsproblemen“ stecken.

Bild_7

Das alles hält uns nicht davon ab, unseren ersten Versuch mit F2 zu speichern und mit F9 zu kompilieren und linken. Dem Code entsprechend tut das Programm nichts, außer dass es für immer läuft. Herzlichen Glückwunsch – wir haben eine Endlosschleife programmiert! 😀

Bild_8

Das ist ausnahmsweise mal etwas gutes, denn das heißt, dass unser Buildprozess grundsätzlich funktioniert. Jetzt können wir mit der eigentlich Entwicklung des Spiels beginnen. Ein paar Variablen hier, ein paar Bildschirmausgaben dort…

Bild_9

…und schon haben wir etwas, was tatsächlich schon ein wenig nach einem Textadventure aussieht!

Fun Fact: An und für sich ist der in der Retro-Entwicklungsumgebung mitgelieferte Editor gar nicht so schlecht. Es gibt viele Tastenkürzel und optisch erinnert mich das alles etwas an das TSO, bzw. den ISPF-Editor von einer Mainframe-Umgebung (siehe Artikel 172) – gewohntes Territorium also! 😉

Bild_10

Natürlich reicht uns eine einfache Bildschirmausgabe nicht. Wir wollen eine virtuelle Welt mit mehreren Räumen, bzw. Orten, in der sich der Spieler frei bewegen kann. Ebenso soll es Objekte geben, die eingesammelt und in einem Inventar verstaut werden können sollen. All diese Dinge müssen vom Programm irgendwie verwaltet werden. Um nicht alles in einzelne Variablen stopfen zu müssen, können wir uns eigene Datentypen in Form von Strukturen zurechtbasteln.

Bild_11

Spätestens jetzt ist der Zeitpunkt gekommen, uns Gedanken über das eigentliche Gamedesign zu machen. Hierfür ist es gut, sich eine Skizze anzufertigen. Besser wäre es, gleich ein ganzes Dokument zu verfassen, in welchem Orte, Charaktere, Geschehnisse, usw. beschrieben sind, aber bei kleineren Spielen tut es manchmal auch eine einfache Karte mit ein paar Details. In unserem Spiel soll es um das Thema „Dorfleben“ (aha – das erklärt den Titel des heutigen Beitrags) mit all seinen Facetten gehen. Wer sich jetzt wundert, ob mein Fotoapparat kaputt ist: Dem ist nicht so. Ich habe das Bild mit voller Absicht etwas verpixelt, schließlich sollt ihr euch ja selbst durch das Abenteuer kämpfen und nicht schon vorab die Lösung wissen. Ich weiß – mega fies! 😉

Not so fun Fact: Ich habe den Fehler gemacht, das „Designdokument“ (um nicht zu sagen das wirre Gekritzel) erst im Lauf der Entwicklung des Spiels zu erstellen, bzw. regelmäßig zu erweitern. Das ist nicht ideal, weil dadurch vergisst man häufig Dinge oder manövriert sich in Sackgassen, die man später mühevoll analysieren, wieder ausbauen, neu designen und letztendlich auch programmieren muss. Was soll ich sagen? Es ist einfach immer gut, einen groben Plan zu haben.

Bild_12

Der grobe Plan steht? Prima, jetzt müssen wir das Ganze nur noch programmieren! Leichter gesagt als getan. Mann – ist das schon wieder lange her, dass ich etwas programmiert habe – und dann auch noch in C! So langsam kommt die Erinnerung an meine Schulzeit zurück, zu der ich tatsächlich mal etwas C-Programmierung gelernt habe. Obwohl das schon Jahre (oder Jahrzehnte?) her ist, erinnere ich mich noch ganz klar an diesen einen Fakt: C ist ein zickiger Zeitgenosse. Hier ist nichts einfach! 😀

Fun Fact: Je mehr ich darüber nachdenke – ganz so lang ist es dann doch nicht her, dass wir etwas in der Sprache C programmiert haben. Vielleicht erinnert sich noch jemand an die Artikel 44 oder 240? 🙂

Bild_13

Für alle Programmierer unter euch: Hier gibt es nicht mal „String“ oder „Bool“ als Datentyp. Dementsprechend muss man sich primitiven Datenarten wie „char“, „int“, „float“ oder „double“ begnügen! Das bereitet uns selbst bei vermeintlich simplen Dingen, wie z.B. dem Umbrechen einer Zeile, sodass ein Wort nicht abgeschnitten wird, ganz schöne Kopfschmerzen. Dabei ist das Problem doch eigentlich schnell erklärt, bzw. gezeigt:

Bild_14

Nur die Lösung dafür ist richtig tricky. Im Endeffekt müssen wird dafür die Zeichen eines Wortes (sowie alles bisherigen in der Zeile befindlichen Wörter, bzw. Zeichen) zählen und anschließend überprüfen, wie viel „Platz“ noch zum Zeilenende vorhanden ist. Ist das Wort zu lang, muss dieses rückwärts bis zum letzten Leerzeichen gelesen und die Zeile an dieser Stelle umgebrochen werden. Das gleiche gilt natürlich dann auch für die Folgezeile, usw. An dieser Stelle vielleicht eine Frage an die Leser mit Programmiererfahrung: Wüsstet ihr auf Anhieb was hier abgeht? Ich verstehe es jetzt schon nicht mehr! 😀

Bild_15

Immerhin – das Ergebnis passt. Jetzt haben wir eine eigene Funktion, mit der wir die Ausgabe auf dem Bildschirm korrekt darstellen können. Ist es nicht erschreckend, was für ein Aufwand das war? Und das alles nur um ein paar Wörter sauber umzubrechen!

Bild_16

Wenn man sich nach längerer Zeit mal wieder mit so einer „Retro-Sprache“ beschäftigt, wird einem klar, wie sehr sich die Programmierung im Lauf der letzten Jahrzehnte verändert hat. Für gefühlt fast alles gibt es heutzutage Funktionen und Codebeispiele im Internet. Die Vorstellung, dass Leute in den Achtzigern und Neunzigern zu Hause mit Büchern gesessen sind, um sich einzelne Befehle selbst zusammenzubauen, wirkt aus heutiger Sicht schon fast unvorstellbar, findet ihr nicht?

Bild_17

Im Lauf der Entwicklung bin ich natürlich noch auf ein paar weitere Herausforderungen gestoßen. So hatte ich z.B. Probleme damit, einzelne Zeichen in Großbuchstaben zu konvertieren, korrekte Werte unabhängig von Groß- und Kleinschreibung miteinander zu vergleichen oder eigene Routinen zur Überprüfung und Reduzierung der Benutzereingabe auf ein bestimmtes Limit zu entwickeln. Ebenso muss man an so ziemlich jeden, theoretisch möglichen Fall denken und diesen programmtechnisch umsetzen. Was passiert, wenn der Nutzer nichts eingibt? Was passiert, wenn er zu viel Text eingibt? Wie verhält sich das Programm, wenn er nur Schrott eingibt? Fragen über Fragen…

Fun Fact: Wieder eine Frage an die Programmierer unter euch: Hättet ihr gewusst, dass man mit den Befehlen „scanf(“%*[^\n]”);“ und anschließend „scanf(“%*c”);“ den Tastaturpuffer der Konsole leeren kann? Das ist z.B. dann notwendig, wenn der User bei einer „Ja/Nein-Abfrage“ anstatt eines „J“ für „Ja“ oder eines „N“ für „Nein“ einfach was anderes wie z.B. „Hugo“ eingibt. Ohne diese Leerung des Puffers fängt das Programm an zu spinnen und nimmt die restlichen Buchstaben nach dem Ersten als Eingabedaten zur weiteren Verarbeitung im Programmablauf. Top! 😀

Bild_18

Doch genug gemeckert. So langsam mausert sich das Spiel und ein paar der schwierigsten Stellen haben wir glücklicherweise bereits entwickelt. Es ist wirklich verblüffend, wie komplex vermeintlich einfache Fragen technisch umgesetzt werden müssen. Was passiert, wenn der Spieler einen Gegenstand nimmt, den er bereits genommen hat? Was passiert, wenn er versucht, sich ein Objekt anzusehen, von dem er eigentlich noch nichts wissen kann, weil er den jeweiligen Ort noch gar nicht erkundet hat? Mit welchen Gegenständen kann der Spieler überhaupt interagieren? Kann er diese mitnehmen? Und falls ja, was sollen sie dann auslösen, bzw. was passiert, wenn man sie mit anderen Objekten kombiniert? Irgendwie ist mir schwindelig…

Bild_19

Haben wir all diese Fragen geklärt? Gut, dann sind wir ja fast fertig, oder? Nicht ganz, denn bei der Vielzahl an möglichen Handlungsschritten sollte man dem Spieler natürlich auch die Möglichkeit geben, seinen Fortschritt zu speichern. Doch wie realisieren wir das? Letztendlich müssen alle vom Spieler in irgendeiner Form veränderbaren Elemente (Räume und Objekte) in eine (binäre) Datei geschrieben und beim Ladevorgang wieder gelesen werden können. Ich kann euch nur eins sagen – diese vermeintlich einfachen Lade- und Speicherroutinen haben definitiv für das ein oder andere graue Haar gesorgt. Ich will gar nicht mehr darüber nachdenken! 😀

Fun Fact: Passend zur Retro-Programmiersprache sind die wichtigsten Objekte in meinem Textadventure in globalen Variablen hinterlegt. Ich weiß, aus heutiger Sicht ist das unter Programmierern verpönt, aber hey – mein Programm, meine Regeln 😛

Bild_20

Wer den Beitrag bis hierhin gelesen hat, den wird es nicht wundern, dass mich die Entwicklung doch einiges mehr an Zeit und Nerven gekostet hat, als es mir lieb gewesen wäre. Ich hatte z.B. ewig mit einem fiesen Bug zu kämpfen, welcher dafür gesorgt hat, dass ab und zu – gefühlt rein zufällig – ein Grill im Inventar des Spielers aufgepoppt ist. Sehr bizarr! Vielleicht hat eine Künstliche Intelligenz mein Spiel übernommen? Vielleicht bin ich auch einfach nur kein besonders begabter Programmierer und verstehe meinen eigenen Code nicht mehr. Wer weiß?

Fun Fact: Der amerikanische Spieleentwickler „Al Lowe“ hat mal auf die Frage hin, wie man ein Spiel programmiert, folgendes gesagt: „You sit in front of your computer and stare at the screen, and a year later you get up.“ Viel treffender hätte ich es nicht formulieren können! 😀

Bild_21

Auch hat ein Speicherproblem mit dem Borland Turbo C++ Compiler mich fast an den Rand eines Nervenzusammenbruchs gebracht. Ich konnte gegen Ende der Entwicklung das Programm nur noch kompilieren, wenn ich die Schritte „linken“ und „kompilieren“ voneinander getrennt habe. Also erst kompilieren (Alt + F9) und dann linken (Alt + C und dann „L“). Ein automatischer „Make“ mit beiden Schritten in einem Aufwasch (F9) benötigt wohl auf Grund der Anzahl an verwendeten Literalen zu viele Ressourcen. Und selbst dann musste ich gegen Ende ganz schön an Text-Konstanten und weiteren Abfragen sparen, weil ich immer wieder in den „Out of Memory“-Fehler gelaufen bin. Sieht so aus, als hätten wir die Retro-Entwicklungsumgebung (also den Uralt-Compiler innerhalb der DOSBox) bis an ihre absoluten Grenzen gebracht! 😀

Bild_22

Das alles ist jetzt aber nicht mehr wichtig, denn mittlerweile ist „DORFLEBEN“ fertig! Laut Compiler sind es ca. 3.300 Zeilen Code, aber wenn man die Leerzeilen und eingebundenen Bibliotheken abzieht, sind es vermutlich „nur“ noch ca. 2.600 Lines of Code. Unfassbar – und das alles für eine (bis auf das Byte exakt) 100 Kilobyte große bzw. kleine EXE-Datei, welche ein paar Zeilen Text auf dem Bildschirm ausgibt. Programmierer sind schon eine seltsames Völkchen… 😀

Bild_23

Wie es sich für ein vernünftiges Textadventure der alten Schule gehört, gibt es mehrere, maximal alberne Möglichkeiten zu sterben! 😛 Keine Angst, ich war gnädig und man behält im Falle des virtuellen Ablebens zumindest sein Inventar, sowie alle erreichten Fortschritte. Generell habe ich mir Mühe gegeben, dem Spiel – trotz des offensichtlich simplen Spielprinzips – viel Persönlichkeit und Charme zu verleihen. Anstatt eines einfachen „Das geht hier nicht.“ wird dem Spieler z.B. eine möglichst abwechslungsreiche, teils sogar zufällig ausgewählte Antwort zurückgegeben, wenn er eine vermeintlich unlogische Kombination von Befehlen ausprobiert.

Bild_24

Und? Hat sich der Aufwand gelohnt? Schwer zu sagen. Das Ergebnis einer kreativen Arbeit ist immer so viel mehr als die Summe seiner Einzelteile. Für einen erfahrenen Programmierer wirkt der Code vermutlich stümperhaft. Ein erfahrener Gamedesigner würde Story und Spielfluss vermutlich nur mitleidig belächeln und ein abgebrühter Adventure-Spieler könnte sich zurecht über die kurze Spieldauer und die viel zu leichten Rätsel beschweren. Aber wisst ihr was? Das alles ist mir egal! 😀 Ich bin trotzdem glücklich darüber, dass ich das durchgezogen habe. So etwas wollte ich einfach schon immer mal machen. Wieder ein Punkt von der „Bucket List“ erledigt. 🙂

Bild_25

Wenn man weiß wie, lässt sich das Spiel in fünf Minuten durchspielen. Ganz schön frustrierend, wenn man die vielen Stunden bedenkt, die ich an Aufwand rein gesteckt habe! Dennoch wäre ich mal so optimistisch, dass es euch mindestens eine Stunde (oder sogar mehr?) kosten sollte, das Spiel durchzuspielen. Es hängt halt immer davon ab, wie gründlich man sucht und wie viel man entdecken will. So ist das eben mit Adventures.

Bild_26

Also, holt Bleistift und Papier raus, zeichnet euch eine Karte und wagt euch auf ein ländliches Abenteuer in „DORFLEBEN“! 🙂

Fun Fact: Die Umrandung des Titelbildschirms wurde mit sog. „Box-drawing Characters“ realisiert. Dabei handelt es sich um darstellbare Zeichen, welche im ASCII-Standard genau für diesen Zweck implementiert wurden. Das interessiert heute keine Sau mehr, ich weiß! 🙂

Bild_27

Das Spiel könnt ihr euch hier herunterladen und nativ auf einem PC mit 32-Bit-Windows-Betriebssystem (oder natürlich unter DOS) laufen lassen. Alternativ könnt ihr das Spiel auch auf 64-Bit-Systemen in einem Emulator wie z.B. DOSBox spielen. Ein vorgefertigtes Paket findet sich hier.

Bild_28

So richtig authentisch lässt sich das Spiel natürlich auf echter Hardware, wie z.B. diesem alten DOS-Computer aus Artikel 282 mit 10 MHz 8088-CPU, 640 kB RAM und einem monochromen Bildschirm zocken. Das nenne ich mal retro! 😉

Bild_29

Doch unabhängig davon, wo oder wie ihr das Spiel spielt: Es würde mich jedenfalls sehr freuen, wenn ihr es spielt und mir ggf. Feedback gibt, falls euch Fehler oder Probleme auffallen. Ich habe gehört, es gibt sogar eine Belohnung, wenn man das Spiel zu 100% abschließt! 😉

Und jetzt wünsche ich euch viel Spaß mit DORFLEBEN!

In diesem Sinne – bis die Tage, ciao!

Kommentar verfassen