- No category
Entwicklerhandbuch (Version 1.0)
Add to my manualsadvertisement
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
Inhaltsverzeichnis
1 Einleitung ......................................................................................................................................... 2
2 Anpassungen am Ruleset................................................................................................................. 3
2.1 Charakterbogen ..................................................................................................................... 3
2.1.1 Tabs erstellen ........................................................................................................... 3
2.1.2 Frames erstellen ....................................................................................................... 5
2.1.3 Inhalte einfügen ........................................................................................................ 5
2.1.4 Listen erstellen ......................................................................................................... 6
2.1.5 Detail-Fenster für (Listen-)Elemente hinzufügen ..................................................... 8
2.2 Würfeln und Auswertung ...................................................................................................... 9
2.2.1 Sicherheits- und Risikowurf .................................................................................... 10
2.2.2 Patzer und Triumph ................................................................................................ 16
2.2.3 Proben und Erfolgsgrade ........................................................................................ 17
2.2.4 Wurf teilen .............................................................................................................. 21
2.3 Tick-Fenster (Combat Tracker) ............................................................................................ 23
3 Anpassungen an Modulen ............................................................................................................. 24
3.1 Zauberbibliothek ................................................................................................................. 24
3.2 Anzeige ändern .................................................................................................................... 25
3.3 Module einbinden ............................................................................................................... 25
4 Design ............................................................................................................................................ 27
4.1 Grundaufbau ....................................................................................................................... 27
4.1.1 Technik.................................................................................................................... 28
4.1.2 Skalierung ............................................................................................................... 28
4.1.3 MouseOver Effekte ................................................................................................. 28
4.1.4 OnClick Effekte ....................................................................................................... 28
4.1.5 Drag Effekt .............................................................................................................. 29
4.2 Hintergrund ......................................................................................................................... 29
4.3 Rechtsklickmenü .................................................................................................................. 30
4.4 Sidebar ................................................................................................................................. 31
4.5 Fenster ................................................................................................................................. 32
4.5.1 Fenster-Elemente ................................................................................................... 32
4.5.2 Implementierung des vollständigen Story-Fensters ............................................... 33
Seite 1
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
1 Einleitung
Damit alle Änderungen gut portiert werden können muss darauf geachtet werden, dass keine
Variablen umbenannt werden. Die Änderungen sollten die Grenzen des Rulesets nicht verlassen, um die Portabilität zu Gewährleisten.
Es werden in diesem Entwicklerhandbuch fortgeschrittene Kenntnisse in den Programmiersprachen
XML und LUA vorausgesetzt. Wem diese Grundlagen fehlen, der sollte sich vorher Grundwissen in diesen aneignen. Entsprechende Literatur findet sich in jeder Bibliothek oder im Internet.
Seite 2
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
2 Anpassungen am Ruleset
Das Ruleset ist in den beiden Programmiersprachen XML und LUA programmiert. Dabei übernimmt
XML meistens die optische Komponente, LUA die Programmlogik dahinter. Die Ordner sind so aufgebaut, dass alle Skripte (LUA-Dateien) in einem Unterordner „scripts“ lagern.
Auf oberster Ordnerebene findet sich die Datei base.xml und elements.xml. Die base.xml spielt eine wichtige Rolle und hat eine elementare Funktion. Innerhalb dieser Datei definiert ihr zuerst den
Namen, Autoren und Version des Rulesets. Danach werden die Dateien eingebunden, welche das
Ruleset laden soll. XML-Dateien werden einfach durch ein „includefile“-Tag geladen:
Bsp.: <includefile source="utility/template_utility.xml" />
Die LUA-Dateien werden ebenfalls innerhalb dieser Datei geladen. Diese werden über das Script-Tag eingebunden:
Bsp.: <script name="SpellManager" file="scripts/manager_spells.lua" />
Wichtig ist die eindeutige Namensvergabe. Durch den Namen können die Funktionen innerhalb der
LUA-Datei eindeutig adressiert und aufgerufen werden. Das geschieht über die Notation:
skriptName.Funktionsname (Bsp.: CombatManager.rollDice() )
2.1 Charakterbogen
Der Charakterbogen kann nach eigenen Wünschen angepasst und modifiziert werden.
Um Änderungen am Charakterbogen vorzunehmen muss die entsprechende Datei im Ordner
~/campaign/ geöffnet werden. Die Dateien sind nach den Tabs (engl.) benannt. Hier die Liste der
Tabs und die dazugehörigen XML-Dateien:
• Allgemein: record_char_main
• Attribute: record_char_attributes
• Fähigkeiten: record_char_abilities
• Kampf: record_char_combat
• Magie: record_char_magic
• Inventar: record_char_inventory
• Notizen: record_char_notes
In diesem Abschnitt wird erklärt, wie Änderungen vorgenommen und vorhandene Frames angepasst werden können. Dabei wird nicht jedes einzelne Fenster im Detail erläutert sondern die
Funktionsweise und der Aufbau erklärt.
2.1.1 Tabs erstellen
Grundlegend sollte die Anzahl der Tabs nicht verändert werden, da ansonsten viele Parameter zur korrekten Anzeige nicht mehr stimmen. Falls eine Änderung dennoch gewünscht ist, so wird in diesem Abschnitt erläutert wie Tabs bei einem Charakterbogen umbenannt, hinzugefügt und entfern werden können.
Wer einen Tab umbenennen möchte hat es am einfachsten. Die Tabs sind nur Bilddateien und wer die Beschriftung ändern möchte, der kann diese Änderungen im Ordner \graphics\tabs vornehmen.
Die entsprechenden Beschriftungen sind im Format tab_name.png hinterlegt und können in einem
Bildbearbeitungsprogramm geändert werden. Wer das Layout der Tabs ändern möchte, findet die
Tab-Leiste tabs.png im Ordner \graphics\frames.
Seite 3
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
Wer hingegen Tabs hinzufügen oder entfernen möchte, der hat es etwas schwieriger. Das
Hinzufügen bzw. Entfernen von Tabs erfordert leichte Programmierkenntnisse und Änderungen in mehreren Dateien.
In der Datei record_char.xml im Ordner campaign des Rulesets findet ihr am unteren Ende des Codes den Bereich TAB-NAVIGATION. Innerhalb dieses Bereichs können neue Punkte hinzugefügt oder existierende entfernt werden. Löscht einen Punkt weg oder fügt einen hinzu um die Tableiste zu erweitern bzw. zu reduzieren. Schauen wir uns einen XML-Eintrag genauer an:
00. <tab>
01.
<icon> tab_magic </icon>
02.
<subwindow> magic </subwindow>
03. </tab>
Ein Tab ist dabei sehr einfach aufgebaut: In Zeile 1 wird das Icon definiert, welches nichts anderes als der Name der PNG Datei im Ordner graphics/tabs/ repräsentiert. Diese PNG-Dabei enthält die
Beschriftung als Grafik. In Zeile 2 wird das Subwindow definiert. Das Subwindow ist das Ziel, welches links im Fenster-Bereich angezeigt werden soll. Entfernt ihr den obenstehenden Code aus der XML-
Datei wird der Reiter in der Tab-Leiste der Charakter verschwinden. Einfach und unkompliziert. Wenn ihr hingegen einen Tab hinzufügen möchtet, müsst ihr darauf achten, dass die Icon-Datei sowie die
Ziel-Klasse existieren müssen.
Die Subwindowc-Klasse wird ebenfalls direkt hier in dieser Datei (oberhalb der Tab-Definitionen) deklariert. Schauen wir uns wieder die Stelle an, welche unser Magie-Fenster betrifft.
00. <subwindow name =" magic ">
01. <bounds> 0,65,-1,-20 </bounds>
02. <class> charsheet_magic </class>
03. </subwindow>
In Zeile 1 wird die Fenstergröße des Subwindow angegeben. Die Formation ist dabei X, Y, BREITE,
HÖHE. Gibt man Minus-Werte an, so wird das Fenster bis zum Rand minus die angegebenen Pixel reichen. In diesem Beispiel wird also ein Fenster erzeugt, welches bei 0,65 beginnt. Die Breite des
Fensters reicht bis zum rechten Rand minus 1 Pixel. In der Höhe geht es bis nach ganz unten minus 20
Pixel. Wir haben rechts also einen Abstand zum Rand von einem und nach unten von 20 Pixel. Am
Anfang kann dieses System etwas verwirrend sein, mit ein wenig Übung ist es aber sehr hilfreich.
Wenn ihr nun das Subwindow und einen Tab für den neuen Tab definiert habt, dann müsst ihr nur noch die Datei für den Inhalt definieren. Hierzu sehen wir uns einmal die Datei record_char_magic.xml an. Hier sehen wir, was wir brauchen.
00. <root>
01.
02.
03.
04.
05.
06. </root>
<windowclass name =" charsheet_magic ">
<sheetdata>
…
</sheetdata>
</windowclass>
Wenn wir nun Inhalt füllen wollen müssen wir nur noch die XML-Datei mit der Windowclasse erstellen, die wir in dem vorherigen Subwindow aufrufen. Alles, was sich in dem Tag Sheetdata befindet wird dann innerhalb des Subwindows angezeigt.
Hinweis: Das Fenster sollte nicht größer werden, daher seid ihr in der Höhe der Tab-Leiste eingeschränkt. Ihr könnt aber einen Tab jederzeit entfernen oder abändern.
Seite 4
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
2.1.2 Frames erstellen
Haben wir unser Subwindow erstellt kann es an die Inhaltsgenerierung gehen. Doch bevor wir den eigentlichen Inhalt einfügen können müssen wir Frames erstellen. Das sind die Fensterbereiche innerhalb des Fensters, welche sich von der Gestaltung etwas abheben und so die Möglichkeit zur besseren Gliederung innerhalb des Fensters bieten. Wir schauen uns dazu wieder die Magie-Sparte an. Innerhalb des Sheetdata Tags (siehe vorhergehenden Code-Auszug in Abschnitt 2.1.1) müssen wir zu Beginn ein Frame erzeugen.
00. <frame_char name =" magicframe ">
01. <bounds> 15,0,-29,200 </bounds>
02. </frame_char>
03.
04. <label_frametop name =" magic_label ">
05. <anchored to =" magicframe " />
06. <static textres ="char_label_magic" />
07. </label_frametop>
Wir erstellen zu Beginn ein Frame, welchem wir einen eindeutigen Namen geben um später Inhalte an diesem Element auszurichten. Mit dem Tag bounds geben wir wieder die Fenstergröße und
Position an. Das war’s auch schon! Unser Frame wird entsprechend der angegebenen Werte positioniert. In diesem Beispiel wäre es bei 15,0 (X,Y) mit einer Breite von „Bis zum rechten Rand minus 29 Pixel“ und einer Höhe von 200 Pixel.
In den Zeilen 4 bis 7 geben wir dem neuen Frame noch eine Beschriftung. Dabei verankern wir die
Beschriftung an unserem neuen Frame und geben eine Verlinkung auf unsere Text-Ressource
(textres) an. Diese ist in der Datei strings/strings_campaign.xml definiert. Eine Frame-Beschriftung ist standardmäßig immer Oben-Mittig ausgerichtet. Mit dem Attribut offset innerhalb des anchored-
Tags könnte man die Position noch anpassen.
2.1.3 Inhalte einfügen
Nachdem das Frame erstellt wurde, können Inhalte bzw. Eingabefelder definiert werden. Dies geschieht bei einer nummerischen Eingabe einfach über die XML-Codezeilen
00. <number_dropadd name =" exp_level ">
01.
<anchored to ="exp_header_level" position ="insidetopleft"
02.
03.
offset=" 3,30
<tooltip
" width=" textres
04. </number_droppadd>
40 " height=" 20 " />
="char_label_exp_level" />
Oder wenn es sich um Text handelt:
05. <string_labeled name =" haircolor ">
06. <anchored to =" culture " position =" right " offset =" 15,0 " width =" 70 " />
07. <labelres> char_label_haircolor </labelres>
08. </string_labeled>
Betrachten wir zuerst den oberen Code. Wenn wir eine Nummer als Eingabefeld (zum Beispiel für einen Fertigkeitswert oder Heldengrad) darstellen möchte, so geschieht das über number_droppadd
. Wir müssen in Zeile 1 die Verankerung des Elements und in Zeile 3 den Tooltip
(Text wenn man mit der Maus darüber fährt) angeben. Soll ein Wert Würfelbar sein, kann diese
Funktion mit
<rollable/> hinzufügt werden. Soll der Wert nicht editierbar sein, so kann das über die Zeile
<readonly/> geschehen.
Bei den Texteingaben ist es sehr ähnlich. Da die Beschriftung hier schon direkt unter der Eingabelinie steht entfällt der Tooltip. Dafür müssen wir den Inhalt der Beschriftung stattdessen angeben. Dies
Seite 5
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch geschieht über das in Zeile 7 definierte labelres. Es handelt sich hierbei wieder um einen Verweis und die Variable char_label_haircolor muss in der Datei strings/strings_campaign.xml definiert sein.
Es gibt auch noch die Möglichkeit nur Text auszugeben und nur eine Linie für Texteingaben (ohne
Beschriftung) zu erstellen. Ersteres geschieht über das Tag
00. <label name ="moon_header_name">
01.
<anchored to ="moonframe" position ="insidetopleft" offset ="25,40" />
02.
<static textres ="char_label_moon_name" />
03. </label>
Dabei wird ein Text ausgegeben, welcher in Zeile 2 definiert wird (wieder über Verlinkung). Möchte man nur eine Texteingabe, dann kann das über die Zeilen
00. <stringu name ="moonsign">
01. <anchored to ="moon_header_name" position ="insidetopleft"
02. offset ="45,0" width ="150" height ="20" />
03. </stringu> geschenen. Dabei verhält es sich ähnlich wie die anderen vorhergehenden Inhaltselemente auch. Es ist wichtig, dass ein eindeutiger Name zugewiesen wird und das Element richtig an ein anderes verankert wird, damit Fantasy Grounds weiß, wo es platziert werden muss.
2.1.4 Listen erstellen
Zu Beginn müssen wir die Liste, welche wir später verwenden möchten, in der Datei campaign/templete_char.xml definieren. Dazu werden am Beispiel der Magie-Liste die Zeilen erklärt.
00.
<!-- MAGIC -->
01. <template name =" list_magic ">
02.
<list_text>
03.
<datasource> .magiclist
</datasource>
04.
05.
06.
07.
<class> char_magic
<sortby><control>
<newfocus>
<allowcreate />
</class> magic_name magic_name
</control></sortby>
</newfocus>
08.
<allowdelete />
09.
</list_text>
10. <template>
Zu Beginn wird das Template-Tag geöffnet und mit einem eindeutigen Namen definiert. In Zeile 10
Wird das Tag wieder geschlossen. Nun kommen wir direkt zu Liste und öffnen hierzu ein „list_text“
Tag. Innerhalb diesem werden die wichtigen Eck-Daten festgelegt, damit das Ruleset später weiß wie es die Liste handhaben soll. Die wichtigste Zeile hierbei ist die Zeile 3, hier geben wir die datasource an. Dabei muss es sich um einen eindeutigen Namen handeln, unter welchem die Daten der Liste in der Datenbank abgelegt werden. Der Variablenname muss mit einem Punkt (.) beginnen. Die Zeile 4 ist ebenso wichtig und gibt das Ziel an, welches die Liste später haben wird. Der „Klassenname“ wird hier eindeutig angegeben. Wir verwenden die Liste später für die WindowClass char_magic. Die
Zeilen 5, 6, 7 und 8 dienen zur Darstellung und Benutzerinteraktion. Wir geben an, nach welchem späteren Wert die Liste sortiert werden soll (es ist dabei darauf zu achten, dass wir später auch einen
Wert mit diesem Namen anlegen). Danach wird das erste Ziel des Zeigers definiert, wenn wir ein neues Listenelement anlegen (hier ebenfalls char_name). Mit den letzten zwei Befehlen erlauben wir das Hinzufügen und Entfernen von Listenelementen.
Nachdem wir unsere Liste definiert haben können wir sie in unser bevorzugtes Frame einbinden.
Beispielshaft nehmen wir wieder die Liste der Magieschulen. Wir benötigen nun eine andere Datei, in
Seite 6
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch unserem Fall ist das die Datei campaign/record_char_magic.xml. Innerhalb dieser Datei können wir die Inhalte des Reiters Magie im Charakterbogen editieren.
Zu Beginn initialisieren wir unsere Liste von eben und geben ihre Position innerhalb des Fensters an.
00.
<!-- LISTE INITIALISIEREN -->
01. <list_magic name =" magic ">
02. <anchored to =" magicframe ">
03. <top offset ="70" />
04. <left offset ="15" />
05. <right offset ="-20" />
06. <bottom offset ="-15" />
07. </anchored>
08. </list_magic>
09. <scrollbar_list>
10. <anchored to =" magic " />
11. <target> magic </target>
12. </scrollbar_list>
13.
14. <button_iedit name =" magic_iedit ">
15.
<anchored to ="magicframe" position ="insidetopright" offset ="20,15" />
16.
<target> magic </target>
17. </button_iedit>
18.
19. <button_iadd name=" magic_iadd ">
20.
<anchored to ="magic_iedit" position ="insidetopright" offset ="30,0" />
21.
<target> magic </target>
22. </button_iadd>
Hier wird nun die Liste initialisiert und positioniert. Man beachte, dass in Zeile 1 der Tag-Name dem
Template-Namen entspricht, den wir in dem vorherigen Schritt definiert haben. Auch hier vergeben wir wieder einen eindeutigen Namen. Zeilen 2-7 dienen nur der Positionierung.
Die Zeilen 9 bis 12 sind wichtig um einen Scroll-Balken zu erhalten. Wir ankern diesen an dem Fenster mit dem Namen magic (unsere Liste – siehe Zeile 1). Auch als Ziel (target) wird unsere Liste gewählt, somit erhalten wir später einen schönen Scroll-Balken am rechten Rand.
Die Zeilen 14 bis 22 sind sehr wichtig um unserem Listenelement Schaltflächen zum Editieren und
Hinzufügen von neuen Listenelementen hinzuzufügen. Wir geben hierzu wie bei dem Scroll-Balken das Fenster zur Verankerung und das Ziel an.
Nun kommen wir zu dem wohl wichtigsten Code-Element. Nachdem die Liste definiert und initialisiert wurde müssen wir im nächsten Schritt die eigentliche Liste gestalten. Sprich Aufbau und
Aussehen der Liste.
Dies geschieht innerhalb einer Windowclass und befindet sich in derselben Datei. Sie wird hier nicht hineinkopiert, da sie über mehr als 100 Zeilen lang ist. Definiert wird die Windowclass durch die erste
Zeile:
00. <windowclass name =" char_magic "> … </windowclass>
In der Windowclass char_magic (beachtet die Betitelung – wir haben die Klasse auch bei der definition der Liste angegeben) wird neben verschiedenen Skripten die Sheetdata angegeben. Dabei handelt es sich um die Definition der Listenelemente. Beispielhaft hier die Spalte für den Namen:
00. <string_textlistitem name =" spell_name ">
01. <anchored position =" insidetopleft "
02. offset=" 10,2 " height=" 20 ">
03. <right parent =" spell_school " anchor =" left "
Seite 7
Splittermond Ruleset für Fantasy Grounds II
04. relation=" current " offset=" -20 " />
05. </anchored>
06. <tabtarget next =" spell_school "/>
07. </string_textlistitem>
Entwickler-Handbuch
In Zeile 1 wird der Elementtyp und der Name definiert (string_textlistitem definiert dabei einen Text, number_droppad wäre eine Zahl). Zeilen 1 bis 5 bestimmen die Position. Zeile 6 gibt das nächste Ziel bei einem Druck auf die TAB-Taste an. Hier ist neben dem Attribut next auch prev möglich um das vorherige Ziel anzugeben.
2.1.5 Detail-Fenster für (Listen-)Elemente hinzufügen
Ein Detail-Fenster hinzuzufügen ist wohl die aufwändigste der in diesem Kapitel beschriebenen
Aufgaben. Man muss in mehreren Dateien Änderungen vornehmen um ein Detail-Fenster fehlerfrei einfügen zu können. Doch fangen wir mit der einfachsten Aufgabe an. Wir öffnen die Datei base.xml welche sich auf oberster Ordnerebene befindet und fügen auf Höhe der CAMPAIGN RECORDS (etwa ab Zeile 125) folgende Zeile ein:
<includefile source =" campaign/record_spell.xml
" />
Wie vielleicht schon bemerkt wurde bleiben wir bei dem Zauber-Beispiel. Wir möchten also nun einem Zauber ein Detail-Fenster hinzufügen. Durch diese Zeile binden wir eine XML-Datei ein, in welcher wir unser Detail-Fenster definieren. Danach legen wir diese Datei in dem Ordner wie angegeben an.
16.
17.
18.
19.
10.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
00. <?xml version="1.0" encoding="iso-8859-1"?>
01. <root>
02.
03.
<!-- FENSTER DER ZAUBER-INFORMATION -->
<windowclass name =" spell ">
04.
05.
06.
07.
<frame> recordsheet
<placement>
<size width
</placement>
</frame>
=" 350 " height =" 400 " />
08.
09.
10.
11.
12.
13.
14.
15.
<sizelimits>
<minimum
</sizelimits>
<nodelete /> width
<dynamic />
<playercontrol />
=" 350
<tooltip field =" name " />
" height =" 400
<minimize> minimized_item </minimize>
" />
<sharable />
<script
<sheetdata>
… file
</sheetdata>
</windowclass>
<!-- HEADER DER ZAUBER-INFORMATION -->
<windowclass name =" spell_header ">
<margins control=" 0,0,0,7 " />
<sheetdata>
…
</sheetdata>
</windowclass>
<!-- BODY DER ZAUBER-INFORMATION -->
<windowclass name ="spell_main">
<margins control =" 0,0,0,2 " />
<script file =" campaign/scripts/spell_main.lua
" />
<sheetdata>
=" campaign/scripts/spell.lua
" />
Seite 8
Splittermond Ruleset für Fantasy Grounds II
35.
36.
…
</sheetdata>
37. </windowclass>
38. </root>
Entwickler-Handbuch
Dieser Auszug zeigt die wichtigsten Eckpfeiler dieser Datei auf. Der Inhalt innerhalb der „sheetdata“-
Tags wurde weggelassen und kann in der Datei nachgeschaut werden. In diesen geht es hauptsächlich um die Inhaltsgestaltung (Name, …).
Doch betrachten wir zunächst diesen Code genauer. Er besteht aus drei Window-Klassen (Zeile 3-20,
Zeile 23-28 und Zeile 31-37). Die erste gibt dabei den Rahmen für die anderen zwei vor. Hier werden viele Eckdaten niedergeschrieben wie Größe und Position, etc.
Wie man in Zeile 17 sieht wird ein Skript eingebunden. Dieses Skript muss später auch noch erstellt werden. Aber eines nach dem anderen. In Zeile 23 startet eine weitere Windowclass. In dieser werden die Kopfinformationen verarbeitet. Es geht hierbei eher um die Ausgabe weniger Strings und ist weniger spektakulär.
Ab Zeile 31 kommt dann der eigentlich spannende Inhalt. Ab hier werden die Body-Informationen beschrieben. Die Platzierung unterscheidet sich nicht von anderen Inhaltsplatzierungen. Alleinig die
Zeile 33 ist mit der Skripteinbindung nochmals interessant.
Schauen wir uns aber zunächst das erste geladene Skript an. Die Datei spell.lua muss in dem angegebenen Ordner erstellt werden. Sie enthält Funktionen die so übernommen werden können und lediglich das Handling verwaltet.
Die Skriptdatei spell_main.lua ist hingegen etwas interessanter. In dieser befindet sich die Update-
Funktion und kann nicht ohne weiteres kopiert werden. Hier müssen die Elemente mit ihrem Namen adressiert werden und angegeben werden ob sie bei dem verschließen des Fensters (über das
Schlosssymbol) ausgeblendet werden sollen, falls sie keinen Inhalt haben.
Als letzten Schritt müssen wir die Verlinkung noch der Liste hinzufügen. Das geschieht über das
Listen-Element linkcontrol. Dieses wird in die Liste (Windowclass der entsprechenden Liste) eingebunden. Bei den Zaubern sieht das zum Beispiel so aus:
00.
<linkcontrol name =" shortcut ">
01.
<anchored width =" 20 " height =" 20 ">
02.
03.
<top offset
<right
=" parent
2 " />
=" rightanchor " anchor =" left "
04.
relation =" relative " offset =" -2 " />
05.
</anchored>
06.
<class> spell </class>
07.
<readonly />
08.
</linkcontrol>
2.2 Würfeln und Auswertung
Benutzte Dateien:
• elements.xml
• desktop/desktop_panels.xml
• desktop/desktop_classes.xml
• graphics/graphics_fonts.xml
• graphics/graphics_icons.xml
• desktop/scripts/chat_window.lua
• scripts/manager_actions.lua
Seite 9
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
Das Splittermond Regelwerk kennt mehrere Wurfarten, die unterschiedlich ausgewertet werden. Im
Folgenden wird darauf eingegangen, wie Sicherheits- und Risikowurf, Erfolgsgrade und Patzer und
Triumph in das Ruleset integriert wurden und wie diese Funktionen modifiziert werden können.
2.2.1 Sicherheits- und Risikowurf
Die Funktionalität, zwischen den einzelnen Wurfarten zu wechseln, wird über einen Button unter dem Chatfenster realisiert. Damit dieser Platz hat, sind die beiden Würfel W6 und W10 nach rechts verschoben worden. Die Position der Würfel lässt sich in der Datei elements.xml ändern.
00.
<!-- 6er Würfel -->
01.
<die name =" d6 ">
02.
03.
<icon> d6icon
<position>
</icon>
290,-68 </position>
04.
</die>
05.
06.
<!-- 10er Würfel -->
07.
<die name =" d10 ">
08.
09.
10.
</die>
<icon> d10icon </icon>
<position> 360,-68 </position>
Das <die> Tag zeigt an, dass es sich bei diesem Element um einen Würfel handelt. Das <icon> Tag verweist auf das 3D-Model des Würfels. Im <position> Tag wird die Position des Würfels auf dem
Desktop bestimmt. Der erste Wert ist hierbei die X-Koordinate, der zweite die Y-Koordinate.
Für den Button selbst, wird in der Datei desktop_panels.xml ein eigenes Panel angelegt.
00.
<panel name ="throwmode" modes ="host,client">
01.
02.
03.
<class> throwmode
<bounds>
</class>
100,-98,64,57
<dynamic />
04.
<locked />
05.
</panel>
</bounds>
Das <panel> Tag erstellt ein neues Panel. In diesem Tag wird außerdem der Name des Panels angegeben, und dass das Panel für den GM und den Client sichtbar ist. Im Tag <class> wird das Panel mit seiner zugehörigen Fensterklasse verknüpft, die sich in der Datei desktop_classes.xml befindet.
Das <bounds> Tag definiert die Position des Panels auf dem Desktop. Die ersten beiden Werte sind hierbei die X- und Y-Koordinaten, die letzten beiden die Breite und die Höhe des Fensters. Das Tag
<dynamic> schaltet die Funktion frei, das Fenster zu schließen, bewegen oder die Größe zu ändern.
Das <locked> Tag baut auf darauf auf und besagt, dass sämtliche Funktionen, die durch das
<dynamic> Tag freigeschaltet werden, erst verfügbar sind, wenn das Element über das Kreismenü freigeschaltet wird.
In der Datei desktop_classes.xml wird nun der eigentliche Button angelegt.
00. <windowclass name = "throwmode" >
01. <sizelimits>
02. <minimum width = "64" height = "57" />
03. </sizelimits>
04. <noclose />
05.
06. <sheetdata>
07. <buttoncontrol name = "throwmodebtn" >
08. <font> modcollectorlabel </font>
Seite 10
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
09.
10.
11.
12.
13.
14.
<anchored position
<state
<state
<state icon icon icon
<default>
<script>
0
= "insidetopleft"
=
=
=
"throwNormIco"
"throwSafeIco"
"throwRiskIco"
</default> width
/>
/>
/>
= "64" height = "57"
15.
16.
17. function onButtonPress()
18.
19. end
</script>
20. </buttoncontrol>
21. </sheetdata>
22. </windowclass> local val = getValue();
ActionsManager.setThrowmode(val);
/>
Das <windowclass> Tag erzeugt eine neue Fensterinstanz. Über den Namen der Instanz wird diese mit dem zugehörigen Panel in der desktop_panels.xml verknüpft. Im Tag <sizelimits> können die maximale und/oder die minimale Breite und Höhe des Fensters definiert werden. Das Tag <noclose> verhindert, dass der User das Fenster schließen kann. Im <sheetdata> Tag können nun verschiedene
Control-Arten eingebunden werden, in diesem Fall eine Buttoncontrol.
Das <buttoncontrol> Tag zeigt an, dass hier ein neuer Button erstellt wird. Über das <font> Tag wird die verwendete Schriftart festgelegt, die in der Datei graphics_fonts.xml definiert ist. Das
<anchored> Tag gibt an, wo der Button innerhalb des Fensters verankert ist. In diesem Fall ist der
Button oben links verankert und hat eine Größe von 64x57 Pixeln. Über das <state> Tag wird definiert, dass dieser Button mehrere Zustände besitzt. Diese Zustände wechseln bei einem Klick auf den Button durch. Innerhalb des Tags wird dem jeweiligen Zustand ein eigenes Icon zugewiesen.
Jedes Icon ist in der Datei graphics_icons.xml definiert. Im Tag <default> wird angegeben, welcher der Zustände beim Starten des Spiels angezeigt wird. In diesem Fall ist es der 1. Zustand (0).
Danach wird dem Button über das <script> Tag eine Funktion zugewiesen. In diesem Fall ist dies die onButtonPress()-Funktion, die ausgelöst wird, sobald der Button geklickt wird. Über den
Funktionsaufruf getValue() wird der Wert des Buttons in der Variable val gespeichert. Der Wert liegt in diesem Fall zwischen 0 und 2 und gibt an, in welchem Zustand sich der Button befindet. Dann wird die Funktion setThrowmode() aufgerufen, die sich in der Datei manager_actions.lua befindet. Dieser
Funktion wird die Variable val und damit der Zustand des Buttons übergeben.
00. function setThrowmode ( mode )
01. throwmode = mode ;
02. local msg = { font = "systemfont" };
03. local user ;
04. if User .
isHost () then
05.
06. else user = "GM" ;
07. user =
08. user .
getIdentityLabel ( User .
getCurrentIdentity ( User .
getUsername ()));
09. end
10. if mode == 0 then msg .
text = user ..
" wirft einen Normalwurf" end
11. if mode == 1 then msg .
text = user ..
" wirft einen Sicherheitswurf
12. (2W10)" end
Seite 11
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
13. if mode == 2 then msg .
text = user ..
" wirft einen Risikowurf
14. (4W10)" end
15. Comm .
deliverChatMessage ( msg );
16. end
In der Funktion setThrowmode() wird der lokalen Variablen throwmode der übergebene Wert zugewiesen. Danach wird der Nachrichtenkörper vorbereitet, dazu wird das Message-Object msg erstellt, dem die Schriftart systemfont zugewiesen wird. In der Variablen user wird dann gespeichert, ob der Benutzer, der den Button betätigt hat der GM oder ein normaler User ist. Ob ein Benutzer GM ist, lässt sich über die Funktion User.isHost() feststellen, die einen boolean zurückgibt. Der
Benutzername eines normalen Users kann über die Funktion
User.getIdentityLabel(User.getCurrentIdentity(User.getUsername())) ausgelesen werden. Danach wird die Wurfart im Text-Attribut von msg gespeichert. In den if-Abfragen wird dafür der übergebene
Wert überprüft und die entsprechende Wurfart beschrieben. Zum Schluss wird das Message-Objekt
msg dann über die Funktion Comm.deliverChatMessage() an alle Chatfenster übertragen. Somit können alle Spieler jederzeit sehen, mit welcher Wurfart gewürfelt wird.
Die eigentliche Auswertung der verschiedenen Wurfarten Normalwurf, Risikowurf und
Sicherheitswurf findet in der Funktion createActionMessage() statt, die aufgerufen wird, nachdem ein Spieler gewürfelt hat.
00. function createActionMessage ( rSource , rRoll )
01. ...
02. if #( rRoll .
aDice ) > 1 and rRoll .
aDice [ 1 ].
type == "d10" then
03. ...
if throwmode == 1 04.
05.
06.
07.
08. then local resultMax resultMax setTotal (
=
=
get1Max resultMax nil
+
(
; rRoll rRoll .
); nMod ); broadcastTotal (); 09.
10.
11.
12.
13.
14.
15.
16. end if throwmode then local local
== 2
resultMin
resultMax resultMin resultMax
=
=
=
= nil nil
get2Min
get2Max
(
(
;
; rRoll rRoll
);
);
...
17.
18.
19.
20.
21.
22.
23. ...
24. end
25. ...
26. end end else end setTotal ( resultMax broadcastTotal ();
+ rRoll .
nMod );
Seite 12
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
Zuerst wird überprüft, ob mit mindestens 2 Würfeln gewürfelt wurde und ob es sich bei diesen um
W10 handelt. Dadurch wird sichergestellt, dass Risiko- und Sicherheitswürfe nur mit W10-Würfeln und mindestens 2 Würfeln stattfinden.
2.2.1.1 Sicherheitswurf
Danach werden die Risiko- und Sicherheitswürfe ausgewertet. Wenn die Variable throwmode den
Wert 1 hat, dann handelt es sich um einen Sicherheitswurf. Bei diesem wird nur der höchste Würfel gewertet. Um diesen festzustellen wird der Wurf, der im Objekt rRoll gespeichert ist an die Funktion
get1Max() übergeben.
00. function get1Max ( rRoll )
01. local sum = 0 ;
02. local maxA = 0 ;
03.
04. for _ , v in ipairs ( rRoll .
aDice ) do
05. if maxA == 0
06.
07. then maxA = v .
result ; elseif v .
result > maxA 08.
09.
10. then maxA = v .
result ;
11.
12. end end
13. sum = maxA ;
14. return sum ;
15. end
In dieser Funktion werden die Werte aller Würfel im rRoll-Objekt ausgewertet und der größte Wert in der Variablen maxA gespeichert. Der Wert von maxA wird dann in der Variablen sum gespeichert, die gleichzeitig auch der Rückgabewert der Funktion ist. Dieser Rückgabewert wird in der Funktion
createActionMessage() in der Variablen resultMax gespeichert. Diese wird daraufhin mit dem
Modifikator zusammengerechnet und an die Funktion setTotal() übergeben.
2.2.1.2 Risikowurf
Hat die Variable throwmode den Wert 2, dann handelt es sich um einen Risikowurf. Hier werden die beiden höchsten Ergebnisse zusammenaddiert. Da es allerdings bei Risikowürfen auch zu Patzern kommen kann, müssen auch die beiden niedrigsten Ergebnisse gefunden werden. Dies geschieht jeweils über die Funktionen get2Min() und get2Max().
00. function get2Min ( rRoll )
01. local sum = 0 ;
02. local minA = 0 ;
03. local minB = 0 ;
04. local iMinA = 0 ;
05.
06. for _ , v in ipairs ( rRoll .
aDice ) do
07.
08. if minA == 0 then
09.
10. minA = v .
result ; iMinA = v ;
Seite 13
Splittermond Ruleset für Fantasy Grounds II
11.
12.
13.
14.
15.
16. end elseif end
v .
result then minA = iMinA
v
=
<
.
v
minA result
;
;
17. for _ , v in ipairs ( rRoll .
aDice ) do
18. if v ~= iMinA then
19. if minB == 0 then 20.
21.
22.
23.
24. elseif v minB
.
result then minB
=
=
v
v
.
<
.
result
minB result
;
;
25.
26. end end
27. end
28. sum = minA + minB ;
29. return sum ;
30. end
31.
32. function get2Max ( rRoll )
33. local sum = 0 ;
34. local maxA = 0 ;
35. local maxB = 0 ;
36. local iMaxA = 0 ;
37.
38. for _ , v in ipairs ( rRoll .
aDice ) do
39. if maxA == 0 then 40.
41.
42.
43. elseif v maxA iMaxA
.
= v
= v result
.
> result
;
;
maxA
44.
45.
46.
55.
56.
57.
58.
59. end end then end maxA = iMaxA
v
=
.
v result
;
47.
48. end end
49. for _ , v in ipairs ( rRoll .
aDice ) do
50.
51. if v ~= iMaxA then if maxB == 0 then 52.
53.
54. elseif v maxB
.
= v result
.
> result
maxB
; then maxB =
;
v .
result ;
Entwickler-Handbuch
Seite 14
Splittermond Ruleset für Fantasy Grounds II
60. sum = maxA + maxB ;
61. return sum ;
62. end
Entwickler-Handbuch
Beide Funktionen finden jeweils die zwei niedrigsten bzw. höchsten Werte, rechnen diese zusammen und speichern sie in der Variablen sum, die gleichzeitig der Rückgabewert ist.
Dieser Rückgabewert wird in der Funktion createActionMessage() in der Variablen resultMax gespeichert. Diese wird daraufhin mit dem Modifikator zusammengerechnet und an die Funktion
setTotal() übergeben.
00. function setTotal ( sum )
01. totalSum = sum ;
02. ...
03. end
In dieser Funktion wird der Gesamtwert in der Variablen totalSum gespeichert.
Nachdem dies geschehen ist, wird in der Funktion createActionMessage() die Funktion
broadcastTotal() aufgerufen.
00. function broadcastTotal ()
01. local msgOOB = {};
02. msgOOB .
type = OOB_MSGTYPE_TOTAL ;
03. msgOOB .
sum = totalSum ;
04. Comm .
deliverOOBMessage ( msgOOB );
05. end
In dieser Funktion wird die Variable totalSum in deiner Out of Bounds-Message an alle anderen
Clients gesendet. Diese empfangen diese Nachricht über den OOBManager.
00. OOB_MSGTYPE_TOTAL = "total" ;
01.
02. function onInit ()
03. ...
04. OOBManager .
registerOOBMsgHandler ( OOB_MSGTYPE_TOTAL , setReceivedTotal );
05. end
Dieser wird in der onInit() Funktion erstellt und ruft sobald eine Nachricht empfangen wird die
Funktion setReceivedTotal() auf.
00. function setReceivedTotal ( msg )
01. totalSum = msg .
sum ;
02. end
Diese Funktion speichert den empfangenen Totalwert in der Variablen totalSum. So ist sichergestellt, dass alle Spieler den gleichen Totalwert des Wurfes im Chatfenster angezeigt bekommen.
Die Anzeige des Totalwertes übernimmt die Funktion onDiceTotal() der Datei chat_window.lua.
00. function onDiceTotal ( messagedata )
Seite 15
Splittermond Ruleset für Fantasy Grounds II
01. local showTotal = ActionsManager .
getTotal ();
02. if showTotal ~= 0 then return true , showTotal end
03. end
Entwickler-Handbuch
Diese ruft die Funktion getTotal() der Datei manager_action.lua auf, welche die Variable totalSum also den Totalwert zurückgibt. Wenn dieser Wert nicht 0 ist, dann wird als Totalwert im Chatfenster der übergebene Wert angezeigt. Ist dieser Wert 0, dann wurde kein Normal-, Sicherheits- oder
Risikowurf gewürfelt und die Standardfunktion zur Berechnung und Anzeige des Totalwerts, welche in Fantasygrounds integriert ist, wird verwendet.
2.2.2 Patzer und Triumph
Ein Patzer entsteht dann, wenn die Summe der beiden niedrigsten Würfel maximal 3 ergibt. Ein
Triumph entsteht, wenn die Summe der beiden höchsten Würfel mindestens 19 ergibt.
Diese Funktionalität wurde ebenfalls in der Datei manager_actions.lua integriert. In der Funktion
createActionMessage(), welche auch für den Risiko- und Sicherheitswurf zuständig ist, wird auch auf
Patzer und Triumph überprüft.
Da diese Funktionalität beim Sicherheitswurf nicht existiert und für Normal- und Risikowurf gleich ist, wird sie hier beispielhaft anhand des Normalwurfes gezeigt.
00. function createActionMessage ( rSource , rRoll )
01. ...
02. if #( rRoll .
aDice ) > 1 and rRoll .
aDice [ 1 ].
type == "d10" then
03. if throwmode == 0 then 04.
05.
06.
07.
08. local local
resultMin
resultMax resultMin resultMax
=
=
=
= nil nil
get2Min
get2Max
(
(
;
; rRoll rRoll
);
); local patzer = false ; 09.
10.
11.
12.
13.
14.
15.
16.
17.
18. local if
triumph patzer = triumph
= false
checkPatzer
=
patzer then rMessage rMessage setTotal
.
.
(
(
; resultMin
checkTriumph font text
(
=
=
PATZER!" resultMin broadcastTotal
;
();
);
); resultMax
"redfont"
rMessage
);
.
; text ..
" –
19.
20.
21.
22.
23.
24.
25.
26.
27.
28. elseif triumph then else end rMessage rMessage setTotal
.
.
font text
=
=
"greenfont"
rMessage
TRIUMPH!"
( resultMax broadcastTotal setTotal ( total broadcastTotal
();
(
();
;
+ rRoll rRoll ));
.
.
; text nMod
..
);
" –
Seite 16
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
29.
30. ...
31. end
32. ...
33. end end
Zuerst werden, wie bereits unter Punkt 2.2.1 beschrieben die Minimal- und Maximalsumme des
Wurfes bestimmt. Daraufhin werden die Funktionen checkPatzer() und checkTriumph() aufgerufen, denen jeweils die Variablen resultMin und resultMax übergeben werden.
00. function checkPatzer ( sum )
01. if sum <= 3 then return true ;
02. else return false ;
03. end
04. end
05.
06. function checkTriumph ( sum )
07. if sum >= 19 then return true ;
08. else return false ;
09. end
10. end
In der Funktion checkPatzer() wird überprüft, ob der übergebene Wert kleiner oder gleich 3 ist. In der Funktion checkTriumph(), ob der Wert größer oder gleich 19 ist. Beide Funktionen geben bei
Erfüllung der Bedingung true, bei Nichterfüllung false zurück.
In der Funktion createActionMessage() werden diese Rückgabewerte dann in den Variablen patzer und triumph gespeichert. Danach wird überprüft, ob sie wahr oder falsch sind. Zuerst wird auf Patzer
überprüft, da bei einem Patzer kein Triumph mehr möglich sein kann. Ist die Variable patzer true, dann wird der Standard-Nachricht des Wurfes mit roter Schrift der Text „—PATZER!“ angefügt. Ist die
Variable patzer false, aber die Variable triumph true, dann wird der Standard-Nachricht mit grüner
Schrift der Text „—TRIUMPH!“ angefügt. Dieser Text erscheint jeweils neben dem Namen des handelnden Spielers.
2.2.3 Proben und Erfolgsgrade
Um Würfelproben zu ermöglichen wird, wie bereits für die Risiko- und Sicherheitswürfe ein eigener
Button erstellt, der sich ebenfalls unter dem Chatfenster befindet. Dazu wird auch hier in der Datei
desktop_panels.xml zuerst ein Panel erstellt.
00. <panel name = "checks" modes = "host,client" >
01. <class> checks </class>
02. <bounds> 185,-98,64,57 </bounds>
03.
04.
<dynamic />
<locked />
05. </panel>
Bis auf den Namen, die verknüpfte Klasse und die Position ist hier alles identisch mit dem Panel unter
2.2.1. Erst bei der Erstellung des Buttons in der Datei desktop_classes.xml gibt es Unterschiede.
Seite 17
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
00. <windowclass name = "checks" >
01. <sizelimits>
02. <minimum width = "64" height = "57" />
03. </sizelimits>
04. <noclose />
05. <sheetdata>
06.
07.
<genericcontrol>
<anchored position = "insidetopleft" width = "64" height = "57" />
<icon> checksIco </icon> 08.
09.
10.
</genericcontrol>
<stringcontrol name = "label" >
<bounds> 5,34,54,12 </bounds> 11.
12.
13.
14.
15.
16.
17.
18.
<font>
<static
<center />
</stringcontrol>
<numbercontrol
<bounds>
<min> 0 optionset text name =
=
</min>
</font>
"Probe"
"checkNumbers"
0,0,64,45
/>
>
</bounds>
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
<font> modcollector
<script>
</font> function onWheel(notches) local val = getValue(); if notches == 1 then elseif notches == -1 then end setValue(val+1); setValue(val-1); return true;
29.
30.
31.
32.
33. end function onValueChanged()
ActionsManager.setCheckValue(getValue()); end
34.
35.
</script>
</numbercontrol>
36. </sheetdata>
37. </windowclass>
Im Gegensatz zum Risiko- und Throwmode-Button werden hier im Tag <sheetdata> mehrere
Controls erstellt. Die erste ist das Tag <genericcontrol>, in dem der Ankerpunkt, sowie das Icon festgelegt werden.
Darauf folgt ein <stringcontrol> Tag, in dem die Beschriftung des Buttons generiert wird. Zuerst wird dazu im <bounds> Tag, wie bereits aus dem Panel bekannt, die Position bestimmt. Danach wird im
Tag <font> die Schriftart bestimmt. Das <static> Tag ermöglicht über das text-Attribut die Anzeige des eigentlichen Textes. Das <center> Tag zentriert das Ganze dann.
Nun folgt ein <numbercontrol> Tag. Dieses dient der Darstellung und des Umgangs mit Zahlen.
Zuerst wird auch hier wieder die Position bestimmt. Danach wird über das Tag <min> der
Seite 18
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
Minimalwert festgelegt, den dieses Control-Element einnehmen kann. Zuletzt wird dann die
Schriftart bestimmt.
Im darauffolgenden Script gibt es zwei Funktionen. Die Funktion onWheel() wird ausgelöst, wenn sich der Mauszeiger über dem Element befindet und das Scrollrad betätigt wird. Wenn der Wert positiv ist, wird der Zahlenwert des Control-Elements um 1 erhöht, ist er negativ, wird er um 1 erniedrigt. Die Funktion onValueChanged() wird jedes Mal aufgerufen, wenn sich der Wert der
Number-Control ändert. Diese Funktion ruft wiederum die Funktion setCheckValue() in der Datei
manager_actions.lua auf und übergibt ihr den aktuellen Wert.
00. local checkVal = 0 ;
01.
02. function setCheckValue ( val )
03. checkVal = val ;
04. end
Diese Funktion speichert den übergebenen Wert dann in der lokalen Variablen checkVal.
Findet nun ein Wurf statt, so wird im Laufe der Funktionsaufrufe die Funktion setTotal() aufgerufen, die wiederum die Funktion getSuccessLevel() aufruft.
00. function getSuccessLevel ()
01. local eg = 0 ;
02. local txt = "" ;
03. if checkVal ~= 0 then
04. if totalSum checkVal > 0 then if totalSum checkVal < 3 then 05.
06.
07.
08.
09. elseif eg txt
totalSum eg
=
=
=
0
1
;
" - Knapp gelungen! "
;
checkVal < 6 then txt = " - Gelungen! " 10.
11.
12.
13.
14.
15.
16.
17.
18.
19. elseif elseif elseif
totalSum eg = txt =
2 ;
checkVal <
" - Gelungen! "
totalSum eg = txt
totalSum eg = txt
=
=
3
4
;
checkVal <
9
12 then
" - Gut gelungen! "
;
checkVal < 15 then
" - Gut gelungen! " then
20.
21.
22.
23.
24.
25.
26.
27.
28. elseif totalSum checkVal < 18 then elseif elseif eg = txt =
5 ;
" - Herausragend gelungen! "
totalSum eg = txt =
6 ;
checkVal < 21 then
" - Herausragend gelungen! "
totalSum eg = txt =
7 ;
checkVal < 24 then
" - Herausragend gelungen! "
Seite 19
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42. elseif elseif elseif elseif elseif
totalSum eg txt
;
-
" - Herausragend gelungen! "
totalSum eg txt
;
-
" - Herausragend gelungen! "
totalSum eg txt
totalSum eg txt
totalSum eg
=
=
=
=
=
=
=
=
=
8
9
10
" - Herausragend gelungen! "
11
-
" - Herausragend gelungen! "
12
;
;
;
-
-
checkVal
checkVal
checkVal
checkVal
checkVal
<
<
<
<
<
27
30
33
36
39 then then then then then
43.
44. end txt = " - Herausragend gelungen! "
45. ChatManager .
CustomMessage ( "Erfolgsgrad: "
46. txt ..
" (Probe gegen " ..
checkVal ..
")" , "greenfont" );
..
eg ..
47. elseif totalSum checkVal < 0 then if totalSum checkVal > 3 then 48.
49.
50.
51. elseif eg = txt =
0 ;
" - Knapp misslungen! "
totalSum checkVal > 6 then eg = 1 ; 52.
53.
54.
55.
56.
57.
58.
59. elseif elseif txt = " - Misslungen! "
totalSum eg = txt =
2 ;
checkVal > 9
" - Misslungen! "
totalSum eg = txt =
3 ;
-
checkVal > 12 then then
" - Schwer misslungen! " elseif totalSum checkVal > 15 then elseif elseif elseif elseif elseif eg eg eg
= txt
= txt
= txt
=
=
=
-
-
-
4
" - Schwer misslungen! "
totalSum eg = txt =
5
totalSum
totalSum
8 ;
-
checkVal
checkVal
>
>
-
-
18
27 then then
" - Verheerend misslungen! "
totalSum eg = txt =
6
" - Verheerend misslungen! "
7
;
;
" - Verheerend misslungen! "
" - Verheerend misslungen! "
totalSum eg = txt =
9
;
;
;
-
-
-
-
checkVal
checkVal
checkVal
>
>
>
-
-
-
21
24
30 then then then
" - Verheerend misslungen! "
Seite 20
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
78.
79.
80.
81.
82.
83. elseif elseif
totalSum eg = txt =
10
> 33 then
" - Verheerend misslungen! "
totalSum eg = txt =
11
-
;
-
;
checkVal
checkVal > 36 then
" - Verheerend misslungen! "
84.
85.
86. elseif totalSum eg = txt =
12
-
;
checkVal > 39 then
" - Verheerend misslungen! "
87.
88.
91. end
ChatManager .
CustomMessage ( "Erfolgsgrad: "
89. txt ..
" (Probe gegen " ..
checkVal ..
")" , "redfont" );
90. end
..
eg ..
local nControl = Interface .
findWindow ( "checks" , "checks" ); nControl .
checkNumbers .
setValue ( 0 ); 92.
93.
94. end
95. end checkVal = 0 ;
Diese subtrahiert jeweils den aktuellen Totalwert des Wurfes mit dem Probenwert. Aus der Differenz ergibt sich dann der Erfolgsgrad. Zusätzlich zum Erfolgsgrad wird auch die jeweilige Auswirkung festgestellt. Diese beiden Werte werden dann über die Funktion Chatmanager.CustomMessage() an die Chatfenster aller Clients weitergeleitet. Ein positiver Erfolgsgrad erscheint in grüner, ein negativer in roter Schrift. Zuletzt wird der Wert der Number-Control wieder auf 0 zurückgesetzt. Dazu wird die
Funktion Interface.findWindow() aufgerufen, welche das Fenster checks findet. Diese Referenz wird in der Variablen nControl gespeichert. Über diese kann dann per Punktnotation die Number-Control aufgerufen und mit der Funktion setValue() der Wert gesetzt.
2.2.4 Wurf teilen
Da manche Würfe des GM’s nicht für die Spieler sichtbar sein sollen, wurde die Funktion implementiert, dass er festlegen kann, ob ein Wurf geteilt wird, oder nicht. Dazu verfügt er über eine
Checkbox unter dem Chatfenster. Für diese wird, wie vorher schon beschrieben in der Datei
desktop_panels.xml ein Panel erstellt.
00. <panel name = "reveal" modes = "host" >
01.
02.
<class> reveal </class>
<bounds> 310,-126,80,16 </bounds>
03. <dynamic />
04. <locked />
05. </panel>
Im Gegensatz zu den anderen Panels, ist im <panel> Tag das Attribut modes nur auf den Wert host gesetzt. Somit kann nur der GM dieses Panel sehen. Die Verknüpfte Klasse reveal befindet sich wieder in der Datei desktop_classes.xml.
00. <windowclass name = "reveal" >
01. <sizelimits>
02. <minimum width = "80" height = "16" />
03. </sizelimits>
04. <noclose />
Seite 21
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
05. <sheetdata>
06.
07.
<stringcontrol name = "label" >
<anchored position = "insidetopleft" width = "80"
08. height = "12" />
09.
10.
<font> mini_name
<static text
</stringcontrol>
=
</font>
"Wurf teilen" />
11.
12.
13.
<buttoncontrol >
<anchored position = "insideright" width = "12"
14. height = "12" />
15.
16.
17.
18.
19.
20.
<state
<state icon icon
<default>
<script>
0
=
=
"button_checkoff"
"button_checkon"
</default>
/>
/> function onButtonPress() local val = getValue();
21.
22.
23. end
</script>
24. </buttoncontrol >
25. </sheetdata>
26. </windowclass>
ActionsManager.setSecret(val);
Alle Elemente sind bereits aus Punkt 2.2.1 und 2.2.3 bekannt. Der Checkbox-Effekt wird durch 2
Zustände erzeugt: Zustand 0 ist die Checkbox ohne, Zustand 1 die Checkbox mit Haken. Die Funktion
onButtonPress() wird auch hier auf Mausklick ausgelöst und ruft wiederum die Funktion setSecret() in der Datei manager_actions.lua auf, der sie den Wert der Checkbox übergibt.
00. local secret = true ;
01.
02. function setSecret ( val )
03. if val == 0 then secret = true ;
04. elseif val == 1 then secret = false ;
05. end
06. end
In dieser Funktion wird die lokale Variable secret auf true gesetzt, wenn der übergebene Wert 0 ist und umgekehrt auf false, wenn der übergebene Wert 1 ist. Bei der Auswertung eines Wurfes wird der Wert dieser Variablen dann in der Funktion createActionMessage() weiter verarbeitet.
00. function createActionMessage ( rSource , rRoll )
01. ...
02. if User .
isHost () then
03.
04. end rMessage .
secret = secret ;
05. ...
06. end
Seite 22
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
Wenn der User GM ist, dann wird das secret-Attribut der Wurfnachricht auf den Wert der Variable
secret gesetzt. Ist diese false, wird das Ergebnis mit allen geteilt.
2.3 Tick-Fenster (Combat Tracker)
Das Tick-Fenster lässt sich im Ordner ct (Combat-Tracker) anpassen. Innerhalb dieses Ordners finden sich drei XML-Dateien. Eine für die Anzeige für den Host, eine für den Client und die dritte Datei dient als Template. Im Ordner scripts werden wie üblich alle LUA-Dateien aufbewahrt, welche vom
Combat-Tracker benötigt werden. Eine Ausnahme bilden die zwei Dateien manager_combat.lua und manager_combat2.lua. Diese sind im Haupt-Skript-Ordner untergebracht und die enthaltenen
Funktionen über CombatManager und CombatManager2 adressierbar.
Seite 23
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
3 Anpassungen an Modulen
Um Änderungen an Modulen vorzunehmen, sollten zunächst – falls nicht schon eingestellt – über die
Ordneroptionen die Endungen der Dateitypen eingeblendet werden. Die Module sind von dem Typ
.mod was mit dem Containerformat .zip zu vergleichen ist. Das bedeutet, dass in dieser .mod-Datei mehrere Dateien zusammengefasst sind. Um die einzelnen Dateien einsehen und bearbeiten zu können, muss die Dateiendung .mod in .zip umbenannt werden. Die Datei wird dadurch nicht verändert, kann nun aber mit einem gewöhnlichen Komprimierungsprogramm (WinZIP) entpackt werden.
3.1 Zauberbibliothek
Die Zauberbibliothek (zauber.mod) besteht aus den drei Dateien client.xml, definition.xml und thumbnail.png. Die Funktion der Grafikdatei dürfte selbsterklärend sein. Die definition.xml muss für eine Erweiterung der Zauberbibliothek auch nicht beachtet werden, hier werden nur Namen des
Autors sowie des Rulesets angegeben.
Das Verwalten der Zauber geschieht nahezu ausnahmslos in der client.xml. Die verschiedenen
Zauberschulen werden in dem Listenelement entries angelegt. Sämtliche Zauberschulen sind in unserer aktuellen Version bereits definiert.
00.
<entries>
01.
<bann>
02.
03.
04.
05.
06.
<librarylink
<class>
<recordname> spelllistsMine.bann@Zauber
</librarylink>
<name
= "windowreference" reference_classspelllist type = type
"string" > Bannmagie
>
</class>
</name>
</recordname>
07.
</bann>
08.
…
09.
</entries>
Ein angelegter Zauber befindet sich im spelldesc Element und ist folgendermaßen aufgebaut:
00.
<spelldesc static = "true" >
01.
<wahrerBlick>
02.
03.
<spell_name type
<spell_school
= "string" type =
> Wahrer Blick
"string" > Bann
</spell_name>
</spell_school>
04.
05.
06.
<spell_schw
<spell_focus type type
<spell_casttime
= "string"
= "string" type =
> 15
>
</spell_schw>
1 K
"string" >
</spell_focus>
1 Tick </spell_casttime>
07.
08.
09.
10.
11.
12.
13.
<spell_range kanalisiert
Illusionen type
<spell_duration
= "string" type =
> Zauberer
"string"
</spell_duration>
<spell_description type =
>
"string"
</spell_description>
<spell_archievement type =
>
"string"
</spell_range>
Erlaubt erkennen von
> 1-EG: Auslösezeit,
Verstärken (s. u.) \n2-EG(Kosten +K1V1): Die Probe geht
14.
15.
Gegen die normale Schwierigkeit des
Illusionszaubers.
</spell_archievement>
16.
<spell_page type = "string" > S. 251 </spell_page>
17.
18.
</wahrerBlick>
…
19.
</spelldesc>
Seite 24
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
Die Variablen der Attribute und Beschreibungen haben wir versucht möglichst aussagekräftig zu benennen, so dass diese hier nicht weiter beschrieben werden müssen. Trat ein Zauber in mehreren
Zauberschulen auf, wurde dieser mehrfach leicht verändert angelegt. Die Namen der Variablen können in der Datei strings_35e.xml (\rulesets\Splittermond\strings\) verändert werden.
Als nächster Schritt müssen die angelegten Zauber den jeweiligen Zauberschulen zugeordnet und in die entsprechende Levelklasse eingestuft werden. Dies geschieht im Element spelllistsMine. Das folgende Beispiel zeigt die Bannzauber des Level 0:
00.
<bann>
01.
<description type = "string" > Bann </description>
02.
03.
04.
<groups>
<level0>
<description type = "string" > Level 0 </description>
05.
06.
07.
08.
09.
10.
11.
12.
<spells>
<wahrerBlick>
<link type
<class>
<recordname> wahrerBlick@Zauber
</link>
<level
= type
"windowreference"
= spelldesc
> spelldesc.
"number" > 0
</class>
</recordname>
</level>
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
</wahrerBlick>
<behindern>
</spells>
</level0>
<link type
<class>
<recordname> behindern@Zauber
</link>
<level
</behindern>
= type
"windowreference"
= spelldesc spelldesc.
"number" > 0
>
</class>
</recordname>
</level>
Nach der Bearbeitung müssen die Dateien wieder in das mod-Format zurück gewandelt werden. Dies funktioniert wie das Entpacken nur in umgekehrter Reihenfolge: Dateien in .zip-Format archivieren und anschließend die Endung in .mod umbenennen.
3.2 Anzeige ändern
Die tabellarische Ansicht der Zauberbibliothek kann in der Datei ref_spells.xml
(\rulesets\Splittermond\ref\) angepasst werden. Hier wird zum einen festgelegt welche Werte angezeigt werden sollen und wie groß die Abstände der Spalten sein sollen.
3.3 Module einbinden
Wie im Benutzerhandbuch erklärt muss zunächst die .mod-Datei in das entsprechende Verzeichnis kopiert werden. Damit dieses Modul vom Ruleset auch initialisiert wird muss dieses in einer Datei vermerkt werden. Diese Datei befindet sich im Kampagnenordner eures Splittermondverzeichnisses
(/campaigns/) und heißt modulestate.xml. Hier werden alle Module eingetragen die beim Start des
Rulesets von FantasyGrounds geladen werden und dem Spieler anschließend zur Verfügung stehen:
00.
<modulestate version = "3.1" >
01.
<module name = "FG Battle Maps" >
02.
03.
<loaded
</module>
/>
04.
05.
06.
<module name =
<loaded
"Zauber"
/>
<allow />
>
Seite 25
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
07.
</module>
08.
</modulestate>
Der optionale Wert allow gibt an ob das Modul von Beginn an für Mitspieler freigeschaltet ist oder erst vom Spielleiter aktiviert werden muss.
Seite 26
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
4 Design
In diesem Kapitel befassen wir uns mit der Anpassung des Designs für das Splittermond Fanprojekt in
Fantasy Grounds II.
Auf die Kreation eigener Grafiken, Buttons und anderer Elemente in einem externen Grafikprogramm wird in diesem Handbuch nicht eingegangen. Zur Änderung/Implementierung des Designs wird ausschließlich XML benötigt.
4.1 Grundaufbau
In Fantasy Grounds II befinden sich die Grafikelemente unter
Fantasy Grounds/Data/rulesets/‘Rulesetname‘/graphics
Darin befinden sich diverse Unterordner:
/buttons Diverse Button-Grafiken
/fonts
/frames
/icons
/portraits
/radial
/sidebar
/tabs
Schriften
Rahmen, Fenstergrafiken und Elemente, Hintergrundelemente
Icon-Grafiken
Elemente für die Charakterportrait-Darstellung
Icons für das Rechtsklickmenü
Buttons für die Hauptmenüleiste am rechten Bildschirmrand
Icons und Elemente für die Tabs einzelner Fenster
/tokens
/toolbar
Mitgelieferte Token-Bilder
Elemente für die Toolbar des Bilder und Kartenfensters
Natürlich ist es jeder Zeit möglich, eigene Ordner anzulegen oder Grafiken an anderen Orten zu speichern. Für das Splittermond Fanprojekt wurde die standardisierte Struktur von Fantasy Grounds
II beibehalten und wird daher auch so in diesem Handbuch wiedergegeben. Die meisten vorhandenen Grafikelemente wurden der Einfachheit halber mit demselben Namen ersetzt, dies erspart uns diverse Umbenennungen in den zugehörigen XML-Dateien.
Die Struktur dieser XML-Dateien ist zu Beginn nicht einfach nachvollziehbar. So liegen alle grafisch relevanten XML-Dateien so ziemlich in jedem Ordner des Ruleset-Hauptverzeichnisses verteilt. Die
Benennung einzelner Elemente ist nicht immer eindeutig, so fällt es schwer, einzelne Elemente wie etwa ein bestimmtes Fenster, über mehrere XML-Dateien zu finden. Im Splittermond Fanprojekt wurde durch sinnige Kommentare versucht, diesen ungünstigen Umstand zu minimieren.
Seite 27
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
4.1.1 Technik
Fantasy Grounds II verwendet diverse Techniken bei der Darstellung. Wir erklären die wichtigsten
Prinzipien die es für ein gelungenes eigenes Design zu beachten gilt.
4.1.2 Skalierung
Die Software bietet prinzipiell keine verschiedenen Darstellungsoptionen wie etwa Auflösung oder generelle Qualitätseinstellungen. Fantasy Grounds II startet generell in einer Minimalauflösung von etwa 1024 mal 768 Pixel. In den Settings lässt sich jedoch die UI-Scale, von 50-200% einstellen. So lässt sich auf einem Bildschirm mit zu geringer Auflösung die UI verkleinern, um eine optimale
Darstellung zu gewähren. Werte über 100% sind hingegen nicht zu empfehlen, da sie die vorhandenen Grafiken strecken was einen sichtbaren Qualitätsverlust mit sich bringt. Das
Splittermond Fanprojekt ist für die HD-Auflösung von 1920x1080 Pixel optimiert, doch wie bereits erwähnt, sind, was die Darstellungsqualität angeht, auch alle anderen Auflösungen funktional.
Abbildung 1: Skalierung 100% Abbildung 2: Skalierung 150%
Dennoch lässt sich Fantasy Grounds II bei jeder beliebigen Auflösung auch im Vollbild-Modus spielen.
Um dabei stets die gleiche Anzeigequalität zu liefern, nutzt das Programm eine simple
Skalierungstechnik: und zwar werden alle Grafikelemente mit Inhalt, wie zum Beispiel das Chat-
Fenster oder die gesamte Hintergrundebene, durch sogenannte „Blueprints“ erstellt. Dies Bedeutet, die beispielsweise Für ein Fenster genutzte Grafik wird, je nach Inhalt, aufgebrochen und einzelne
Teile Wiederholt. So kann die Oberfläche von Fantasy Grounds II skaliert werden ohne
Qualitätsverlust.
Ein ausführliches Beispiel ist in Kapitel 1.5.2.2 zu finden.
4.1.3 MouseOver Effekte
Ähnlich wie bei der Webprogrammierung mit HTML/CSS lassen sich auch hier einfache MouseOver-
Effekte erstellen. Kommt der Mauszeiger in einen definierten Bereich, wird das dort befindliche Bild durch ein anderes ausgetauscht. Verlässt der Mauszeiger den Bereich wieder, so erscheint wieder das Ursprungsbild.
4.1.4 OnClick Effekte
Sehr Ähnlich zu den MouseOver Effekten. Der Auslöser für einen Bildwechsel ist hier allerdings der
Klick auf ein Objekt, meist Button.
Seite 28
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
4.1.5 Drag Effekt
Diverse Elemente in Fantasy Grounds II lassen sich durch drag, also Klicken und halten der linken
Maustaste, in beispielsweise andere Fenster ziehen. Eine sehr gängige Anwendung zum Beispiel beim
Einfügen von Kampfteilnehmern im Combat Tracker.
4.2 Hintergrund
Verwendete XML-Dateien:
‘Ruleset‘/elements.xml
‘Ruleset‘/graphics/graphics_frames.xml
‘Ruleset‘/desktop/desktop_panels.xml
‘Ruleset‘/graphics/graphics_icons.xml
Um unseren eigenen Hintergrund mit Splittermond Fan-Logo einzubinden, bedarf es einiger
Anpassungen in den oben genannten XML-Dateien.
Um unser Logo unabhängig vom gemusterten Hintergrund immer zentral darstellen zu können, müssen wir dieses als eigenes Frame definieren und darstellen (Punkt X). Aus dem restlichen
Hintergrund erstellen wir einen Blueprint (siehe 1.1.3).
1. Hintergrundbild Blueprint
In der ELEMENTS .
XML ist als erstes Root-Element das Desktopframe definiert,
00. <desktopframe> desktop </desktopframe> hier ist es wichtig, dass der eingetragene Name (desktop) mit der Definition (name=“ “) im
GRAPHICS _ FRAMES .
XML übereinstimmt. Außerdem setzten wir hier den Pfad zu unserem verwendeten
Bild.
00. <framedef name = "desktop" >
01.
02.
03.
<bitmap file = "graphics/frames/desktop-bg.jpg" />
<left rect = "0,0,1785,1080" />
<right rect = "1785,0,135,1080" />
04. </framedef>
Für den Blueprint zerschneiden wir in Gedanken das Bild in 2 Flächen. <left> beginnt ganz links oben im Eck bei den Koordinaten 0,0 und umfasst eine Breite von 1785 Pixel bei voller. Mit <right> definieren wir die steinerne Sidebar, diese hat eine Höhe von 1080 und eine Breite von 135 Pixel, und beginnt dementsprechend bei einem x-Wert von 1785.
Abbildung 3:Hintergrund Splittermond-Ruleset
Seite 29
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
2. Fanlogo einfügen
Wie bereits erwähnt, erhält das Logo einen eigenen Frame, und lässt sich so unabhängig vom
Hintergrundbild platzieren.
Hierfür erstellen wir ein Panel in der DESKTOP _ PANELS .
XML .
00.
03.
<panel name = "BGlogo" modes = "host,client" >
01.
02.
<class> BGlogo </class>
<bounds> 0,0,-1,-1
</panel>
<disabled />
</bounds>
04.
Das Panel erhält einen Namen und eine Klasse unter modes werden host und client eingetragen, damit beide Spielerklassen das Logo auch sehen. Mit <bounds> definieren wir die Positionierung des
Logos. Hier setzen wir nur jeweils -1 in die eigentlichen Breiten- und Höhenangaben, so erhalten wir ein Zentriertes Panel.
Zuletzt setzen wir das Panel auf disabled, andern Falls könnte man es durch das Rechtklickmenü anwählen, verschieben oder schließen, das wollen wir in diesem Fall nicht, es soll nur als Bild dienen.
Zusätzlich erstellen wir in der GRAPHICS _ ICON .
XML ein Icon mit Verweis auf das zu verwendende Bild für unser Logo.
00. <icon name = "BGlogo" file = "graphics/frames/desktop-logo.png" />
Abbildung 4: Platzierung des Splittermond-Fanlogos
4.3 Rechtsklickmenü
Auf jedem existierenden Panel oder Frame, sei es nun ein Fenster, der Hintergrund oder ein einzelnes Element, kann man per Rechtsklick ein Menü aufrufen. Je nach geklicktem Element, erhält man anhand von Radial-Buttons verschiedene Möglichkeiten zur Interaktion.
Für das Splittermond Fanprojekt wurde das Standard-Rechtsklickmenü von Fantasy Grounds II nur im
Bereich der genutzten Radial-Icons verändert. Daher sind hier keinerlei XML-Anpassungen nötig, solange man die bestehende Namensgebung verwendet.
Seite 30
Splittermond Ruleset für Fantasy Grounds II
Die Radials sind unter
/‘Rulesetname‘/graphics/radial
Entwickler-Handbuch
Zu finden.
Es existieren 103 Radial-Buttons, plus einem Zurück-Radial und dem Menü an sich.
Beispiel: Rechtsklickmenü Hintergrund-Ebene
1
2
3
4
5
Fantasy Grounds II Beenden
Vollbildmodus
Würfelposition festlegen
Würfelposition zurücksetzen
Radial Menü
Abbildung 5: Radial-Menü
4.4 Sidebar
Die Sidebar beinhaltet alle wichtigen Fenster zur Verwendung von
Fantasy Grounds 2. Designtechnisch relevant sind demnach die einzelnen Buttons zum Aufrufen dieser. Die Erstellung des steinernen
Hintergrundes wurde bereits in Kapitel 1.2 erläutert.
Alle benötigten Grafiken befinden sich unter
/‘Rulesetname‘/graphics/sidebar
Jeder Button existiert zweimal, einmal im normalen Zustand und für einen OnClick-Effekt.
Bei den großen Themen-Buttons wird bei diesem der Schatten der
Buttons ausgeblendet. Die kleinen steinernen Buttons erhalten gegenteilige Beleuchtungen, so wirkt es als würden sie in den Stein hineingedrückt.
Abbildung 6: Sidebar
Seite 31
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
4.5 Fenster
Die Fenster bilden den Großteil der Grafischen Darstellung in Fantasy Grounds II. Für das
Splittermond Fanprojekt wurden insgesamt 8 optisch verschiedene Fenstertypen erstellt: utilitybox Utilitybox2 referencepage chatbox tokenbag charselect Utilitybox3 Storybox /
Campaignlistwithtabs
4.5.1 Fenster-Elemente
Je nach Verwendung, besitzt ein Fenster unterschiedliche unabhängige Elemente.
1. Inhalt
[Listen, Textfelder, Tabellen…]
2. Titelleiste
3. Schließen-Button
4. Filterleiste
5. Editieren-Button
6. Tabs
7. Inhalts-Ende-Icon
8. Fenster-Skalierungs-Button
9. Button
[für weiterführende Fenster]
Abbildung 7: NPCs-Fenster aus dem Ruleset
Seite 32
Splittermond Ruleset für Fantasy Grounds II
Diese Elemente müssen für jeden Fenstertyp
erstellt
zugewiesen und
positioniert werden
Entwickler-Handbuch
Die Umsetzung all dieser Anpassungen ist in der Regel für jeden Fenstertyp gleich, daher gehen wir im Folgenden beispielhaft detailliert auf einen existierenden Fenstertyp ein.
4.5.2 Implementierung des vollständigen Story-Fensters
Anhand des meistverwendeten Fensters „campaignlistwithtabs“, gehen wir im Folgenden Schritt für
Schritt dessen Implementierung durch. Hierfür nehmen wir das „Story-Fenster“, welches sich in der
Sidebar unter „Story“ wiederfindet und editierbare Listen von Geschichten beinhaltet.
Verwendete XML-Dateien:
/campaign/ CAMPAIGN _ STORY .
XML
/graphics/ GRAPHICS _ FRAMES .
XML
/graphics/ GRAPHICS _ ICONS .
XML
/common/ TEMPLATE _ LISTS .
XML
/common/ TEMPLATE _ WINDOWS .
XML
4.5.2.1 Windowclass erstellen
Jedes Fenster besitzt eine eigene Klasse, welche in ihrer zugehörigen eigenen XML-Datei definiert wird. Für das Story-Fenster ist diese die CAMPAIGN _ STORY .
XML .
Die Klasse nennt sich encounterlist und verwendet das Frame campaignlistwithtabs , welches wir im zweiten Schritt erstellen werden.
00.
01.
02.
<windowclass name = "encounterlist" >
<frame> campaignlistwithtabs </frame>
...
Des Weiteren definieren wir hier die Anfangsgröße sowie die Minimalgröße des Fensters.
00.
01.
02.
03.
04.
05.
06.
<placement>
<size width = "545" height = "619" /> <!-- start dimension der scrollbox-->
</placement>
<sizelimits>
<minimum width
<dynamic />
</sizelimits>
= "400" height = "400" /> <!-- minimale dimension der scrollbox-->
<dynamic /> wird gesetzt, um es dem Spieler möglich zu machen, das Fenster beliebig zu Skalieren.
Folgend werden alle weiteren Elemente, die im Fenster Verwendung finden sollen, implementiert.
Auf diese gehen wir jeweils in den folgenden Schritten detaillierter ein.
4.5.2.2 Framedef erstellen
Erneut erstellen wir zuerst in der GRAPHICS _ FRAMES .
XML ein Frame für unser Fenster:
00.
01.
<!-- Story and Notes -->
<framedef name = "campaignlistwithtabs" >
02.
03.
<bitmap
<topleft file rect
=
=
"graphics/frames/scrollbox.png"
"0,0,130,90" />
/>
Seite 33
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
04.
05.
06.
07.
08.
09.
10.
11.
<top rect = "130,0,285,90" />
<topright rect = "415,0,130,90" />
<left rect = "0,90,130,494" />
<middle rect = "130,90,285,494" />
<right rect = "415,90,130,494" />
<bottomleft rect = "0,584,130,35" />
<bottom rect = "130,584,285,35" />
<bottomright rect = "415,584,130,35" />
12.
13.
<insideoffset> 0,0,40,0 </insideoffset>
</framedef>
Es wird das verwendete Fenster-Bild verknüpft. Daraufhin gilt es wiederum, den Blueprint für die
Grafik zu definieren, diesmal das volle Programm, mit allen 9 Flächen.
Bei der Skalierung wird das Fenster später nach rechts-unten erweitert, der Bildinhalt der Fläche middle wird dann, wie ein Muster, so oft wiederholt, bis die zu füllende Fläche ausgefüllt ist.
Daher ist es wichtig, dass diese
Fläche ein möglichst gleichmäßiges
Muster bildet und keine Elemente sich darin befinden, die sich nicht widerholen dürfen (z.B. ein Verlauf,
Ecken etc.).
Es empfiehlt sich daher, bereits bei der Erstellung der Grafik darauf zu achten, und die nötigen Pixelwerte zu notieren.
Abbildung 8: Unterteilung der Frames
Die Zeile <insideoffset> definiert den Punkt und die Achse, an welchem man das Fenster größer ziehen kann. An dieser Achse erscheinen beim
Drüberfahren mit der Maus Skalierungspfeile. Durch ziehen mit linken
Maustaste lässt sich so das Fenst12er vertikal, horizontal oder in beide
Richtungen gleichzeitig skalieren.
Der Standardwert beträgt hier 0,0,0,0 was bedeutet, das unterste rechte Eck des Frames. Da die Kante unseres Fensterbildes an dieser
Stelle durch die Verzierungen an der Oberseite jedoch nicht an der
Framekante liegt, müssen wir diesen Wert um 40 Pixel korrigieren.
Seite 34
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
4.5.2.3 Close Button
Jedes Fenster lässt sich mit einem Button schließen. Dieser Button befindet sich konsequent im oberen rechten Eck eines jeden Fensters. Zudem ist der Button mit einem MouseOver-Effekt sowie
OnFocus-Effekt ausgestattet, demnach benötigen wir drei Bilder bei der Erstellung des Buttons.
G RAPHICS _ ICONS .
XML
00. <icon name = "button_close" file = "graphics/buttons/button_close.png" />
01. <icon name = "button_close_down" file = "graphics/buttons/button_close_down.png" />
02. <icon name = "button_close_hover" file = "graphics/buttons/button_close_hover.png" /> hover
<template name = "close_campaignlistwithtabs" >
<close>
02.
03.
<anchored>
<top offset = "30" />
<right offset = "-40" /> down normal
In der TEMPLATE _ WINDOWS .
XML wird der Close-Button jedem Fenster zugewiesen und platziert.
00.
01.
04.
05.
06.
07.
</anchored>
</close>
</template>
Mit den Werten top und right platzieren wir den Button an unserer Gewünschten Position, durch die
Dimensionen unseres Bildes muss dieser sowohl etwas tiefer wie nach links verschoben werden.
Um den Close-Button auch in unserem Story-Fenster anzuzeigen, wird er in der zugehörigen windowclass ( CAMPAIGN _ STORY .
XML ) initialisiert:
00. <close_campaignlist />
01.
02.
4.5.2.4 Resize Button
Die meisten Fenster lassen sich manuell vergrößern oder verkleinern. In Schritt 1 haben wir für unser
Fenster bereits per <insideoffset > die Achsen definiert, bei welchen diese Funktion dem Nutzer dargestellt werden soll. Zusätzlich dazu erstellen wir noch ein Icon, welches diese Funktionalität symbolisch darstellen soll.
G RAPHICS _ ICONS .
XML
<icon
<icon name name
=
=
"window_resize" file = "graphics/icons/window_resize.png"
"window_resize_filled" file =
/>
"graphics/icons/window_resize_filled.png" />
Seite 35
Splittermond Ruleset für Fantasy Grounds II
Genau wie zuvor beim Close-Button, weisen wir dieses Icon unserem Fenster in der TEMPLATE _ WINDOWS .
XML zu, und platzieren es mit Hilfe des Offsets so, dass es genau im unteren rechten Eck sitzt:
00.
01.
<template name = "resize_campaignlistwithtabs" >
<resize>
02.
03.
04.
<anchored>
05.
06.
07.
</resize>
</template>
<right offset = "-39" />
<bottom offset = "-1" />
</anchored>
Zuletzt implementierung in unserer windowclass ( CAMPAIGN _ STORY .
XML ):
00. <resize_campaignlistwithtabs />
Entwickler-Handbuch
4.5.2.5 Filter
Wie die meisten Fenster, besitzt auch das Story-Fenster eine Filterleiste. Mit dieser lässt sich die
Anzeige der Inhalte des Fensters auf nur die Inhalte mit verwendetem Begriff eingrenzen.
Es existieren zwei Frames zum Filter. Diese sind verknüpft mit zwei Bildern, das eine im
Normalzustand, das andere bei aktivem Zustand, das heißt, wenn ein Filterbegriff eingetragen wurde.
Graphics_frames.xml
Normal
00. <framedef name = "search" >
01.
02.
03.
04.
05.
<bitmap file = "graphics/frames/search.png" />
<offset> 35,28,12,28 </offset>
<topleft rect = "0,0,35,28" />
</framedef>
Aktiv
08.
<framedef name = "search_active" >
06.
07.
<bitmap file = "graphics/frames/search_active.png" />
<offset> 35,28,12,28 </offset>
<topleft rect = "0,0,35,28" />
</framedef> 09.
Mit dem <offset> werden die linken und rechten Stücke der Leiste definiert, der Teil der Bilder dazwischen wird je nach nötiger Breite wiederholt.
Da die Filterleiste mehrfach Verwendung findet, wird dafür in der TEMPLATE _ LISTS .
XML ein template erstellt:
00. <template name = "filter" >
01. <stringcontrol>
Seite 36
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
02.
03.
04.
05.
<frame name = "search" offset = "11,5,5,5" /> <!-- Text offset -->
...
</stringcontrol>
</template>
Mit dem offset-Werts des Frames, lässt sich der Beginn des eingetippten Textes definieren, falls dieser nicht korrekt zur verwendeten Grafik passt.
Nun packen wir das allgemeine Filter-Template in ein Template speziell für unser Fenster. Dies geschieht in der TEMPLATE _ CAMPAIGN .
XML :
00. <template
01.
02.
03.
04.
05.
06.
07.
08.
09. name = "filter_campaign"
<filter name = "filter" >
<anchored height = "20" >
<top
<left
</template> parent parent
</filter>
</anchored>
=
=
>
"rightanchor"
"list" offset = offset
"55" />
= "-20" /> <!-- Filterleiste offset vertikal -->
<!-- Filterleiste offset nach links /n
<!--Rechts-->
<right parent = "rightanchor" anchor = "left" relation = "relative" offset = "-20" />
Hier lässt sich die Leiste außerdem durch die anchored-Elemente in unserem Fenster positionieren.
Zu guter Letzt wird das Filter-Template in der windowclass definiert ( CAMPAIGN _ STORY .
XML ):
00. <filter_campaign />
4.5.2.6 Edit Buttons
Die Editier-Buttons werden genau wie die Filterleiste eingefügt. Änderungen hier beschränken sich ausschließlich auf das Austauschen der Icons.
4.5.2.7 Titelleiste
Für die Anzeige des Fenstertitels kommt ein einfaches Icon zum Einsatz. Wie immer definiert in der
GRAPHICS _ ICONS .
XML :
00. <icon name = "title_story" file = "graphics/tabs/title_story.png" />
In der TEMPLATE _ CAMPAIGN .
XML wird dazu ein template kreiert. Da es sich um ein einfaches unskalierbares Bild handelt, sind keine Größendefinitionen nötig.
<template name = "banner_campaign" >
<genericcontrol>
</genericcontrol>
</template>
Beim Einfügen in die windowclass positionieren wir per <bounds> das Bild. Beim Skalieren des
Fensters bewegt es sich so mit.
CAMPAIGN _ STORY .
XML
00.
01.
02.
03.
<banner_campaign>
<icon> title_story </icon>
<bounds> 0,25,-30,40 </bounds> <!-- Windowtitle Positionierung-->
</banner_campaign>
Seite 37
Splittermond Ruleset für Fantasy Grounds II Entwickler-Handbuch
4.5.2.8 Inhalt
Im Story-Fenster befindet sich eine Liste von Texten, die sich bei einem Klick in einem weiteren
Fenster öffnen. Für uns wichtig ist hier die Anpassung an unsere Fenster-Dimensionen. Dies bewerkstelligen wir direkt in der windowclass, beim Aufruf der Liste:
CAMPAIGN _ STORY .
XML
00. <list_campaign name = "list" >
01.
02.
03.
<bounds> 45,70,-60,-60 </bounds>
...
</list_campaign>
Von unserem gesamten Frame aus gesehen, wird die Liste so 45 Pixel entfernt vom linken Rand und
70 Pixel vom obigen dargestellt. Rechts und unten herrschen jeweils 60 Pixel Abstand bevor der
Inhalt ausgeblendet wird.
4.5.2.9 Tabs
Die durchschaltbaren und gestaltbaren Tabs am unteren Fensterrand gilt es neu zu positionieren.
Dies geschieht in der TEMPLATE _ LIST .
XML , dort sind die Tabs unter dem template categories definiert:
00.
01.
02.
03.
04.
05.
06.
07.
08.
09.
<template name = "categories" > <!—Kategorie-Tabs unten am Rand der Scrollbox -->
< categoryselectioncontrol>
<anchored>
<top
<left anchor offset =
<bottom offset = "0" />
</anchored>
<gmvisibleonly />
</categoryselectioncontrol>
</template>
= "bottom"
"50" /> offset = "-38" />
4.5.2.10 Vollständiges Story-Fenster
Alle beschriebenen Implementierungen münden somit in das fertige Story-Fenster (rechts).
Abbildung 9: Story-Fenster aus dem Splittermond-Ruleset
Seite 38
advertisement
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project