Macros for Dummies - A MapTool Macro-Tutorial (german)

Doc requests, organization, and submissions

Moderators: dorpond, trevor, Azhrei

Post Reply
Thargun
Giant
Posts: 188
Joined: Sun Sep 14, 2014 4:27 am

Re: Macros for Dummies - A guide to MapTool-Macros (german)

Post by Thargun »

9.4 - Spezielle Input Typen

LABEL

Erstellt eine statische Kennzeichnung und kann z. B. als Überschrift oder Hinweistext verwendet werden. Eine Variable muss zwar angegeben werden, diese wird allerdings ignoriert und es wird ihr auch kein Wert zugewiesen.

Mögliche Optionen:

TEXT=FALSE
Der Anfangswert wird nicht angezeigt. Der Standardwert ist "TEXT=TRUE".

SPAN=TRUE
Erlaubt der Kennzeichnung die Ausdehnung in die gesamte Breite des Eingabefensters. Der Titel der Kennzeichnung wird dabei versteckt und nur als Tooltip angezeigt. Der Standardwert ist "SPAN=FALSE".

Beispiel:

Code: Select all

[h: status = input(
  "label1|Die erste Kennzeichnung|Titel 1|LABEL",
  "label2|Die zweite Kennzeichnung|Titel 2|LABEL|TEXT=FALSE",
  "label3|Die dritte Kennzeichnung|Titel 3|LABEL|SPAN=TRUE"
)]
[h: abort(status)]
Image


PROPS

Erstellt eine umrandete Box die mehrere Textfelder enthalten kann. Der Anfangswert muss zwingend eine String Property Liste sein. Die Schlüssel der Liste sind die Titel der Textfelder, und die den Schlüsseln zugeordneten Werte sind die Anfangswerte der Textfelder. In der angegebenen Variable wird ebenfalls eine String Property Liste gespeichert, die dann die aktuellen Werte der Textfelder enthält.

Mögliche Optionen:

SETVARS=SUFFIXED
Speichert zusätzlich jeden Eintrag der String Property Liste in einer eigenen Variable. Die zusätzlichen Variablen werden nach den Schlüsseln der Liste gefolgt von einem Unterstrich (_) benannt. Der Standartwert ist "SETVARS=NONE".

Diese Option besitzt eine weitere Einstellungsmöglichkeit:

SETVARS=UNSUFFIXED
Speichert zusätzlich jeden Eintrag der String Property Liste in einer eigenen Variable. Die zusätzlichen Variablen werden nach den Schlüsseln der Liste benannt.

SPAN=TRUE
Erlaubt der Box die Ausdehnung in die gesamte Breite des Eingabefensters. Der Standardwert ist "SPAN=FALSE".

Beispiele:

Code: Select all

[h: status = input(
  "props.list|Name=Schwert; Typ=Klingenwaffe; Schadensbonus=2|Waffeneditor|PROPS"
)]
[h: abort(status)]
[r: props.list]

Code: Select all

[h: status = input(
  "props.list|Name=Schwert; Typ=Klingenwaffe; Schadensbonus=2|Waffeneditor|PROPS|SETVARS=SUFFIXED"
)]
[h: abort(status)]
Waffenname: [r: Name_] - Waffentyp: [r: Typ_] - Schadensbonus: [r: Schadensbonus_]

Code: Select all

[h: status = input(
  "props.list|Name=Schwert; Typ=Klingenwaffe; Schadensbonus=2|Waffeneditor|PROPS|SETVARS=UNSUFFIXED"
)]
[h: abort(status)]
Waffenname: [r: Name] - Waffentyp: [r: Typ] - Schadensbonus: [r: Schadensbonus]
Image


TAB

Erstellt im Eingabefenster ein oder mehrere Tabs (Registerreiter), die jeweils verschiedene Eingabefelder enthalten können. Hierbei müssen einige Dinge beachtet werden:
  • Bei Tabs wird kein Titel angegeben.
  • Alle Eingabefelder innerhalb eines Tabs werden als ein Parameter, also ein String notiert, und somit zusammen statt einzeln in doppelte Anführungszeichen eingeschlossen.
  • Die Eingabefelder innerhalb eines Tabs werden nicht durch Kommata (,), sondern durch doppelte Rauten (##) voneinander getrennt.
  • Zusätzlich zu den Variablen der einzelnen Eingabefelder werden in den Variablen der Tabs alle Eingabefelder innerhalb dieses Tabs als String Property Liste gespeichert. Dabei werden statt Semikolons (;) doppelte Rauten (##) als Trennzeichen verwendet.
Mögliche Optionen:

SELECT=TRUE
Zeigt diesen Tab bei Aufruf des Eingabefensters an. Der Standardwert ist "SELECT=FALSE".

Beispiele:

Code: Select all

[h: status = input(
  "tab0 | Waffe || TAB",
    "waffe.name|Bitte eingeben|Name|TEXT ## 
    waffe.typ|Bitte eingeben|Typ|TEXT ##
    waffe.bonus|Bitte eingeben|Schadensbonus|TEXT",
  "tab1 | Inventar || TAB",
    "item1|Bitte eingeben|Gegenstand 1|TEXT ## 
    item2|Bitte eingeben|Gegenstand 2|TEXT ##
    item3|Bitte eingeben|Gegenstand 3|TEXT"
)]
[h: abort(status)]
Waffenname: [r: waffe.name] - Erster Inventargegenstand: [r: item1]

Code: Select all

[h: status = input(
  "tab0 | Waffe || TAB",
    "waffe.name|Bitte eingeben|Name|TEXT ## 
    waffe.typ|Bitte eingeben|Typ|TEXT ##
    waffe.bonus|Bitte eingeben|Schadensbonus|TEXT",
  "tab1 | Inventar || TAB|SELECT=TRUE",
    "item1|Bitte eingeben|Gegenstand 1|TEXT ## 
    item2|Bitte eingeben|Gegenstand 2|TEXT ##
    item3|Bitte eingeben|Gegenstand 3|TEXT"
)]
[h: abort(status)]
Inhalt der Variable tab0 (Waffentab): [r: tab0]
Image

Thargun
Giant
Posts: 188
Joined: Sun Sep 14, 2014 4:27 am

Re: Macros for Dummies - A guide to MapTool-Macros (german)

Post by Thargun »

9.5 - Noch mehr input()

Variablen in Sub-Parametern

Als Sub-Parameter von Eingabefeldern lassen sich ohne Probleme auch Variablen oder Properties einfügen. Das funktioniert wie bei der einfachen Kombination von Code und Text, da die eigentlichen Parameter der input()-Funktion ja als String notiert werden. Ein Beispiel:

Code: Select all

[h: feld1.titel = "Das erste Eingabefeld"]
[h: feld2.anfangswert = "Zweites Eingabefeld"]

[h: status = input(
  "eingabe1|Erstes Eingabefeld|"+feld1.titel+"|TEXT",
  "eingabe2|"+feld2.anfangswert+"|Das zweite Eingabefeld|TEXT"
)]
[h: abort(status)]
Das ist eine praktische Sache. Wenn du z. B. ein Makro zum Editieren von Charakterattributen schreibst, kannst du die Attribute, also die Token-Properties, bereits als Anfangswert für die Eingabefelder festlegen.


Weitere Möglichkeiten

Mit der input()-Funktion lässt sich noch mehr anstellen, z. B. Bilder im Eingabefenster einfügen, aber für heute soll es genug sein. Wenn dich deine Neugier jetzt aber vorantreibt, ist die Wiki-Seite zu input() eine gute Anlaufstelle.

Thargun
Giant
Posts: 188
Joined: Sun Sep 14, 2014 4:27 am

Re: Macros for Dummies - A guide to MapTool-Macros (german)

Post by Thargun »

9.6 - Usereingaben überprüfen

Etwas solltest du dir immer merken: Wenn User bei einer Eingabe etwas falsch eingeben können, wird irgendjemand das früher oder später auch tun! Das ist schon fast ein unumstößliches Gesetzt, genauso wie ein Apfel irgendwann vom Baum fallen wird.

Stelle dir vor du schreibst ein Makro für einen Angriffswurf bei dem der User zusätzlich einen Bonus angeben kann. Was passiert wohl wenn der User statt einer Zahl einen Buchstaben eingibt, und das Makro dann versucht damit zu rechnen? Genau, es erscheint eine unverständliche Fehlermeldung im Chat. Oder was ist wenn der Bonus einen bestimmten Wert nicht überschreiten darf? Wie stellst du sicher, dass der User sich daran hält?

Zum Glück lässt sich das alles überprüfen. Vorher schauen wir uns aber noch an, was passieren kann wenn tatsächlich ein Fehler bei der Eingabe gefunden wurde.


Die Fehlermeldung

Liegt ein Fehler bei der Usereingabe vor ist es oft sinnvoll das Makro abzubrechen. Dafür könntest du wieder die Funktion abort() benutzen. Dann sieht der User allerdings nicht was er überhaupt falsch gemacht hat. Besser geeignet ist die Funktion assert(), die ebenfalls das Makro abbricht, aber zusätzlich noch eine passende, von dir festgelegte Fehlermeldung ausgibt. Das Format:

Code: Select all

assert(Bedingung, Meldung, Präfix)
Bedingung
Eine Bedingung wie sie auch in einer IF-Anweisung vorkommt. Trifft die Bedingung zu (True), wird das Makro weiter ausgeführt. Trifft sie nicht zu (False), wird das Makro abgebrochen. Statt die vollständige Bedingung anzugeben, reicht auch eine "1" für True oder eine "0" für False.

Meldung
Die Fehlermeldung die ausgegeben wird, wenn die Bedingung nicht zutrifft. Die Fehlermeldung wird übrigens auch dann ausgegeben wenn die Roll Option hide benutzt wird.

Präfix
Gibt an ob die Meldung "Makroverursachter Fehler" vor der eigentlichen Fehlermeldung angezeigt werden soll. Der Standardwert ist "1" (True). Setze es auf "0" (False), wenn dieser Präfix nicht angezeigt werden soll.

Zwei Beispiele, bei denen die eingegebene Zahl nicht höher als 5 sein darf:

Code: Select all

[h: status = input(
  "eingabe|0|Bonus|TEXT"
)]
[h: abort(status)]
[h: assert(eingabe <= 5, "Fehler! Die eingegebene Zahl ist groesser als 5.", 0)]
Die eingegebene Zahl ist 5 oder kleiner.

Code: Select all

[h: status = input(
  "eingabe|0|Bonus|TEXT"
)]
[h: abort(status)]
[h,if(eingabe <= 5): testwert = 1; testwert = 0]
[h: assert(testwert, "Fehler! Die eingegebene Zahl ist groesser als 5.", 0)]
Die eingegebene Zahl ist 5 oder kleiner.
Auf leeres Textfeld prüfen

Bei Textfeldern solltest du immer erst prüfen ob es überhaupt eine Eingabe gibt. Zwar wird normalerweise ein Anfangswert angezeigt, der kann aber auch vom User gelöscht werden, so dass das Eingabefeld einfach leer ist. Und wenn in der Variable eines Textfelds kein Wert gespeichert ist kann das in vielen Situationen zu Problemen führen.

Wenn in einer Variable kein Wert gespeichert ist enthält die Variable quasi einen leeren String. So kannst du die Überprüfung dann vornehmen (achte auf Zeile 5):

Code: Select all

[h: status = input(
  "eingabe|0|Bonus|TEXT"
)]
[h: abort(status)]
[h,if(eingabe == ""): pruefwert = 0; pruefwert = 1]
[h: assert(pruefwert, "Fehler! Es wurde nichts eingegeben", 0)]
Deine Eingabe ist [r: eingabe].
Bei Eingabefeldern für Zahlen, z. B. bei einem Bonus für Angriffswürfe, kann es (muss es aber nicht) bei einem leeren Eingabefeld auch nützlich sein die fehlende Eingabe einfach durch eine "0" zu ersetzen. Somit sparst du dir die Fehlermeldung und das Makro kann normal weiterarbeiten:

Code: Select all

[h: status = input(
  "eingabe|0|Bonus|TEXT"
)]
[h: abort(status)]
[h,if(eingabe == ""): eingabe = 0; eingabe = eingabe]
Deine Eingabe ist [r: eingabe].
Auf Zahlen prüfen

Zum Überprüfen ob in einer Variable auch wirklich eine Zahl gespeichert ist, kannst du die Funktion isNumber() benutzen. Als Parameter wird die Variable mit dem gespeicherten Wert angegeben. Handelt es sich dabei um eine Zahl, gibt die Funktion "1" (True) zurück. Wenn nicht gibt sie "0" (False) zurück.

Code: Select all

[h: status = input(
  "eingabe|0|Bonus|TEXT"
)]
[h: abort(status)]
[h: pruefwert = isNumber(eingabe)]
[h: assert(pruefwert, "Fehler! Die Eingabe ist keine Zahl.", 0)]
Deine Eingabe: [r: eingabe]
Auf ganze Zahlen prüfen

Was ist aber wenn der User eine Kommazahl eingibt, z. B. "1.45", das Makro aber eine ganze Zahl benötigt um ohne Fehler durchzulaufen? Mit dem cleveren Einsatz der Funktion round() lässt sich auch das überprüfen:

Code: Select all

[h: status = input(
  "eingabe|0|Bonus|TEXT"
)]
[h: abort(status)]
[h,if(eingabe != round(eingabe)): pruefwert = 0; pruefwert = 1]
[h: assert(pruefwert, "Fehler! Die Eingabe ist keine ganze Zahl.", 0)]
Deine Eingabe: [r: eingabe]
Mehrere Eingabefelder prüfen

Falls es sich anbietet kannst du auch mehrere Felder gleichzeitig auf eine bestimmte Bedingung überprüfen:

Code: Select all

[h: status = input(
  "eingabe1|0|Bonus|TEXT",
  "eingabe2|0|Bonus|TEXT"
)]
[h: abort(status)]
[h,if(isNumber(eingabe1) == 0 || isNumber(eingabe2) == 0): pruefwert = 0; pruefwert = 1]
[h: assert(pruefwert, "Fehler! In einem der Eingabefelder wurde keine Zahl eingetragen.", 0)]
Die eingegebenen Zahlen sind [r: eingabe1] und [r: eingabe2].
Die richtige Reihenfolge

Wenn du eine Eingabe auf mehrere Bedingungen überprüfst, solltest du dabei immer eine gewisse Reihenfolge einhalten um Fehler zu vermeiden:

1. Auf leere Eingabe prüfen
2. Auf Zahlen prüfen
3. Auf ganze Zahlen prüfen

Das folgende Beispiel prüft zuerst ob es sich bei der Eingabe um eine Zahl handelt, und dann ob es sich um eine ganze Zahl handelt:

Code: Select all

[h: status = input(
  "eingabe|0|Bonus|TEXT"
)]
[h: abort(status)]

[h: pruefwert = isNumber(eingabe)]
[h: assert(pruefwert, "Fehler! Die Eingabe ist keine Zahl.", 0)]

[h,if(eingabe != round(eingabe)): pruefwert = 0; pruefwert = 1]
[h: assert(pruefwert, "Fehler! Die Eingabe ist keine ganze Zahl.", 0)]
Gibt der User jetzt einen Buchstaben ein ist das kein Problem, denn als erstes wird auf eine Zahl geprüft und das Makro dann abgebrochen. Wenn allerdings zuerst auf eine ganze Zahl geprüft würde, und danach erst ob es sich überhaupt um eine Zahl handelt, könnte die Funktion round() nichts mit dem Buchstaben anfangen und würde einen Fehler im Makro verursachen.

Aus diesem Grund solltest du es auch vermeiden gleichzeitig mehrere Bedingungen zu überprüfen. Als Beispiel:

Code: Select all

[h,if(isNumber(eingabe) == 0 || eingabe != round(eingabe)): pruefwert = 0; pruefwert = 1]
Auch hier wäre Text in der Variable "eingabe" fatal. isNumber() hätte damit zwar keine Probleme, aber round() würde in diesem Fall erneut einen Fehler im Makro verursachen.
Last edited by Thargun on Tue Sep 29, 2015 4:21 pm, edited 1 time in total.

Thargun
Giant
Posts: 188
Joined: Sun Sep 14, 2014 4:27 am

Re: Macros for Dummies - A guide to MapTool-Macros (german)

Post by Thargun »

10 - Bastelstunde I: Ein universelles Würfelmakro

10.1 - Das Makro

Du hast bisher schon richtig viel gelernt, aber alles nur mit kleinen Beispielen ausprobiert. Daher schreiben wir jetzt als Übung ein Würfelmakro, damit du mal siehst wie die verschiedenen Dinge zusammenspielen. Mit dem Makro wirst du eine beliebige Anzahl von beliebigen Würfeltypen würfeln können. Außerdem kannst du einen Bonus und einen Malus festlegen, und entscheiden wer das Ergebnis sehen kann.

Image

Hier das gesamte Makro. Was da genau passiert schauen wir uns anschließend im Detail an.

Code: Select all

[h: status = input(
  "wuerfel.anzahl|1|Wuerfelanzahl|TEXT|WIDTH=2",
  "wuerfel.seiten|3,4,6,8,10,12,20,100|Wuerfelseiten|LIST|SELECT=2 VALUE=STRING",
  "label1|-----||LABEL|SPAN=TRUE",
  "bonus|0|Bonus|TEXT|WIDTH=2",
  "malus|0|Malus|TEXT|WIDTH=2",
  "label2|-----||LABEL|SPAN=TRUE",
  "sichtbarkeit|Oeffentlich,Nur Spielleiter,Spieler und Spielleiter|Sichtbarkeit|RADIO"
)]
[h: abort(status)]

[h,if(wuerfel.anzahl == ""): wuerfel.anzahl = 0; wuerfel.anzahl = wuerfel.anzahl]
[h,if(bonus == ""): bonus = 0; bonus = bonus]
[h,if(malus == ""): malus = 0; malus = malus]

[h,if(isNumber(wuerfel.anzahl) == 0 || isNumber(bonus) == 0 || isNumber(malus) == 0): pruefwert = 0; pruefwert = 1]
[h: assert(pruefwert, "Fehler! In die Eingabefelder duerfen nur Zahlen eingetragen werden.", 0)]

[h,if(wuerfel.anzahl != round(wuerfel.anzahl) || bonus != round(bonus) || malus != round(malus)): pruefwert = 0; pruefwert = 1]
[h: assert(pruefwert, "Fehler! In die Eingabefelder duerfen nur ganze Zahlen eingetragen werden.", 0)]

[h: wuerfel.ergebnis = roll(wuerfel.anzahl, wuerfel.seiten)]
[h: endergebnis = wuerfel.ergebnis + bonus - malus]
[h,if(endergebnis < 0): endergebnis = 0; endergebnis = endergebnis]
[h: modifikator = bonus - malus]

[h: ausgabe = strformat("Wurf mit %sW%s: %s - Modifikator: %s - Endergebnis: %s", wuerfel.anzahl, wuerfel.seiten, wuerfel.ergebnis, modifikator, endergebnis)]

[switch(sichtbarkeit), code:
  case 0:
    {
      [r: ausgabe]
    };
  case 1:
    {
      [r,g: ausgabe]
    };
  case 2:
    {
      [r,g,s: ausgabe]
    };
  default:
    {}
]

Thargun
Giant
Posts: 188
Joined: Sun Sep 14, 2014 4:27 am

Re: Macros for Dummies - A guide to MapTool-Macros (german)

Post by Thargun »

10.2 - Die Erklärung

Code: Select all

[h: status = input(
  "wuerfel.anzahl|1|Wuerfelanzahl|TEXT|WIDTH=2",
Als erstes erstellen wir mit input() das Eingabefenster, und eine Zeile darunter auch gleich das erste Textfeld, in dem der User die Anzahl der Würfel, mit denen er würfeln will, angeben kann. Mit der Option WIDTH=2 schmälern wir es etwas, damit das Feld nicht so klobig wirkt.

Code: Select all

  "wuerfel.seiten|3,4,6,8,10,12,20,100|Wuerfelseiten|LIST|SELECT=2 VALUE=STRING",
Im nächsten Eingabefeld, einer Liste, kann sich der User entscheiden mit welcher Art von Würfeln er würfeln möchte, also wie viele Seiten die Würfel haben sollen (W6, W10, W20 etc.). Da unser hypothetisches Rollenspielsystem hauptsächlich W6 verwendet, legen wir mit der Option SELECT=2 fest, dass der dritte Eintrag in der Liste (denke daran: Der Index der Liste beginnt bei "0") beim Aufruf des Eingabefensters angezeigt wird. Und das ist die "6". Außerdem verwenden wir "VALUE=STRING", damit nicht der Index des ausgewählten Eintrags, sondern gleich der Eintrag selbst in der Variable gespeichert wird, und wir damit dann später direkt weiterarbeiten können.

Code: Select all

 "label1|-----||LABEL|SPAN=TRUE",
Hier fügen wir zur optischen Abstufung per LABEL eine kleine Trennlinie ein, und verwenden die Option SPAN=TRUE damit die Linie ganz links im Eingabefenster beginnt.

Code: Select all

[h,if(bonus == ""): bonus = 0; bonus = bonus]
[h,if(malus == ""): malus = 0; malus = malus]
Hier erstellen wir zwei weitere Textfelder. Der User kann hier einen Bonus eingeben, der später zum Würfelergebnis hinzugerechnet wird, oder ein Malus, der vom Ergebnis abgezogen wird.

Code: Select all

  "label2|-----||LABEL|SPAN=TRUE",
  "sichtbarkeit|Oeffentlich,Nur Spielleiter,Spieler und Spielleiter|Sichtbarkeit|RADIO"
Noch eine Trennlinie, und dann schließlich die Auswahl über Radio Buttons wer das Würfelergebnis später sehen kann.

Code: Select all

)]
[h: abort(status)]
Unser Eingabefenster ist fertig, also schließen wir die input()-Funktion und fügen dann noch abort() hinzu, damit das Makro abgebrochen wird falls der User auf "Abbrechen" klickt.

Code: Select all

[h,if(wuerfel.anzahl == ""): wuerfel.anzahl = 0; wuerfel.anzahl = wuerfel.anzahl]
[h,if(bonus == ""): bonus = 0; bonus = bonus]
[h,if(malus == ""): malus = 0; malus = malus]
Mit diesen Anweisungen prüfen wir ob vielleicht eines der Textfelder leer ist. Falls ein Textfeld leer ist, setzen wir automatisch eine "0" ein, damit das Makro sich später nicht verrechnet. Falls aber nicht, bleibt der eingegebene Wert wie er ist.

Code: Select all

[h,if(isNumber(wuerfel.anzahl) == 0 || isNumber(bonus) == 0 || isNumber(malus) == 0): pruefwert = 0; pruefwert = 1]
[h: assert(pruefwert, "Fehler! In die Eingabefelder duerfen nur Zahlen eingetragen werden.", 0)]

[h,if(wuerfel.anzahl != round(wuerfel.anzahl) || bonus != round(bonus) || malus != round(malus)): pruefwert = 0; pruefwert = 1]
[h: assert(pruefwert, "Fehler! In die Eingabefelder duerfen nur ganze Zahlen eingetragen werden.", 0)]
Mit diesen Anweisungen überprüfen wir ob in den Textfeldern auch wirklich Zahlen stehen und ob es auch ganze Zahlen sind. Wenn in irgendeinem Textfeld keine Zahl oder keine ganze Zahl eingetragen wurde, brechen wir das Makro mit assert() ab und lassen eine passende Fehlermeldung ausgeben.

Code: Select all

[h: wuerfel.ergebnis = roll(wuerfel.anzahl, wuerfel.seiten)]
Hier benutzen wir die roll()-Funktion um den eigentlichen Würfelwurf durchzuführen. Als Parameter geben wir dabei die Würfelanzahl und die Seiten der Würfel an, die wir ja mit dem Eingabefenster schon in Variablen gespeichert haben. Das Würfelergebnis speichern wir ebenfalls in einer Variable.

Code: Select all

[h: endergebnis = wuerfel.ergebnis + bonus - malus]
Jetzt rechnen wir noch den Bonus zum Würfelergebnis hinzu und ziehen den Malus ab. Das Endergebnis speichern wir in einer neuen Variable.

Code: Select all

[h,if(endergebnis < 0): endergebnis = 0; endergebnis = endergebnis]
Wenn der vom User eingegebene Malus sehr hoch war, könnte das Endergebnis auch im negativen Bereich liegen (z. B. "-5"). In unserem Rollenspiel wollen wir aber keine Würfelergebnisse unter "0" haben. Wir prüfen also ob das Ergebnis tatsächlich unter "0" liegt, und falls das der Fall ist, setzen wir es einfach auf "0". Falls nicht bleibt das Ergebnis wie es ist.

Code: Select all

[h: modifikator = bonus - malus]
Den endgültigen Modifikator zum Würfelwurf wollen wir später ebenfalls im Chat anzeigen. Also rechnen wir diesen Modifikator aus und speichern ihn in einer Variable.

Code: Select all

[h: ausgabe = strformat("Wurf mit %sW%s: %s - Modifikator: %s - Endergebnis: %s", wuerfel.anzahl, wuerfel.seiten, wuerfel.ergebnis, modifikator, endergebnis)]
Mit Hilfe der der Funktion strformat() legen wir nun endgültig fest was nach dem Würfelwurf in der Chatbox angezeigt werden soll, und speichern das alles in einer Variable.

Bevor es weitergeht noch schnell die Erklärung zu zwei neuen Roll Options die wir gleich verwenden werden:
  • gm (wird mit "g" abgekürzt) - Die Ausgabe wird nur dem Spielleiter angezeigt.
  • self (wird mit "s" abgekürzt) - Die Ausgabe wird nur dem Spieler angezeigt der das Makro ausgeführt hat.

Code: Select all

[switch(sichtbarkeit), code:
  case 0:
    {
      [r: ausgabe]
    };
  case 1:
    {
      [r,g: ausgabe]
    };
  case 2:
    {
      [r,g,s: ausgabe]
    };
  default:
    {}
]
Im Eingabefenster konnte der User über Radio Buttons festlegen wer das Würfelergebnis letztendlich sehen darf. Die Variable dieser Auswahl, in der der Index des ausgewählten Radio Buttons gespeichert ist, wird nun mit einer switch-Anweisung überprüft. Je nachdem wie der Index lautet wird der Inhalt der Variable "ausgabe", die den Ausgabetext für die Chatbox enthält, nun entweder allen angezeigt, nur dem Spielleiter, oder dem Spielleiter und dem Spieler der das Makro ausgeführt hat.

Fertig! Und? War doch gar nicht so schwierig, oder?

Thargun
Giant
Posts: 188
Joined: Sun Sep 14, 2014 4:27 am

Re: Macros for Dummies - A guide to MapTool-Macros (german)

Post by Thargun »

11 - Codeschleifen

11.1 - COUNT: Runden drehen wie im Karussell

Mit der Codeschleife COUNT, eine Roll Option, kannst du einen oder mehrere Makro-Befehle beliebig oft wiederholen. Wozu das gut sein soll? Du erinnerst dich doch bestimmt noch an das Würfelmakro im letzten Kapitel. Damit konnte der User z. B. mit beliebig vielen W6 würfeln, und zum Schluss hast du ihm das Endergebnis in der Chatbox präsentiert. Was du aber nicht konntest, war das Ergebnis der einzelnen Würfe anzuzeigen. Mit COUNT geht das.

Schauen wir uns zuerst das Format der einfachen Variante an:

Code: Select all

[count(Wiederholungen): Makrobefehl]
Als Beispiel wollen wir zehn mal hintereinander mit einem 6-seitigen Würfel würfeln. Kombiniere COUNT mit result, damit das Ergebnis jedes Wurfs in der Chatbox ausgegeben wird:

Code: Select all

[h: wurf.anzahl = 10]
[r,count(wurf.anzahl): 1d6]
In der Praxis wirst du diese einfache Variante jedoch kaum benötigen. Interessant wird es erst wenn du COUNT mit der Roll Option CODE kombinierst, damit du gleich mehrere Befehle wiederholen kannst. Erst wieder das Format:

Code: Select all

[count(Wiederholungen), code:
  {
    [Befehl 1]
    [Befehl 2]
    [Befehl 3]
  }
]
Damit du das in Aktion siehst, schreiben wir ein kleines Würfelmakro um mit beliebig vielen 6-seitigen Würfeln zu würfeln. Anschließend nehmen wir das Makro Zeile für Zeile auseinander.

Code: Select all

[h: status = input(
  "anzahl|0|Anzahl W6|TEXT"
)]
[h: abort(status)]

[h: ergebnis.liste = ""]
[h: endergebnis = 0]

[h,count(anzahl), code:
  {
    [wurf.ergebnis = roll(1, 6)]
    [ergebnis.liste = listAppend(ergebnis.liste, wurf.ergebnis)]
    [endergebnis = endergebnis + wurf.ergebnis]
  }
]

Endergebnis: [r: endergebnis] --- Einzelergebnisse: [r: ergebnis.liste]
Zeile 1-4:
Das Eingabefenster mit einem Textfeld, um die Anzahl der Würfel einzugeben.

Zeile 6:
Hier erstellen wir eine leere Variable. Leer deshalb, weil wir später die einzelnen Würfelergebnisse als String-Liste darin speichern möchten.

Zeile 7:
Erstellung einer weiteren Variable, die später das Endergebnis aller Würfelwürfe enthalten soll. Damit wir damit rechnen können weisen wir ihr schon mal den Wert "0" zu.

Zeile 9:
Hier beginnt die COUNT-Anweisung. Als Parameter wird die Anzahl der Würfel angegeben, die gewürfelt werden sollen. Diese Anzahl steckt ja bereits in der Variable des Textfeldes, weswegen wir diese auch hier als Parameter angeben.

Zeile 11:
Hier wird mit einem W6 gewürfelt und das Ergebnis in einer Variable gespeichert.

Zeile 12:
Das eben gewürfelte Ergebnis fügen wir der String-Liste hinzu (die Variable dafür haben wir ja schon in Zeile 6 erstellt). Dafür benutzen wir die Funktion listAppend(), bei der wir als Parameter die Variable angeben in der die String-Liste gespeichert ist, und den neuen Wert welcher der Liste hinzugefügt werden soll.

Zeile 13:
Hier rechnen wir das eben gewürfelte Ergebnis zu den bereits gewürfelten Ergebnissen hinzu. Die Variable dafür haben wir in Zeile 7 erstellt.

In der COUNT-Schleife würfeln wir also bei jedem Durchlauf mit einem W6, fügen das Ergebnis einer Liste hinzu, und addieren das Ergebnis auch noch zu Ergebnissen aus anderen Durchläufen. Ich denke das Prinzip sollte jetzt klar sein. Probiere es aus!


roll.count - Eine spezielle Variable

roll.count gehört zu den Spezial-Variablen und ist nur innerhalb einer COUNT-Schleife nutzbar. In roll.count wird immer der aktuelle Durchlauf der COUNT-Schleife gespeichert, wobei mit "0" begonnen wird. Im ersten Durchlauf hat roll.count also den Wert "0", im zweiten Durchlauf den Wert "1", im dritten Durchlauf den Wert "2", usw.

Ein kleines Beispiel:

Code: Select all

[r,count(5): "Durchlauf " + roll.count]
Es gibt verschiedene Situationen in denen das nützlich sein kann, du wirst schon merken wenn es soweit ist. Abschließend trotzdem noch ein Beispiel für eine Waffe mit Flächenwirkung, bei der für fünf getroffene Personen der Schaden separat ausgewürfelt werden soll:

Code: Select all

[count(5), code:
  {
    [h: schaden = 1d6+2]
    [h: ziel = roll.count + 1]
    Treffer [r: ziel]: [r: schaden] Schadenspunkte
  }
]
Eine kleine Übung

Wie wäre es? Schnappe dir das Würfelmakro aus dem letzten Kapitel, baue eine COUNT-Schleife ein, und speichere so die einzelnen Würfelergebnisse in einer String-Liste. Dann ändere noch die Chatausgabe, damit du die Einzelergebnisse auch nach dem Würfeln sehen kannst.
Last edited by Thargun on Tue Sep 29, 2015 4:22 pm, edited 1 time in total.

Thargun
Giant
Posts: 188
Joined: Sun Sep 14, 2014 4:27 am

Re: Macros for Dummies - A guide to MapTool-Macros (german)

Post by Thargun »

11.2 - WHILE: Den Ball am Laufen halten

Befehle innerhalb einer WHILE-Schleife werden, wie bei COUNT, mehrmals wiederholt. Allerdings gibt es hier keine feste Anzahl an Wiederholungen. Stattdessen gibt es, wie bei einer IF-Anweisung, eine Bedingung. Solange diese Bedingung wahr ist (True), werden die Befehle innerhalb der Schleife wiederholt. Erst wenn die Bedingung nicht mehr wahr ist (False), endet die Schleife. Bei der Bedingung können die üblichen Operatoren verwendet werden. WHILE ist eine Roll Option, und kann ebenfalls mit der CODE-Roll Option kombiniert werden.

Zuerst das Format der einfachen Variante:

Code: Select all

[while(Bedingung): Makrobefehl]
Und ein Beispiel dazu:

Code: Select all

[h: zahl = 10]
[r,while(zahl > 0): zahl = zahl - 1]
Die Schleife bewirkt folgendes: Solange "zahl" größer ist als "0" wird bei jedem Durchlauf der Schleife von "zahl" ein Punkt abgezogen. Bei jedem Durchlauf wird also erneut geprüft, ob "zahl" noch größer als "0" ist. Erst wenn "zahl" nicht mehr größer als "0" ist endet die Schleife. Wenn du das Makro ausführst siehst du auch sehr gut in der Chatbox was da passiert.

Bei einer WHILE-Schleife musst du natürlich darauf achten, dass die Schleife auch irgendwann beendet wird. Im obigen Beispiel ist das gewährleistet, da der Wert der Variable "zahl" jeden Durchlauf um eins verringert wird, und somit irgendwann nicht mehr größer als "0" ist. Schaue dir dagegen folgendes Beispiel an:

Code: Select all

[h: zahl1 = 10]
[h: zahl2 = 5]
[r,while(zahl1 > 0): zahl2 = zahl2 + 1]
Hier würde die Schleife niemals enden, denn "zahl1" wird nicht verringert und ist somit bei jedem Durchlauf größer als "0". Du hängst also in der Schleife fest, und das würde einen Fehler im Makro verursachen.

Kommen wir jetzt zur Kombination mit der CODE-Roll Option. Das Format:

Code: Select all

[while(Bedingung), code:
  {
    [Befehl 1]
    [Befehl 2]
    [Befehl 3]
  }
]
Als Beispiel soll ein Charakter eine Angriffsserie ausführen. Er darf solange attackieren bis eine Attacke misslingt. Damit eine Attacke gelingt muss er gleich oder kleiner dem Attacke-Wert würfeln. Der Schaden soll auch gleich angegeben werden.

Code: Select all

[h: attacke = 15]
[h: angriff.nummer = 0]
[r,while(1d20 <= attacke), code:
  {
    [h: angriff.nummer = angriff.nummer + 1]
    [h: schaden = 1d6+1]
    Angriff Nr. [r: angriff.nummer] erfolgreich: [r: schaden] Schadenspunkte
  }
]
Angriff Nr. [r: angriff.nummer = angriff.nummer + 1] nicht erfolgreich!
Last edited by Thargun on Tue Sep 29, 2015 4:23 pm, edited 1 time in total.

Thargun
Giant
Posts: 188
Joined: Sun Sep 14, 2014 4:27 am

Re: Macros for Dummies - A guide to MapTool-Macros (german)

Post by Thargun »

11.3 - FOR: Schritt für Schritt

Die FOR-Schleife, auch wieder eine Roll Option, ist eine Mischung aus COUNT und WHILE. Es gibt einen Startwert und einen Endwert. Wird der Endwert erreicht endet auch die Schleife. Aber schauen wir uns erst das Format an:

Code: Select all

[for(Zähler, Startwert, Endwert, Schrittgröße): Makrobefehl]
Zähler:
Eine Variable die speziell für die FOR-Schleife genutzt wird. Ändert sich bei jedem Durchlauf je nach Schrittgröße. Traditionell wird diese Variable einfach "i" genannt, darf aber natürlich auch eine andere Bezeichnung haben.

Startwert:
Der Wert mit dem die Zähler-Variable startet.

Endwert:
Sobald die Zähler-Variable diesen Wert erreicht endet die Schleife.

Schrittgröße:
Die Zähler-Variable, bzw. ihr Wert, ändert sich nach jedem Durchlauf abhängig von der Schrittgröße. Ist die Schrittgröße z. B. "2", wird die Zähler-Variable nach jedem Durchlauf um zwei erhöht. Ist die Schrittgröße "-2", wird die Zähler-Variable nach jedem Durchlauf um zwei gesenkt.

Wie immer fangen wir mit der einfachen Variante an:

Code: Select all

[r,for(i,0,10,1): ausgabe = "i hat nun den Wert " + i]
Der Startwert ist also "0", der Endwert "10", und der Zähler wird jeden Durchlauf um eins erhöht. Probiere es aus und erhöhe anschließend mal die Schrittgröße:

Code: Select all

[r,for(i,0,10,4): ausgabe = "i hat nun den Wert " + i]
Ich hoffe das Prinzip ist dir nun klar. Falls nicht, experimentiere ein wenig herum bis du den Dreh raus hast.

Und jetzt noch ein Beispiel für die Kombination mit der CODE-Roll Option (Format und Syntax sollten dir ja mittlerweile bekannt sein). Sagen wir du möchtest die ersten fünf Gegenstände aus deinem Inventar, das in einer String-Liste gespeichert ist, in der Chatbox ausgeben. Dafür benutzen wir zusätzlich noch die Funktion listGet(), mit der du die Einträge aus der String-Liste holen kannst. Als Parameter werden die String-Liste und der Index des gewünschten Listeneintrags angegeben.

Code: Select all

[h: inventar = "Fackel, Buch, Teller, Dolch, Decke, Proviant, Wasserflasche, Feuerstein, Schreibzeug"]
[r,for(i,0,5,1), code:
  {
    [h: item = listGet(inventar, i)]
    Gegenstand Nr. [r: i+1]: [r: item]
  }
]

Thargun
Giant
Posts: 188
Joined: Sun Sep 14, 2014 4:27 am

Re: Macros for Dummies - A guide to MapTool-Macros (german)

Post by Thargun »

11.4 - FOREACH: Einer für Alle

Die letzte Codeschleife, und natürlich auch wieder eine Roll Option, ist FOREACH. FOREACH durchläuft z. B. eine String-Liste und führt dann die gleichen Befehle für jeden Eintrag in der Liste aus. FOREACH funktioniert mit allen Arten von Listen, also String-Listen, JSON-Arrays, JSON-Objects und mit leichten Umwegen auch mit String Property Listen. Wir bleiben jedoch vorerst bei String-Listen.

Das Format der einfachen Variante:

Code: Select all

[foreach(Item, Liste): Makrobefehl]
"Item" ist die Variable, in der in jedem Durchlauf der Wert des aktuellen Eintrags in der String-Liste gespeichert wird. "Liste" steht für die String-Liste mit der FOREACH arbeiten soll.

Probieren wir ein ganz simples Beispiel aus, bei der wir die Einträge in einer String-Liste nacheinander in der Chatbox ausgeben:

Code: Select all

[h: inventar = "Fackel, Teller, Feuerstein, Wasserflasche, Buch"]
[r,foreach(item, inventar): item]
Zugegeben, da hättest du auch einfach die Variable "inventar" ausgeben können, aber auf das Prinzip kommt es an. FOREACH geht also nacheinander alle Einträge in der String-Liste durch. Bei jedem Durchlauf wird der aktuelle Eintrag in der Variable "item" gespeichert und dann der Makrobefehl ausgeführt. In unserem Fall also die Ausgabe der Variable "item" in der Chatbox.

Jetzt die Kombination mit der CODE-Roll Option. Sagen wir du triffst mit einem Flammenwerfer gleichzeitig fünf Gegner und möchtest für jeden Gegner den Schaden einzeln auswürfeln:

Code: Select all

[h: gegner = "Christian, Stefan, Normen, Lars, Kerstin"]
[r,foreach(item, gegner), code:
  {
    [h: schaden = 1d6+3]
    [r: item] erhaelt [r: schaden] Schadenspunkte
  }
]

Thargun
Giant
Posts: 188
Joined: Sun Sep 14, 2014 4:27 am

Re: Macros for Dummies - A guide to MapTool-Macros (german)

Post by Thargun »

11.5 - Trennzeichen bei Codeschleifen

Schaue dir nochmal dieses Beispiel an:

Code: Select all

[h: wurf.anzahl = 10]
[r,count(wurf.anzahl): 1d6]
Wie du bemerkst werden in der Chatbox die einzelnen Ausgaben der Durchläufe, hier also die zehn verschiedenen Ergebnisse der Würfelwürfe, durch Kommata (,) voneinander getrennt. Alle Schleifenanweisungen, egal ob COUNT, WHILE, FOR oder FOREACH, akzeptieren noch einen weiteren Parameter, mit dem du das Trennzeichen selbst bestimmen kannst. Dieser Parameter wird immer an letzter Stelle notiert.

Wie wäre es mit einem Gleichheitszeichen?

Code: Select all

[h: wurf.anzahl = 10]
[r,count(wurf.anzahl, "="): 1d6]
Oder doch nur ein Leerzeichen?

Code: Select all

[h: wurf.anzahl = 10]
[r,count(wurf.anzahl, " "): 1d6]
Du kannst auch komplett auf Trennzeichen verzichten. Dann notiere einfach einen leeren String:

Code: Select all

[h: wurf.anzahl = 10]
[r,count(wurf.anzahl, ""): 1d6]

Thargun
Giant
Posts: 188
Joined: Sun Sep 14, 2014 4:27 am

Re: Macros for Dummies - A guide to MapTool-Macros (german)

Post by Thargun »

11.6 - Wie wichtig sind Codeschleifen?

Die Beispiele zu den verschiedenen Codeschleifen in den letzten Kapiteln sind sehr einfach gehalten, und nur dazu gedacht das Prinzip zu verdeutlichen nach dem sie arbeiten. Im Moment fragst du dich deshalb vielleicht was diese Codeschleifen so nützlich macht. Tatsächlich sind sie sehr wichtig, und unabdingbar wenn du etwas komplexere Makros schreibst.

Experimentiere immer mal wieder ein wenig mit ihnen herum. Und wenn du später deine eigenen Makros schreibst, überlege immer ob du für eine bestimmte Aufgabe nicht auch eine der Codeschleifen verwenden kannst. Das kann nicht nur eine Menge Schreibarbeit sparen und das Makro übersichtlicher halten, viele Dinge lassen sich ohne Codeschleifen auch garnicht umsetzen.

Thargun
Giant
Posts: 188
Joined: Sun Sep 14, 2014 4:27 am

Re: Macros for Dummies - A guide to MapTool-Macros (german)

Post by Thargun »

12 - Fenster: Das Tor zur Welt

12.1 - Fensterarten: Unterschiede & Gemeinsamkeiten

Bis jetzt haben wir alle Ausgaben immer in der Chatbox anzeigen lassen. Für Charakterbögen und ähnliches eignet sich aber natürlich eher ein eigenes Fenster. In MapTool gibt es zwei verschiedene Arten von Fenstern: Dialoge und Frames. Beide Fenstertypen funktionieren recht ähnlich, haben das gleiche Format und sogar ähnliche Parameter. Es gibt jedoch wichtige Unterschiede.

Dialoge sind klassische Fenster mit einem zusätzlichen "Schließen-Button" am unteren Rand. Sie werden auf der Spieloberfläche immer übergeordnet angezeigt, verdecken also alles andere hinter ihnen. Dadurch eignen sie sich gut für z. B. Statusmeldungen, Eingabefenster oder andere Fensterinhalte die nur kurz angezeigt werden sollen.

Image

Frames sind etwas schlankere Fenster. Den unteren "Schließen-Button" gibt es nicht und sie werden Dialog-Fenstern gegenüber untergeordnet angezeigt, von diesen also verdeckt. Der große Vorteil von Frames ist, dass sie am Bildschirmrand und anderen Frame-Fenstern angedockt werden können. Dadurch eignen sie sich gut für Fensterinhalte die längerfristig auf der Spieloberfläche angezeigt werden sollen, z. B. Charakterbögen.

Image

Egal ob Dialog oder Frame: Im Inhalt eines Fensters kannst du beliebig Funktionen und andere Makro-Befehle einsetzen. Diese müssen dann, wie üblich, in eckigen Klammern stehen.

Thargun
Giant
Posts: 188
Joined: Sun Sep 14, 2014 4:27 am

Re: Macros for Dummies - A guide to MapTool-Macros (german)

Post by Thargun »

12.2 - Dialoge

Dialoge sind Roll Options. Als einziger Parameter wird der Name des Dialogs als String benötigt. Das Format:

Code: Select all

[dialog(name): 
  {
    Inhalt des Fensters
  }
]
Es gibt noch einige optionale Sub-Parameter, diese werden dann als String-Property-List angegeben:

Code: Select all

[dialog(name, [size; temporary; input; title; noframe]): 
  {
    Inhalt des Fensters
  }
]
Besser sieht man es an einem Beispiel. Schreibe also ein neues Makro mit folgendem Inhalt:

Code: Select all

[dialog("dialogtest", "width=300; height=200; temporary=1; input=0; noframe=0"):
  {
    Dies ist ein Dialog-Fenster.
  }
]
Schauen wir uns jetzt die einzelnen Parameter etwas genauer an:

name
Das ist der interne Name für das Dialog-Fenster, nicht der Fenstertitel den man beim Aufrufen des Fensters sieht! Dieser Name wird von anderen Funktionen benötigt um das Fenster anzusprechen. Nur wenn du den Fenstertitel nicht auf andere Weise festlegst (es gibt noch zwei weitere Möglichkeiten), wird der interne Name auch als Fenstertitel genutzt.

size
Die Größe des Fensters wird gleich mit zwei Angaben festgelegt: width (Breite des Fensters) und height (Höhe des Fensters). Die Zahlenwerte stehen dabei für die Größe in Pixel. Je höher diese Werte sind, desto größer ist auch das Fenster. Falls du dich schon mit HTML auskennst, merke dir, dass du statt Pixel auch andere Einheiten wie em oder Prozent benutzen kannst.

temporary
Wenn ein User ein Fenster öffnet kann er dieses Fenster mit der Maus natürlich auch vergrößern oder verkleinern. Wenn du "temporary=0" als Parameter angibst merkt sich MapTool die Größe des Fensters, falls der User diese geändert hat. Ruft der User also das nächste Mal dieses Fenster auf, wird es wieder in dieser Größe geöffnet. Gibst du dagegen "temporary=1" an, öffnet sich das Fenster immer in der Größe die du bei size angegeben hast, auch wenn der User die Größe des Fensters zwischendurch verändert hat.

input
Wenn du als Parameter "input=1" angibst, wird im Dialog-Fenster kein "Schließen-Button" am unteren Rand angezeigt. Stattdessen wird, falls du HTML-Formulare mit einem "input-submit Button" benutzt, das Fenster automatisch bei einem Klick auf diesen Button geschlossen. Du hast keine Ahnung was ich damit meine? Kein Problem, wir kommen später noch darauf zurück. Benutze einfach "input=0" oder lasse den Parameter komplett weg.

title
Hier kannst du einen Fenstertitel festlegen, den der User dann auch beim Öffnen des Fensters sieht. Dadurch wird dann auch nicht mehr der interne Name des Dialogs als Fenstertitel genutzt. Wenn du allerdings per HTML einen Fenstertitel festlegst, und das wirst du sicher in den meisten Fällen tun (aber dazu kommen wir später), ist dieser Parameter überflüssig, da der HTML-Titel immer Vorrang hat.

noframe
Wenn du als Parameter "noframe=1" angibst, wird kein Rahmen mehr um das Fenster herum angezeigt. Dadurch wird außerdem auch kein Fenstertitel angezeigt, und der User kann das Fenster weder in der Größe verändern noch das Fenster auf der Spieloberfläche verschieben. Mit "noframe=0" wird der Rahmen angezeigt und das Fenster verhält sich ganz normal.

So, jetzt weißt du wie man Dialog-Fenster erstellt. Spiele gleich mal ein bisschen mit den Parametern herum und probiere ein paar Sachen aus, damit du auch live siehst wie sich die Änderungen auswirken.

Thargun
Giant
Posts: 188
Joined: Sun Sep 14, 2014 4:27 am

Re: Macros for Dummies - A guide to MapTool-Macros (german)

Post by Thargun »

12.3 - Frames

Frames sind Roll Options. Als einziger Parameter wird der Name des Frames als String benötigt. Das Format:

Code: Select all

[frame(name): 
  {
    Inhalt des Fensters
  }
]
Es gibt noch einige optionale Sub-Parameter, diese werden dann als String-Property-List angegeben:

Code: Select all

[frame(name, [size; temporary; title]): 
  {
    Inhalt des Fensters
  }
]
Besser sieht man es an einem Beispiel. Schreibe also ein neues Makro mit folgendem Inhalt:

Code: Select all

[frame("frametest", "width=300; height=200; temporary=1"):
  {
    Dies ist ein Frame-Fenster.
  }
]
Die Parameter habe ich ja schon im letzten Kapitel über die Dialog-Fenster erklärt. Bei Frames gibt es zwar weniger mögliche Parameter, aber sie funktionieren genau so wie bei den Dialogen.

Achtung: Es gibt einen Fehler in MapTool. Egal ob du bei Frames "temporary=1" oder "temporary=0" angibst, MapTool merkt sich immer die Größe eines Frames wenn der User diese verändert, und öffnet das Fenster das nächste Mal wieder in dieser Größe, auch wenn es das eigentlich garnicht soll. Hoffen wir, dass der Fehler in einer der nächsten MapTool-Versionen behoben wird.

Thargun
Giant
Posts: 188
Joined: Sun Sep 14, 2014 4:27 am

Re: Macros for Dummies - A guide to MapTool-Macros (german)

Post by Thargun »

13 - HTML

13.1 - HTML Grundlagen

Was ist HTML?

HTML hat eigentlich garnichts mit MapTool zu tun. Es ist eine eigenständige Auszeichnunsgssprache mit der man normalerweise Webseiten erstellt. Dabei ist HTML hauptsächlich für die Struktur einer Seite zuständig, man kann damit also z. B. Tabellen oder Listen erstellen. Zwar sind damit auch Formatierungen, wie z. B. Schriftformatierungen möglich, aber dafür benutzt man heute CSS, das schauen wir uns später auch noch an.

MapTool ist aber ein freundliches Programm. Der Parser versteht HTML und kann die Befehle umsetzen. Das ist auch gut so, denn sonst hättest du keine Chance z. B. einen Charakterbogen zu erstellen. Oder wie meinst du würde das aussehen, wenn du noch nicht mal einen Zeilenumbruch einfügen könntest?


HTML in diesem Tutorial

In diesem Tutorial werde ich dir längst nicht alles zeigen was mit HTML möglich ist. Das würde ein eigenes, sehr großes Tutorial benötigen und an dieser Stelle einfach den Rahmen sprengen. Ausserdem werde ich einige Formatierungsoptionen weglassen, die zwar per HTML möglich sind, aber heutzutage per CSS erledigt werden. Ich zeige dir also wirklich nur die wichtigsten Dinge in Verbindung mit MapTool, und CSS wird ohnehin noch in einem späteren Kapitel behandelt.

Wenn du mehr über HTML und dessen Möglichkeiten erfahren möchtest, empfehle ich dir die deutsche Seite SELFHTML. In der dortigen Dokumentation findest du Einsteigertutorials und eine komplette Befehlsreferenz.


Die HTML-Version

Wenn du dich entschließt mehr über HTML zu lernen als in diesem Tutorial, oder du dich bereits gut mit HTML auskennst, musst du immer auf die HTML-Version achten. Aktuell ist eigentlich HTML 5, MapTool unterstützt jedoch nur HTML 3.2. Seit HTML 3.2 hat sich einiges geändert, es ist mehr möglich und es sind neue Befehle hinzugekommen. Andere Dinge wurden dagegen abgeschafft. Im Rahmen dieses Tutorials musst du dir darum aber keine Gedanken machen.


Tags

HTML-Befehle werden Tags genannt und stehen immer in spitzen Klammern "< >". Tag ist englisch und bedeutet Markierung. Und genau so funktioniert es auch. Zuerst kommt der einleitende Tag, damit beginnt eine Markierung. Dann folgt der betroffene Bereich auf den sich der Tag auswirkt. Diese Bereiche inkl. Tags nennt man Elemente. Zum Schluß kommt der abschließende Tag, der das Ende der Markierung darstellt. Tags können verschiedene Befehle beinhalten, die dann natürlich auch verschiedene Dinge bewirken.

Ein kleines Beispiel. Wenn du Text fett darstellen willst, kannst du dafür den Tag "<b>" benutzen:

Code: Select all

<b>Dieser Text wird fett dargestellt.</b>
Fällt dir etwas auf? Der abschließende Tag zum Beenden der Markierung ist der gleiche wie der Anfangs-Tag, nur mit einem Schrägstrich vorangestellt. Das ist immer so! Noch ein kleines Beispiel um kursiven Text darzustellen:

Code: Select all

<i>Dieser Text wird kursiv dargestellt.</i>
Es gibt ein paar Tags die für sich alleine stehen und keinen Anfang oder Ende haben. Dazu kommen wir aber noch. Ausserdem solltest du wissen, dass Tags, bzw. Elemente, auch verschachtelt werden können. Aber auch das wirst du noch sehen.

HTML-Tags werden zwar vom Parser richtig gelesen und interpretiert, aber genau so behandelt wie ganz normaler Text. Das solltest du dann natürlich auch tun. Und keine Angst, die Tags werden bei der Ausgabe nicht angezeigt. Hier noch ein Beispiel innerhalb eines normalen Strings:

Code: Select all

[r: "<b>Fetter Text</b>"]
Tag-Attribute

Zu vielen Tags kannst du auch Attribute angeben. Attribute sind Zusatzangaben zu den Tags, die dann das Element und eventuell auch alle darin enthaltenen Elemente beeinflusst. Attribute werden immer im einleitenden Tag notiert, niemals im abschließenden Tag. Ein Beispiel:

Mit <table>...</table> kannst du eine Tabelle erstellen (mehr dazu später). Die Breite der Tabelle passt sich automatisch dem Inhalt an. Mit dem Attribut witdh könntest du jetzt aber auch eine feste Breite in Pixeln für diese Tabelle angeben:

Code: Select all

<table width='250'>...</table>
Attribute in einem Tag werden mit einem einfachen Leerzeichen vom eigentlichen HTML-Befehl getrennt. Nach dem Attributsnamen folgt dann ein Gleichheitszeichen und schließlich der Wert in Anführungszeichen (bei HTML in MapTool normalerweise immer einfache Anführungszeichen, keine doppelten). Im obigen Fall wäre die Tabelle also genau 250 Pixel breit. Es können auch mehrere Attribute auf einmal notiert werden, diese werden dann ebenfalls durch einfache Leerzeichen getrennt:

Code: Select all

<table width='300' border='1'>...</table>
Diese Tabelle hätte also eine Breite von 300 Pixeln, und durch das Attribut "border" mit dem Wert "1" würden auch die Gitternetzlinien der Tabelle angezeigt werden. Wenn du mehrere Attribute angibst, achte darauf immer die gleiche Reihenfolge zu wählen. Das macht den Code übersichtlicher.

Viele Attribute lassen sich heute durch CSS-Angaben ersetzen, und das solltest du auch tun. Daher werde ich dir nur ein paar Attribute im Laufe des Tutorials zeigen. Den Rest erledigen wir dann mit CSS (auch dazu später mehr).


Aufbau

Wenn du HTML in einem Dialog-Fenster oder Frame verwendest solltest du das auch richtig tun. Wichtig dabei ist der Aufbau:

Code: Select all

<html>
  <head>
    <title>
      Der Titel
    </title>
  </head>
  <body>
    Der Inhalt
  </body>
</html>
<html>...</html>
Markiert den eigentlichen HTML-Bereich innerhalb dessen alle HTML-Angaben gemacht werden.

<head>...</head>
Markiert den "Kopf" eines HTML-Bereichs. Der "Kopf" enthält ganz bestimmte Angaben und ist bei der Ausgabe im Dialog-Fenster oder Frame nicht zu sehen.

<title>...</title>
Enthält den Titel. Dieser Titel wird als Fenstertitel für Dialog-Fenster oder Frames genutzt und dementsprechend angezeigt.

<body>...</body>
Markiert den eigentlichen Inhalt, den "Körper" des HTML-Bereichs, der dann auch im Dialog-Fenster oder Frame angezeigt wird. Im "Körper" können natürlich noch weitere HTML-Tags und auch Makro-Befehle genutzt werden.

Schauen wir uns das jetzt in einem richtigen Beispiel an. Hier in einem Frame, Dialog-Fenster funktionieren aber natürlich auch.

Code: Select all

[frame("charbogen"): 
  {
    <html>
      <head>
        <title>
          Heldenbogen
        </title>
      </head>
      <body>
        Hier stehen alle Angaben des <b>Charakterbogens</b>.
      </body>
    </html>
  }
]
HTML in der Chatbox

Wenn du HTML-Befehle nicht in einem Fenster (Frame oder Dialog) nutzt, sondern bei der Ausgabe in der Chatbox (z. B. zur Anzeige eines Würfelwurfs), kannst und musst du auf den oben beschriebenen Aufbau verzichten (<html>, <head>, <title>, <body>). Der funktioniert in der Chatbox einfach nicht, und einen Fenstertitel gibt es ja auch nicht. HTML-Befehle können dann direkt angegeben werden, Einschränkungen gibt es dabei keine. Hier ein kleines Beispiel:

Code: Select all

[h: wurf = 1d6]
Du hast mit <i>1W6</i> eine <b>[r: wurf]</b> gewuerfelt.
Zeilenumbrüche

Mit dem Tag "<br>" kannst du an beliebigen Stellen Zeilenumbrüche einfügen. "<br>" steht immer für sich alleine und hat weder Anfang noch Ende. Ein Beispiel:

Code: Select all

[frame("charbogen"): 
  {
    <html>
      <head>
        <title>
          Heldenbogen
        </title>
      </head>
      <body>
        Zeile 1<br>
        Zeile 2<br>
        Zeile 3
      </body>
    </html>
  }
]

Post Reply

Return to “Documentation Requests/Discussion”