Entwicklerhandbuch (Version 1.0)

Add to my manuals

advertisement

Entwicklerhandbuch (Version 1.0) | Manualzz

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

Was this manual useful for you? Yes No
Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Related manuals

Download PDF

advertisement