18.2.2 - Charakterbogen: Die Erklärung
Wir beginnen mit dem Charakterbogen von dem aus auch alles andere gesteuert wird. Es kann hilfreich sein wenn du dir in einem weiteren Fenster das komplett fertige Makro anzeigen lässt, damit du auch immer den kompletten Code vor Augen hast und die Zusammenhänge besser erkennen kannst (das gilt auch bei allen anderen Makros die wir noch schreiben). Damit du die Erklärungen besser nachvollziehen kannst schauen wir uns schon mal das fertige Ergebnis an.
Gut, erstelle zuerst ein neues Makro mit dem Namen "charbogen" im Library-Token. Damit die Spieler auch ihre Charakterbögen aufrufen können, erstelle ein weiteres Makro im Kampagnenfenster (Campaign), nenne es "Charakterbogen", und rufe damit das eigentliche Charakterbogen-Makro auf:
Code: Select all
[macro("charbogen@Lib:makros"): ""]
Jetzt aber zum Charakterbogen, den wir in verschiedene Bereiche gliedern:
- Zuerst der Kopfbereich mit dem Tokenbild, dem Charakternamen und der Charakterklasse.
- Der nächste Bereich darunter beinhaltet die Charakterattribute und die Grundwerte für den Kampf.
- Anschließend kommt die Anzeige der Hitpoints inkl. eines Balkens, damit der aktuelle Stand auch graphisch angezeigt wird.
- Die nächsten zwei Bereiche zeigen die Waffen- und Zauberliste.
- Ganz unten kommt dann noch eine Fußzeile in der wir das Inventar, den Charaktereditor und den Initiativewurf verlinken.
Im Charakterbogen prüfen wir ganz oben mit
assert() ob der User überhaupt einen Token verkörpert hat (impersonated). Wenn nicht wird hier direkt abgebrochen und eine Fehlermeldung erscheint:
Code: Select all
[h: assert(hasImpersonated(), "<span style='font-weight: bold'>Fehler!</span> Du musst erst einen Token verkörpern.", 0)]
Jetzt notieren wir den Code für das Fenster (wir benutzen ein
Frame mit dem Namen "charbogen") inkl. des grundsätzlichen HTML-Aufbaus. Alles was wir danach an Code schreiben kommt in das body-Element, also zwischen
<body> und
</body>.
Code: Select all
[frame("charbogen", "width=260; height=400; temporary=1"):
{
<html>
<head>
<title>
Charakterbogen
</title>
</head>
<body style='text-align: center; background-color: a4c8a4'>
</body>
</html>
}
]
Nun sind die einzelnen Bereiche an der Reihe. Nach jedem fertiggestellten Bereich kannst du zum Testen den Charakterbogen aufrufen und dir anschauen wie dieser im Moment aussieht.
Der Kopfbereich
Eine kleine Zwischenbemerkung: Das Festlegen von Größenangaben kann schwierig, sogar eine echte Herausforderung sein, denn oft weißt du am Anfang noch nicht wie viel Platz die untergeordneten Inhalte benötigen. Daher wirst du die Größenangaben wahrscheinlich zwischendurch immer mal wieder anpassen müssen, oder legst sie vielleicht erst später fest. Bei unserem kleinen Mini-Framework stimmen aber alle Angaben, denn ich habe sie vorher schon abgemessen.
Jetzt der Kopfbereich. Da wir mit
strformat() arbeiten wollen um den Stack-Speicher von MapTool etwas zu entlasten, müssen wir vorher die Variablen für Charakterbild, Charaktername und Charakterklasse definieren:
Code: Select all
[h: char.bild = getTokenImage(50)]
[h: char.name = getImpersonatedName()]
[h: char.klasse = Klasse]
Kommen wir zur Tabelle für den Kopfbereich mit
strformat(). Beachte, dass ich den Anfang der Funktion
[r: strformat(" und das Ende der Funktion
", variable1, variable2, variable3)] jeweils in einer separaten Zeile notiert habe. Das macht es einfach übersichtlicher, und MapTool macht das nichts aus.
Code: Select all
[r: strformat("
<table style='border-spacing: 0px; background-color: #008000; border: 2px solid #008000; width: 220'>
<tr>
<td style='text-align: center; padding: 6px'>
<img src='%s'>
</td>
<td style='color: #ffffff; width: 150'>
<span style='font-size: 14pt; font-weight: bold'>%s</span>
<br>
Klasse: %s
</td>
</tr>
</table>
", char.bild, char.name, char.klasse)]
Charakterwerte
Als nächstes der Bereich mit den Charakterattributen und Kampfwerten, auch hier legen wir erst die Variablen für die Werte fest. Allerdings wollen wir, dass der User bei einem Mausklick auf den Namen eines Charakterattributs gleich eine Probe auf das Attribut würfeln kann. Daher erstellen wir mit
macroLink() auch Links zu unserem Probenmakro "probeAttribut", das wir später noch einfügen. Außerdem geben wir bei den Links Daten an das Probenmakro weiter, nämlich den Namen des jeweiligen Attributs als
String. Wofür das gut ist siehst du ebenfalls später.
Code: Select all
[h: char.kraft.link = macroLink("Kraft", "probeAttribut@Lib:makros", "all", "Kraft")]
[h: char.geschick.link = macroLink("Geschick", "probeAttribut@Lib:makros", "all", "Geschick")]
[h: char.klugheit.link = macroLink("Klugheit", "probeAttribut@Lib:makros", "all", "Klugheit")]
[h: char.kraft = Kraft]
[h: char.geschick = Geschick]
[h: char.klugheit = Klugheit]
[h: char.angriff = Angriff]
[h: char.verteidigung = Verteidigung]
[h: char.ruestung = Ruestung]
Und jetzt die Tabelle zur Ausgabe, wieder mit
strformat():
Code: Select all
[r: strformat("
<table style='border-spacing: 0px; border-left: 2px solid #008000; border-right: 2px solid #008000; background-color: #ffffff; width: 220'>
<tr>
<td valign='middle'>
<table style='border-spacing: 0px'>
<tr>
<td>
<span style='color: #000000; text-decoration: none'>%s:</span>
</td>
<td style='font-weight: bold; text-align: right'>
%s
</td>
</tr>
<tr>
<td>
<span style='color: #000000; text-decoration: none'>%s:</span>
</td>
<td style='font-weight: bold; text-align: right'>
%s
</td>
</tr>
<tr>
<td>
<span style='color: #000000; text-decoration: none'>%s:</span>
</td>
<td style='font-weight: bold; text-align: right'>
%s
</td>
</tr>
</table>
</td>
<td style='width: 20px'>
</td>
<td>
<table style='border-spacing: 0px'>
<tr>
<td>
Angriff:
</td>
<td style='font-weight: bold; text-align: right'>
%s
</td>
</tr>
<tr>
<td>
Verteidigung:
</td>
<td style='font-weight: bold; text-align: right'>
%s
</td>
</tr>
<tr>
<td>
Rüstung:
</td>
<td style='font-weight: bold; text-align: right'>
%s
</td>
</tr>
</table>
</td>
</tr>
</table>
", char.kraft.link, char.kraft, char.geschick.link, char.geschick, char.klugheit.link, char.klugheit, char.angriff, char.verteidigung, char.ruestung)]
Die HP-Anzeige
Kommen wir zur Hitpoint-Anzeige, die wir unter den Charakterwerten mittig platzieren wollen. Die Anzeige soll die aktuellen und maximalen HP in Zahlen und zusätzlich in Form eines Balkens darstellen. Der Balken soll außerdem die Farbe wechseln sobald die aktuellen HP auf 50% und 25% sinken.
Fangen wir wieder mit ein paar Variablen an. Zuerst müssen wir herausfinden wie viel Prozent unserer HP wir noch haben, das geht mit einfacher Prozentrechnung. Wir dividieren also die aktuellen HP durch die maximalen HP und multiplizieren das Ergebnis mit 100. Danach runden wir das Ganze noch.
Code: Select all
[h: hp.prozent = (HP / HPmax) * 100]
[h: hp.prozent = round(hp.prozent)]
Mit zwei IF-Anweisungen bestimmen wir die Balkenfarbe. Besitzt der Charakter weniger als 51% der HP ist die Balkenfarbe orange (#FF8000), ansonsten grün (#28a328). Die zweite IF-Anweisung prüft nochmal ob der Charakter weniger als 26% seiner HP besitzt, und setzt die Farbe in diesem Fall auf rot (#FF0000).
Code: Select all
[h,if(hp.prozent < 51): hp.farbe = "#FF8000"; hp.farbe = "#28a328"]
[h,if(hp.prozent < 26): hp.farbe = "#FF0000"; hp.farbe = hp.farbe]
Jetzt noch schnell die Variablen für die Links zu den Makros um HP hinzuzufügen oder abzuziehen. Als Linktext nutzen wir mit HTML maskierte Zeichen, nämlich den Doppelpfeil nach oben (⇑) und den Doppelpfeil nach unten (⇓).
Code: Select all
[h: hp.plus.link = macroLink("⇑", "hpPlus@Lib:makros", "all")]
[h: hp.minus.link = macroLink("⇓", "hpMinus@Lib:makros", "all")]
Der erste Teil der Tabelle für die HP-Anzeige:
Code: Select all
[r: strformat("
<table style='border-spacing: 0px; border-left: 2px solid #008000; border-right: 2px solid #008000; background-color: #ffffff; padding: 6px 0px 10px 0px; width: 220' cellpadding='0'>
<tr>
<td>
</td>
<td>
<span style='font-weight: bold'>HP:</span> %s/%s
</td>
"cellpadding" kennst du noch nicht. Das ist ein HTML-Attribut mit dem sich der Abstand vom Inhalt einer Zelle zum Rand festlegen lässt. In Fenstern fügt MapTool automatisch so einen Abstand ein, was in den meisten Fällen auch in Ordnung ist, aber beim HP-Balken stören würde. Da wir diesen Abstand auch nicht mit der CSS-Eigenschaft "padding" entfernen können, müssen wir also "cellpadding" mit dem Wert "0" notieren.
Schauen wir uns nun die nächste Zelle der Tabelle an, die zur Darstellung des HP-Balkens genutzt wird:
Code: Select all
<td style='border: 1px solid %s; width: 100'>
<table style='border-spacing: 0px'>
<tr>
<td style='background-color: %s; width: %s'>
</td>
</tr>
</table>
</td>
Diese Zelle ist unser kompletter HP-Balken, stellt also die maximalen HP dar, weswegen sie unbedingt eine Breite von 100 Pixeln (100%) haben muss. In dieser Zelle erstellen wir eine weitere Tabelle mit nur einer Zelle und ohne Inhalt. Diese Tabelle stellt die aktuellen HP dar, um ihre Breite festzulegen benutzen wir also die Variable "hp.prozent" und für ihre Hintergrundfarbe die Variable "hp.farbe". Das wird deutlicher wenn wir uns den Rest der kompletten Tabelle anschauen:
Code: Select all
<td style='text-align: right'>
( <span style='text-decoration: none; color: #000000'>%s</span> / <span style='text-decoration: none; color: #000000'>%s</span> )
</td>
<td>
</td>
</tr>
</table>
", HP, HPmax, hp.farbe, hp.farbe, hp.prozent)]
Beachte, dass wir die Variable "hp.farbe" zweimal nutzen: für den Rahmen des kompletten HP-Balkens und als Hintergrundfarbe für die Tabelle, die den Balken für die aktuellen HP darstellt.
Der Waffenbereich
Nun ist die Waffenliste an der Reihe. Beginnen wir mit einer Art Überschrift für den gesamten Waffenbereich um die Waffen optisch etwas vom oberen Teil abzutrennen. Auf der rechten Seite fügen wir Links ein um neue Waffen hinzuzufügen oder zu löschen. Definieren wir erst die Variablen für die Links:
Code: Select all
[h: neu.waffe.link = macroLink("Neu", "waffeNeu@Lib:makros")]
[h: loesche.waffe.link = macroLink("Löschen", "waffeLoeschen@Lib:makros")]
Und jetzt die Tabelle für die Überschrift:
Code: Select all
[r: strformat("
<table style='border-spacing: 0px; color: #ffffff; border-left: 2px solid #008000; border-right: 2px solid #008000; background-color: #008000; width: 220'>
<tr>
<td style='font-weight: bold; width: 110'>
Waffen
</td>
<td style='text-align: right; width: 110' valign='bottom'>
<span style='font-size: 10pt; color: #ffffff; text-decoration: none'>(%s | %s)</span>
</td>
</tr>
</table>
", neu.waffe.link, loesche.waffe.link)]
Anschließend eine weitere Tabelle als Überschrift der eigentlichen Waffenliste. Da wir in dem kleinen Charakterbogen allerdings nicht so viel Platz haben benutzen wir Abkürzungen. "B" steht für "Bonus", "A" für "Angriff", "V" für "Verteidigung" und "S" für "Schaden". Und weil wir hier keine Variablen benötigen geben wir das einfach als
String aus:
Code: Select all
[r: "<table style='border-left: 2px solid #008000; border-right: 2px solid #008000; background-color: #ffffff; width: 220'>
<tr style='font-style: italic; border-bottom: 1px solid'>
<td style='width: 115'>
Waffe
</td>
<td style='text-align: center; width: 20'>
B
</td>
<td style='text-align: center; width: 25'>
A
</td>
<td style='text-align: center; width: 25'>
V
</td>
<td style='text-align: center; width: 35'>
S
</td>
</tr>
</table>"]
Und noch eine Tabelle, jetzt mit der Auflistung der Waffen. Allerdings nur der erste Teil ohne Zeilen und Zellen:
Code: Select all
[r: "<table style='border-spacing: 0px; border-left: 2px solid #008000; border-right: 2px solid #008000; background-color: #ffffff; width: 220'>"]
Wie es mit der Tabelle weitergeht hängt davon ab ob der Charakter überhaupt Waffen dabei hat oder nicht. Wir prüfen mit einer IF-Anweisung also die Waffenanzahl. Dafür rufen wir in der
String Property List des Propertys "Waffen" den Wert für den Schlüssel "WaffenAnzahl" ab. Ist die Anzahl "0" wird eine Tabellenzeile mit einer Zelle und einer entsprechenden Meldung ausgegeben. Ist die Anzahl aber nicht "0", hat der Charakter also mindestens eine Waffe dabei, passiert gar nichts.
Code: Select all
[r,if(getStrProp(Waffen, "WaffenAnzahl") == 0), code:
{
[r: "<tr>
<td style='text-align: center; width: 220'>
Keine Waffen vorhanden
</td>
</tr>"]
};{}
]
Wenn eine oder mehrere Waffen vorhanden sind sollen diese nun mit ihren verschiedenen Werten (Name, Bonus, Angriff, Verteidigung, Schaden) jeweils in einer eigenen Tabellenzeile aufgelistet werden. Das machen wir mit einer
Count-Schleife. Die Anzahl der Durchläufe bestimmen wir logischerweise mit der Anzahl der Waffen. Sind also keine Waffen vorhanden, gibt es keinen einzigen Durchlauf und es wird nichts ausgegeben. Vor der Schleife definieren wir noch die neue Variable "num" als Waffennummer.
Code: Select all
[h: num = 1]
[r,count(getStrProp(Waffen, "WaffenAnzahl"), ""), code:
{
}
]
Kommen wir zum Inhalt der Count-Schleife. Bei jedem Durchlauf müssen wir zuerst alle Variablen festlegen die wir für die aktuelle Waffe benötigen:
- Der Name der Waffe
- Der Waffenbonus, der bei jeder Waffe zum Grundangriffs- und Grundverteidigungswert dazugerechnet wird.
- Der Schaden den die Waffe verursacht. In unserem System macht jede Waffe entweder 1W6, 2W6 oder 3W6 Schaden.
- Der endgültige Angriffswert der Waffe, der sich aus dem Grundangriffswert und dem Waffenbonus zusammensetzt.
- Der endgültige Verteidigungswert der Waffe, der sich aus dem Grundverteidigungswert und dem Waffenbonus zusammensetzt.
- Ein Link um beim Mausklick auf den Angriffswert gleich das Angriffsmakro aufzurufen. Bei diesem Link geben wir die den Text "Angriff" und die Waffennummer als String-List an das Angriffsmakro weiter.
- Ein Link um beim Mausklick auf den Verteidigungswert gleich das Verteidigungsmakro aufzurufen. Bei diesem Link geben wir den Text "Verteidigung" und die Waffennummer als String-List an das Verteidigungsmakro weiter.
Die Waffen in unserem Property "Waffen" folgen einem bestimmten Schema bei dem die Waffennummer eine wichtige Rolle spielt (Waffe1Name, Waffe1Bonus, etc.). Wenn wir jetzt die verschiedenen Waffenwerte abrufen wollen, müssen wir auch bei jedem Durchlauf diese Waffennummer um eins erhöhen, sonst werden ja immer nur die Daten der gleichen Waffe abgerufen. Aus diesem Grund haben wir vor der Schleife die Variable "num" mit der Waffennummer erstellt. Mit dieser Nummer und
strformat() (dieses Mal die Variante mit geschweiften Klammern) können wir bei jedem Durchlauf die Daten der nächsten Waffe abrufen. Dafür müssen wir nur die Nummer am Ende eines jeden Durchlaufs um eins erhöhen. Definieren wir erst mal die benötigten Variablen:
Code: Select all
[h: waffe.name = getStrProp(Waffen, strformat("Waffe%{num}Name"))]
[h: waffe.bonus = getStrProp(Waffen, strformat("Waffe%{num}Bonus"))]
[h: waffe.schaden = getStrProp(Waffen, strformat("Waffe%{num}Schaden")) + "W6"]
[h: waffe.angriff = Angriff + waffe.Bonus]
[h: waffe.verteidigung = Verteidigung + waffe.Bonus]
[h: angriff.link = macroLink(waffe.angriff, "probeKampf@Lib:makros", "all", strformat("Angriff, %s", num))]
[h: verteidigung.link = macroLink(waffe.verteidigung, "probeKampf@Lib:makros", "all", strformat("Verteidigung, %s", num))]
Natürlich müssen wir auch noch dafür sorgen, dass in jedem Durchlauf eine Tabellenzeile mit den Werten der aktuellen Waffe ausgegeben wird:
Code: Select all
[r: strformat("
<tr>
<td style='width: 115'>
%s
</td>
<td style='text-align: center; width: 20'>
%s
</td>
<td style='text-align: center; width: 25'>
<span style='font-weight: bold; color: #000000; text-decoration: none'>%s</span>
</td>
<td style='text-align: center; width: 25'>
<span style='font-weight: bold; color: #000000; text-decoration: none'>%s</span>
</td>
<td style='text-align: center; width: 35'>
%s
</td>
</tr>
", waffe.name, waffe.Bonus, angriff.link, verteidigung.link, waffe.schaden)]
Am Anfang war die Waffennumer "num" 1. Jetzt erhöhen wir die Nummer um eins, damit im nächsten Durchlauf nicht "Waffe1Name, Waffe1Bonus, etc." abgerufen wird, sondern "Waffe2Name, Waffe2Bonus, etc.":
Damit ist die Count-Schleife fertig. Unter der Schleife müssen wir aber jetzt noch die Tabelle schließen. Also:
Der Zauberbereich
Nach der Waffenliste kommt nun der Bereich für die Zauber. Auch hier gibt es wieder eine Überschrift, und auch hier fügen wir Links hinzu um neue Zauber einzutragen oder bestehende Zauber zu löschen. Beginnen wir also erneut mit dem Definieren der Variablen für die Links:
Code: Select all
[h: neu.zauber.link = macroLink("Neu", "zauberNeu@Lib:makros")]
[h: loesche.zauber.link = macroLink("Löschen", "zauberLoeschen@Lib:makros")]
Und die Tabelle:
Code: Select all
[r: strformat("
<table style='border-spacing: 0px; color: #ffffff; border-left: 2px solid #008000; border-right: 2px solid #008000; background-color: #008000; width: 220'>
<tr>
<td style='font-weight: bold; width: 110'>
Zauber
</td>
<td style='text-align: right; width: 110' valign='bottom'>
<span style='font-size: 10pt; color: #ffffff; text-decoration: none'>(%s | %s)</span>
</td>
</tr>
</table>
", neu.zauber.link, loesche.zauber.link)]
Bei der Zauberliste gibt es keine weitere Überschrift, denn als einzigen Zauberwert gibt es nur den Namen, sonst nichts. Erstellen wir also den Anfang der Tabelle für die Zauberliste:
Code: Select all
[r: "<table style='border-spacing: 0px; border-left: 2px solid #008000; border-right: 2px solid #008000; background-color: #ffffff; width: 220'>"]
Auch hier müssen wir wieder mit einer IF-Anweisung prüfen ob überhaupt Zauber vorhanden sind, und wenn nicht eine Tabellenzeile mit der entsprechenden Meldung ausgeben. Da es sich bei der Zauberliste, also dem Property "Zauber", um eine einfache
String-List handelt, nutzen wir die Funktion
listCount(), die uns als Rückgabewert die Anzahl der Einträge in der
String-List liefert. Als Parameter wird die
String-List angegeben.
Code: Select all
[r,if(listCount(Zauber) == 0), code:
{
[r: "<tr>
<td style='text-align: center; width: 220'>
Keine Zauber vorhanden
</td>
</tr>"]
};{}
]
Falls Zauber vorhanden sind wollen wir diese nun Zeile für Zeile auflisten. Dafür benutzen wir eine FOREACH-Schleife, die den entsprechenden Code für jeden Eintrag in der Liste erstellt:
Code: Select all
[r,foreach(item, Zauber, ""), code:
{
[r: strformat("
<tr>
<td style='border-bottom: 1px solid; width: 220'>
%s
</td>
</tr>
", item)]
}
]
Unter der Schleife schließen wir wieder die Tabelle:
Die Fußzeile
Damit ist der Charakterbogen fast fertig. Zum Schluss kommt noch die Fußzeile, die Links zu dem Charaktereditor, dem Inventar und dem Initiativewurf enthält. Also erst wieder die Variablen definieren:
Code: Select all
[h: charedit.link = macroLink("Charaktereditor", "charedit@Lib:makros")]
[h: ini.link = macroLink("Initiative", "iniWurf@Lib:makros", "all")]
[h: inventar.link = macroLink("Inventar", "inventar@Lib:makros")]
Und jetzt die Ausgabe der Fußzeile:
Code: Select all
[r: strformat("
<table style='border-spacing: 0px; border-left: 2px solid #008000; border-right: 2px solid #008000; background-color: #008000; width: 220'>
<tr>
<td style='text-align: left; width: 110'>
<span style='color: #ffffff; text-decoration: none'>%s</span>
</td>
<td style='text-align: right; width: 110'>
<span style='color: #ffffff; text-decoration: none'>%s | %s</span>
</td>
</tr>
</table>
", charedit.link, ini.link, inventar.link)]
Jetzt haben wir es hinter uns, der komplette Charakterbogen ist fertig! Du kannst den Bogen auch schon aufrufen, nur die Links zu den anderen Makros funktionieren eben noch nicht, die müssen wir ja erst noch basteln.