Hmm, wo genau hast du das her, dass man keine digitalen Spiele damit umsetzen darf? Und "digitales Spiel" ist jetzt wirklich nicht so einfach zu definieren. Ich glaube, das Problem liegt da eher allgemein an den Inhalten, also das man ohne Erlaubnis nicht einfach die Monster benutzen darf, die nicht unter der OGL stehen. Der Generator selbst ist ja davon erst mal ausgenommen, der generiert ja nur aus den Templates. Das generierte Produkt und die Templates selbst könnten allerdings unter irgendwas fallen, das stimmt.
Ich bin noch mal einen großen Schritt weiter gekommen. So weit, dass ich euch schon mal die erste Version zum herum spielen geben kann. Ich hab den Download des Codes mal oben am Ende des Startposts eingefügt. Ich hab da auch eine Readme drin liegen, wo beschrieben wird, wie man die Templates zusammen baut. Ist aber alles noch WIP.
Was dazu gekommen ist:
Ich kann jetzt 2 verschiedene Template-Formate einlesen:
.txt Dateien wie bisher.
.py Dateien, also script-Dateien, mit denen sich die Texte VOLLKOMMEN dynamisch erzeugen lassen. Damit kann man quasi ALLES umsetzen.
Python Beispiel, eine zufällige Textauswahl für die Rocky Desert:
import random
#set the seed to a hex coord specific one, so we always get the same random numbers for this hex and therefore, generate the same content:
random.seed(hex.h+hex.v)
s = ('' +
'<style>' +
'body {' +
' background-image: url("../img/rockyDesert.jpg");' +
' background-color: rgb(142,89,62);' +
' }' +
'</style>' +
'<h1 style="color: rgb(70,45,30)">Felswüste</h1>' )
hexPage.write(s)
texts = list()
start = '<p class="description">'
end = '</p>'
#Case 1:
t = (start +
'Eine brennende Hitze herrscht in dieser kargen Landschaft. Überall nur trockene, rote Gesteinsbrocken.' +
end)
texts.append(t)
#Case 2:
t = (start +
'Der Boden dieser Gegend ist mit Geröll und Gestein bedeckt. Die hohen Temperaturen setzen den meisten Kreaturen hier mächtig zu.' +
end)
texts.append(t)
#Case 3:
t = (start +
'Überall nur Steine. Eine Wüste voller Steine und ohne Wasser, ein lebensfeindlicher Ort.' +
end)
texts.append(t)
#Case 4:
t = (start +
'Eine flache Ebene, in der über einem harten Steinboden nur ab und zu größere Gesteinsbrocken zu sehen sind.<br/>' +
'Die Landschaft sieht aus, als wäre sie von einer anderen Welt.' +
end)
texts.append(t)
hexPage.write(random.choice(texts))
Also sind zwei Extreme schon eingebaut: Extreme simplizität in Form der Textdateien, und extreme Komplexität mit den .py scripten. Mit den .py Scripten könnte man jetzt quasi einen Drachen platzieren, in den umgebenden Hex-Feldern Markierungen setzen und dann in anderen Scripten diese Markierungen auslesen und darauf wieder Text generieren. Allerdings ist das Ganze etwas zu kompliziert zu handhaben. Ich lasse es nur drin, um die volle Flexibilität zu gewährleisten.
Die eigentliche Richtung in die ich gehen möchte ist, mächtige, aber einfach zu bedienende Funktionen einzubauen. Eine dieser Funktionen ist jetzt schon drin, ein einfacher Zufallsgenerator. Wenn man für einen Landschaftstyp verschiedene Beschreibungen hat, aus denen zufällig ausgewählt werden soll, dann muss man sie einfach nur folgendermaßen bennenen und in den template/content Ordner packen:
"Farmland.1.txt", "Farmland.2.txt", "Farmland.3.txt".
Das funktioniert genau so auch mit Feature Texten, Hexfeld-Individuellen Beschreibungstexten und auch allen anderen Dateiarten. Man kann also auch zufällig verschiedene Scripte ausführen lassen.
Die eigentliche Arbeit ist jetzt aber, eine Zwischenform zwischen den einfachen Textdateien und den Scripten zu schaffen. Dafür nehme ich .xml Dateien. Die Grundlagen dafür habe ich schon gelegt, sie werden schon eingelesen, aber ich bin mir noch nicht ganz sicher, wie ich das Weltendesign dahinter konstruiere. Einen Ansatz habe ich ja schon weiter oben gepostet, aber das ist noch nicht ganz ausgereift.
Soo, bin jetzt noch ein gutes Stück weiter gekommen. Ich hab jetzt "Events" eingebaut. Mit diesen kann man dann z.B. Encounter generieren. Das ganze funktioniert mit XML Dateien die in einem bestimmten Ordner liegen.
Als Beispiel hier mal mein Test-XML-File:
<?xml version="1.0" encoding="UTF-8"?>
<generichexcrawl>
<events>
<conditions>
<or>
<hasattribute name="Village" range="2" />
<hasattribute name="Town" range="2" />
<hasattribute name="Capital" range="2" />
</or>
</conditions>
<event tableWeight="1">
<conditions>
<hasvalue name="CR" min="1" max="20"/>
</conditions>
<html>
<h1>Goblin Überfallkommando</h1>
<p class="stats">1W4 x <a href="http://www.d20pfsrd.com/bestiary/monster-listings/humanoids/goblin">Goblin (CR 1/3, XP 135)</a><br/>
Startdistanz: 2+1W6 Felder<br/>
</p>
<p class="description">
Ihr werdet von einem Goblin Überfallkommando aus dem Hinterhalt angegriffen.<br/>
<p class="option">
Perception gegen DC 20 -> Fail: Goblins bekommen Überraschungsrunde.
</p>
</p>
<p class="tactic">Taktik<br/>
Wenn mehr als 6 Felder entfernt: Angriff mit Kurzbogen.<br/>
Ansonsten: Angriff mit Kurzschwert
</p>
<p class="loot">Schatz: 1W100<br/>
1-50: 260gpeq / goblin<br/>
51-100: Nichts brauchbares
</p>
</html>
</event>
<event tableWeight="1">
<conditions>
<hasvalue name="CR" min="1" max="20"/>
</conditions>
<html>
<h1>Goblin Lager</h1>
<p class="stats">4 + 1W4 x <a href="http://www.d20pfsrd.com/bestiary/monster-listings/humanoids/goblin">Goblin (CR 1/3, XP 135)</a><br/>
</p>
<p class="option">
Perception gegen DC 20<br/>
<a class="option.success" href="#lagerEntdeckt" >Erfolg</a>
<a class="option.fail" href="#lagerUnentdeckt" >Misserfolg</a>
</p>
<p id="lagerEntdeckt" class="description">
Ihr bemerkt vor euch ein kleines Goblinlager.
<p class="option">
Stealth gegen DC 9<br/>
<a class="option.success" href="#anschleichen" >Erfolg</a><br/>
<a class="option.fail" href="#lagerUnentdeckt" >Misserfolg</a>
</p>
<a href="#Kampf">Alternative: Direkt angreifen</a>
</p>
<p id="lagerUnentdeckt" class="description">
Ihr stolpert ungeschickt direkt in ein kleines Goblinlager. Die Goblins sind aber genau so überrascht wie ihr, alle ziehen ihre Waffen und greifen euch an.<br/>
<i>Startdistanz um 4 verringern.</i>
<a href="#Kampf">Weiter zum Kampf</a>
</p>
<p id="lagerUnentdeckt" class="description">
Ihr schleicht euch erfolgreich langsam an das Lager heran.<br/>
<i>Ihr könnt, müsst aber nicht, die Startdistanz um bis zu 4 verringern.</i>
<a href="#Kampf">Weiter zum Kampf</a>
</p>
<p id="Kampf" class="tactic">Taktik<br/>
Startdistanz: 4+1W6 Felder<br/>
<br/>
Wenn mehr als 6 Felder entfernt: Angriff mit Kurzbogen.<br/>
Ansonsten: Angriff mit Kurzschwert
</p>
<p class="loot">Schatz: 1W100<br/>
1-50: 260gpeq / goblin<br/>
51-100: Nichts brauchbares
</p>
</html>
</event>
</events>
</generichexcrawl>
Zur Erklärung:
<conditions> leitet immer einen Bedingungsblock ein. In diesem können Bedingungen geschachtelt verbaut werden, die dann, wenn für ein Hexfile geschaut wird, welche Events es dort geben kann, geprüft werden. Folgende gibt es bisher:
<and/or/nor/nand/not>
normale logik. Ein and block ist z.B. immer dann Wahr, wenn alle darin enthaltenen Bedingungen Wahr sind. nor und nand sind jeweils eine kombination aus einem not und einem and bzw. or, der bequemlichkeit wegen. Vielleicht bau ich auch noch ein xor ein, mal schauen. Kommen wir zu den interessanteren:
<hasattribute name = "" range="">
Ist immer dann Wahr, wenn ein Hexfeld innerhalb der angegebenen Distanz ein Attribut mit diesem Namen hat. Im Moment werden die Features noch einfach als Attribut an die Hexfelder geklemmt. Deshalb kann man das nehmen, wenn man schauen möchte, ob auf dem gleichen Hex (range = 0) oder in der Umgebung (range > 0) bestimmte Features existieren. Die range ist bisher noch nicht funktional, man kann also bisher nur auf das aktuelle Hex testen. Aber das kommt noch.
<hasvalue name="" value="" min="" max="">
Damit kann man konkrete Werte von Attributen abfragen. Entweder man nutzt einen konkreten Wert, indem man "value" ausfüllt, oder man benutzt min und/oder max Zahlen um einen Wertebereich anzugeben. Man könnte z.B. sagen:
<hasvalue name="h" max="10"> und dann würde es nur dann Wahr sein, wenn die horizontale Koordinate des Hexfeldes maximal = 10 ist. Ich plane hier auch noch einen range parameter ein zu bauen, ist aber WIP.
<probability value="">
Dies ist Zufällig Wahr oder nicht Wahr. Man kann eine Wahrscheinlichkeit angeben, mit der es Wahr sein soll. So lassen sich seltene Monster darstellen, nicht nicht immer in bestimmten Terrain vorkommen. <probability value="0.01"> bedeutet z.B., das das Event nur bei 1% der Hexfelder überhaupt vorkommen kann.
So, weiter gehts. Wie man im Beispiel sieht, gibt es ein "events" und zwei "event" elemente. Die Bedingungen die man direkt unter "events" definiert hat, gelten für alle weiter unten definierten "event" elemente. Das habe ich deshalb so gemacht, damit man gemeinsam benutzte Bedingungen nicht immer wieder neu schreiben muss. Man kann z.B. so global für Goblins bestimmen, in welchen Landschaftstypen sie vorkommen sollen. Und dann aber bei den einzelnen Encountern noch mal weiter einschränken, das sie z.B. nur bei bestimmten Schwierigkeitsgraden oder so vorkommen sollen. Oder mit unterschiedlichen Wahrscheinlichkeiten. Ok, schauen wir uns ein Event an:
<event tableWeight=""> Das tableWeight attribut gibt an, wie stark es in der Begegnungstabelle eines Hexes vorkommen kann, wenn es denn dafür in Frage gekommen ist. Die Begegnungstabelle ist immer eine W100 Tabelle, die Würfelrange für ein bestimmtes Event wird dann Anteilig nach seinem tableWeight berechnet. Unter dem <event> element kann man noch einmal conditions einbauen, oder aber eben mit html den Encounter formulieren.
Wenn das event bei einem Hexfeld vorkommt, wird für dieses eine Datei angelegt und von der Begegnungstabelle des Hexfeldes auf diese Datei verlinkt. Der Start und End html-tag werden vom Generator mit einem Header und einem Footer versehen, in dem ein Link zurück auf das Hexfeld platziert wird.
Soo, das wars erstmal. Es gibt leider noch nichts neues zum Ausprobieren, weil ich erst noch ein paar Baustellen und Bugs beheben möchte. Aber das Konzept funktioniert soweit schon ganz gut. Es wird... Es wird ;)
Edit: hab doch noch wenigstens die live demo aktualisiert. Schaut mal bei den Dörfern, da sind die encounter von oben immer da.