[Guide][Wiki-Beitrag] How-To Total RP 3 Extended ❔

Extended am Sonntag #5


Ein Minispiel: Geschenke Sortieren

Heute soll es um ein Extended-Item gehen, mit dem man ein kleines Spiel spielen kann.
In diesem geht es darum, Geschenke möglichst schnell in die richtige Kategorie (bzw. Geschenksack) einzusortieren. Wenn man den falschen Sack auswählt oder zu langsam ist, ist das Spiel zuende.

Import-Code

Probieren geht hier vor analysieren, deshalb gleich zu Beginn der Import-Code, danach die Erklärung.

Geschenksortierspiel

!TN1xtTnss8pllvQ6c5YzSSnBaxfpa2qaIrMWyc3LTwzpwASLonEgxZmcc416ZY9q(mSpLNo)f76EKKT5poqi3v7UxTa1OrJ65x)h1DpDl8C86456a)vUAzp3kEeNkvQvE7nFtTT305QRpXZTkqb5ixCmsyusCsN)HhPzBpsRJG7mEK9AJGqoC3SBpCFp3nlxgwVJ3EEesdCpAdvzWjKo4iYyclJ7i0baf(QOXW2PQH6Shq4sFkpTNp1WgkvxN2BN0EJOMWskQiqo6LoVoTx11tpoNUidBKlDeZs3lNKE8K16WccUU)SpRw71PhV2PjJhZSZouYVHfPzI(0qHDLpgjeAjpa4v2cNr1Ag3o9aP00NYZUzpAsmF2VAUjdjIFiSaJpEatfyx5ez)iE2d)inPptD1SVOgaqnfwcKQ1ElF2xcVIfLXhIjYpg0ToYbdyGSFAsqqKyyb4YyjNgKb3ju1nrJPz7ZvMmKAgRO8irUi3UV2elv9ZXvY55pypf1qhpixDiJzXjCQjkrBVVfRFCIFiqBHe6MO1XcQFmlZW9oM6MCOUGcIPy8aoBitZmz2hwatL2lreaQb4MKjT7X0gMFCbrxqv4RMdyC(OzFPW85o7ZH3WsMRUcgt7hgX6NZ5wr(HgMkMzYrTbD0yW8qt0QzFrBsal100JNU(pv4L8Z)0DDrCkV(pNEC6XGK8bQ6LOdgS6AY1WXITH3umF9vqBHdgEtX81bxE8xc8hpsdJcpsfCHQ33hpq6NmIjmD1HYRULR(Dc8s7neW(HGUgUqL7d9Luvxz))jZ)2HqxzdR3bdKjMWi9zs4TKNBnpYlMOW5tFiMufxyteA4AFWu6hcxNZpFjGr(n5sqMaaor(XDbaO3I9lymYjRaTtEQLvTrPLm18nzfr45)yX8Az7gP9tWtM9z)qWDtN27TOdetexQujiPINlKikitkGjmo9Aq(TBtGQiS4BUVX0W(0TnJTyrwx8Bss7XPIHA6OsPh3eIHTrSIyZn0qE90EVyI2xQytro6w5U2wdQaR2RWNl1S7)24nlSaNU78D25V7rMe6u3FAHgdIIwQmrmftmzJqhiUyY4PnPGr5cmQubzQ8dhaHLP9e0qtEeBqeBHvdXicxvi9dHrm8BoSMFadJ2JXI4WI7dG96jBmoJnt8L86LHFgmykzCeJJr1t2awDk4mZcN9RkyprcGFmyyzY7ZPjOeNrlbs7uc5tojBbenfsrXe6rrqwa(Tbfb7UOA3Yqi)GyvWsPiVblh4CdQHEiKntOnZ(SiG9y4NVxL0Cp0lSgWlf4seeNupsCz3rrA)U9Pd76uUBFEcR(pwB6)(FH)(W0muXyIhJiflajzotdRKX1LmStGJgIFL9O3x1sQTQK5VO)HP5InS1Wkzjai714DEUBbxrpmI7UWr8YyRBj(0dR29apYBHCshifgxPAeL3cIpyEKdoZRVh5IJYp0)qhKYMGtwK4AK4dtqQoScU87tG1Xf7MT6PfO2rk5MOXhYGJ6uEKtAIcXjqngUTZepB6WNzThqADBcZvw6Hkr09kPkEahZk)0ZULLKQ4uJ5j3s)LFPi92LlLeyP0jzBe1P2xc67Qob5bsZ)FzrDNNKGkG0HNTuQ4LYNzVfG153odSZFumWRwqFcg4Q)2zGR(hfd8Qf0hZaV45FnR8JDq9Qk7Bf1MLjA)vBTz2QgS1L58qgZVXQ(wgz18k(EqKxuQ3tc5Nx9KyvBzvS9N989N989)N98TOxIV3Us2cr6R1NWZV7rSvcY2F7z2CkJRSfsU53zDeUDXCqgVNE9)Ug5S3o)8VV2PgF)5Ox15k3t7S96DfvHTRaddOC0RBE7jpd18Ho05XCwQU49Z3A)QPhxCmsPfXm1TTTz7V5ftkIbNA7DbFY74qYualAYG820uycKOH40cm0GfWctEVz2oJW6wF1xVnTIwWkOVYkOFElB3DdvxXgYBFlV)TmR1VV7bZuiyn3h82XMkzqh9SOLTYzVo1y))aYe4vVZwG)95eSBSw4(k(0aEKgTrHg1YL(6exzZ9ZZraIPasE)U2qdWxcvs74h21McTHvVBI8PcQ4h1a8qlm0dJgy6wgIkE)(ivN7IJK9WXgwCVyFeetrBIsX5A2ZpsENVNi5VHu7zFg(NuG6tqExu3z5hsExkuoGzOrCT1aTFJUNT)UK2UDHxbhDANCGZeTIgdY2MTrDs7ZlSVMcplstqMRTHtLnQ4aNx7u3PwDhyRnW(2zC2Lm9FRtiuQd4h8bWXgIlc(aypkvRun77X7rf6RUpKLXaKB)pAqA1gLBaZBXRYBxFZ3uVgEWb6eII3rwFJZWtXjKJGlFQM1TakAL08CRV2jxK7TOz(jQiZ1TaMZT6n4E3jJ8mDKSlmvXapzDSn5KakEizu2Po9zdHYozcek8RzCe(HlSomwnZ459Fc

Dieses Item verwendet einen Lua-Skripteffekt, um die zufälligen Geschenke zu erzeugen. Daher ist die Sicherheitsstufe des Items niedrig.

Wie es funktioniert

Grundstruktur

Das Spiel-Item enthält zwei innere Dokument-Objekte. Das Dokument intro weist den Spieler in das Spiel ein, es enthält einen Link, mit dem sich das Spiel starten lässt.
Die Hauptarbeit leistet das Dokument game. Damit wird eine komplette Spielrunde modelliert, also:

  • Geschenk zufällig auswählen
  • Geschenk anzeigen
  • Aktion des Spielers auswerten

Geschenk auswählen

Jedes Geschenk wird zufällig aus 30 möglichen Geschenken ausgewählt. Diese sind vorab einer der drei Kategorien zugeordnet. Die Auswahl wird von einem Lua-Skripteffekt übernommen.
In diesem Effekt verwende ich math.random, um zufällige Werte auszuwürfeln, sowie setVar. setVar ermöglich es mir, Objektvariablen aus dem Skripteffekt heraus zu setzen. Ich exportiere also die beiden Ergebnisse category, damit das Spiel weiß, was die richtige Lösung ist, sowie itemName, damit der Spieler sieht, um welches Geschenk es sich handelt.

Erste Abbruchbedingung: Falsche Kategorie

Falls der Spieler den falschen Geschenksack erwischt, soll das Spiel beendet werden. Dazu bereite ich zwei Arbeitsabläufe vor: nextRound und gameOver. Diese beiden Arbeitsabläufe werden innerhalb der drei Arbeitsabläufe cat1, cat2 bzw. cat3 aufgerufen, diese wiederum durch Klicks auf die im game-Dokument dargestellten Säcke.
gameOver wird dabei ausgelöst, wenn der vorher gespeicherte Wert von category nicht mit der Kategorie übereinstimmt. (Beachte die Effektbedingung)

Zweite Abbruchbedingung: Zu langsam

Für diese ist ein kleiner Trick nötig. Zunächst starte ich nach dem Anzeigen des game-Dokuments einen Verzögerungs-Effekt. Nachdem die Verzögerung abgelaufen ist, ist das Spiel gelaufen, aber halt! Das soll natürlich nur dann passieren, wenn die Spieler zwischendurch nichts angeklickt hat.
Das realisiere ich mit einem Rundenzähler round. Diesen gibt es einmal als Objektvariable und einmal als Arbeitsablauf-Variable thisRound. Zu Beginn jeder Runde (d.h. nachdem der Spieler etwas angeklickt hat) erhöhe ich den Rundenzähler um eins und weise dann diesen Wert der Variable thisRound zu. Auf diese Weise kann ich erkennen, ob ein „Timeout“ noch gültig ist (round = thisRound), oder nicht (round > thisRound).
An dieser Stelle sei nochmal daran erinnert, dass Arbeitsablauf-Variablen eine kürzere Gültigkeit haben als Objekt-Variablen. Mit jedem Klick im Dokument erzeuge ich neue Arbeitsablauf-Variablen, deshalb kann es auch mehrere Versionen der Variable thisRound geben, die Objektvariable gibt es aber nur ein einziges Mal pro Item.

Ende des Spiels

Am Ende des Spiels zeige ich eine lapidare Meldung an, weshalb das Spiel beendet wurde (zu langsam oder falsch geklickt), dazu noch eine Punktzahl score, die ich vorher in jeder Runde um eins erhöht habe.

Genug Platz für Ideen

Das Item ist ausdrücklich nicht nur dazu da, benutzt zu werden, sondern auch verbessert.

Zum Beispiel kannst du dich an folgendem versuchen:

  • Verändere die Liste der Geschenke oder füge welche hinzu.
  • Gestalte das game- und intro-Dokument hübscher.
  • Verschönere die „Spiel zuende“-Meldung, und/oder baue einen „nochmal spielen“-Link ein.
  • Verringere oder erhöhe die Zeit, die der Spieler zum Reagieren hat.
  • Hübsch sortierte Säcke. Wäre doch schade drum, wenn jemand in jeder Runde die Reihenfolge vertauschen würde… Wer tut sowas nur?
  • Mach ein Endlosspiel draus. Bei Fehlern gibt es Punktabzug statt Spielende.
  • Speichere einen Highscore ab.
  • Es geht auch ohne Lua-Skript. Überführe das Skript in normale Arbeitsablauf-Elemente.
  • (für Fortgeschrittene) Ein Dokument reicht auch aus. Versuche, das ganze Spiel mit einem einzigen Dokument zu bauen.

Viel Spaß beim Experimentieren und
:wave: bis zum nächsten Sonntag…

3 Likes

Extended am Sonntag #6


Zwischensequenzen

Zwischensequenzen (engl. Cutscenes) oder Dialoge sind, ähnlich wie Dokumente, besondere Objekte, die eine bestimmte Situation auf dem Bildschirm anzeigen. In Zwischensequenzen geht es darum, eine Szene mit bis zu zwei Akteuren darzustellen. Sie sind maßgeschneidert für die Anzeige von Dialogen, insbesondere innerhalb von Quests, z.B.:

  • Erklärung einer Questaufgabe in Dialogform
  • ein NSC erzählt etwas
  • Darstellung von Interaktionen mit Objekten (Truhen, Geräte,…)

Wie Dokumente sind auch Zwischensequenzen keine eigenständigen Objekte, sondern müssen als innere Objekte eingebettet werden.

Sichtbare Struktur

Für den Spieler sichtbar ist ein Fenster mit zwei 3D-Modellen, die sich anschauen. Im unteren Bereich befindet sich ein Textfeld, welches den gesprochenen Text der Akteure darstellen kann.
Jede Zwischensequenz kann aus mehreren „Szenenbildern“ bestehen. Mit einem Klick auf das Textfeld gelangt man zum nächsten Schritt.
Außerdem ist es möglich, dem Spieler bis zu fünf Wahlmöglichkeiten anzubieten. In diesem Fall muss sich der Spieler für eine der angebotenen Optionen entscheiden, bevor es weitergeht.

Anzeige einer Zwischensequenz

Mit dem Effekt „Kampagne und Quests > Zwischensequenz starten“ wird eine bestimmte Zwischensequenz angezeigt. Diese beginnt jedes Mal von vorn. es ist also nicht möglich, eine Zwischensequenz ab einem bestimmten Schritt starten zu lassen.
Auch wenn der Effekt unter „Kampagnen“ gelistet ist, können Zwischensequenzen auch außerhalb einer Kampagne verwendet werden.

Verlauf einer Zwischensequenz

Der einfachste Dialog verläuft geradlinig. Jeder Dialogschritt wird der Reihe nach durchlaufen.

Aber es geht noch viel dynamischer.

Wahlmöglichkeiten

Mit der Schaltfläche „Wahlmöglichkeiten“ öffnet man das Menü zur Einstellung von Optionen. Jede Option ist mit einer Schrittnummer versehen. Eine Wahlmöglichkeit ist also eine Sprungmarke. Nachdem der Spieler auf eine Option klickt, springt der Dialog zum angegebenen Schritt.
Optionen können auch mit Bedingungen versehen werden. Man kann den Spieler also auch in seiner Auswahl einschränken. Bestimmte Optionen könnten nur Magiern zur Verfügung stehen, oder nur dann, wenn man vorher eine bestimmte Quest erledigt hat, oder oder oder…

Nächster Schritt

Im Feld „Nächster Schritt“ kann man eintragen, womit es im Dialog weitergehen soll. Das ist zusammen mit Wahlmöglichkeiten praktisch, denn auf diese Weise kann man Dialogteile überspringen, die zu einer anderen Auswahl gehören.
Wenn man das Feld leer lässt, geht es mit dem direkt folgenden Schritt weiter.
Es ist auch möglich, im Dialog rückwärts zu springen, bspw. wenn man möchte, dass der Spieler solange probiert, bis die „richtige“ Option gefunden wurde.

Endschritt

Setzt man die Markierung Endschritt, hört der Dialog nach Anzeige des betreffenden Schritts auf, auch wenn danach noch weitere Schritte folgen sollten. Auch das ist im Zusammenhang mit Wahlmöglichkeiten interessant, denn so lassen sich Dialogteile am Ende überspringen.

Ereignisse und Arbeitsabläufe

Vor, während, und nach einer Zwischensequenz treten Ereignisse ein, die man mit Arbeitsabläufen verknüpfen kann.

  • Bevor der Dialog startet, tritt das Ereignis „Dialog startet“ ein.
  • Nachdem der Dialog beendet wurde, tritt das Ereignis „Dialog beendet“ ein. Wichtig: Dieses Ereignis tritt nicht ein, wenn der Spieler das Dialogfenster zwischendurch schließt.
  • Jeder einzelne Dialogschritt kann mit einem Arbeitsabluf verknüpft werden. Dieser wird vor der Anzeige des Schritts ausgeführt. Hier kann man z.B. Sounds einbauen.

Akteure

Bei „Linkes Modell“ und „Rechtes Modell“ können wir einstellen, wer oder was angezeigt werden soll. Dazu stehen verschiedene Optionen zur Verfügung.

Spielfigur

Geben wir player ein, erscheint die Spielfigur des Spielers.
Bitte beachte, dass es nicht möglich ist, das Aussehen der eigenen Spielfigur in Extended abzuspeichern, bspw. kann ich nicht meinen Charakter als Akteur in einem Dialog anzeigen, den du auf deinem Account ansiehst.

Ziel

Mit target legen wir fest, dass das momentan anvisierte Ziel angezeigt werden soll.
In der einfachsten Version eines Questgeberdialogs steht demnach auf einer Seite player und auf der anderen target.

NSC-Id

Wenn man einen numerischen Wert eingibt, z.B. 10184, wird der NSC mit der angegebenen Id dargestellt, in meinem Beispiel Onyxia. Wer sich an den Beitrag zu Sounds erinnert, wir ahnen, woher ich diese Id kenne: https://www.wowhead.com/npc=10184/onyxia. Man suche nach dem Namen des gewünschten NSC, und der Wowhead-Link wird dessen Id enthalten.
Bei der Benutzung von NSC-Ids ist allerdings Vorsicht geboten:

NSC-Anzeige-Id

NSC-Ids haben zwei Einschränkungen:

  • Das NSC-Modell wird nur angezeigt, wenn es sich im Cache befindet. Das ist normalerweise der Fall, wenn man in letzter Zeit in der Nähe des NSCs war. Beim oberen Beispiel würde Onxyia wahrscheinlich nur dann zu sehen sein, wenn man in letzter Zeit die Raidinstanz besucht hat.
  • Manche NSCs haben mehrere Modelle. Die meisten Stadtwachen haben z.B. ein weibliches und ein männliches Modell. Wenn man die NSC-Id benutzt, wird ein zufälliges Modell ausgewählt.

Beide Einschränkungen kann man mit Anzeige-Ids (engl. display id) umgehen. Diese Ids sind auch auf Wowhead zu finden. Dazu klicke ich auf „Links“ und dann „Anzeige ID“. Wowhead sagt 8570. Damit Extendend normale NSC-Ids von Anzeige-Ids unterscheiden kann, muss ich DID voranstellen. Ich trage also DID8570 ein und Onyxia erscheint (mal wieder).

Wer ein Bisschen auf Wowhead stöbert, wird merken, dass dort immer nur eine einzige Anzeige-Id steht, selbst wenn es mehrere Modelle gibt.
Leider ist es nicht so leicht, alle Anzeige-Ids eines NSCs zu finden, meistens liegen die numerischen Werte aber nahe beieinander. Die gefundene Id plus/minus 1,2,3,… liefert oft die anderen Modelle.

Noch etwas Deko

Dialogtext

Neben Variablen-Tags (${variable}) kann man auch Sternchen oder Spitze Klammern verwenden, um Emotes zu kennzeichnen. Diese erscheinen dann in der gewohnten Emote-Farbe.
Beispiel: <Der Questgeber gähnt laut.> Was willst du?

Hintergrund

Standard-Hintergrund einer Zwischensequenz ist eine nachtelfisch angehauchte Szene. Dort kann man jeden Bildpfad aus dem Spiel eingeben, sofern man ihn kennt. Wie man diese findet, steht in einem anderen Tutorial. :wink:
Fürs erste kannst du versuchen, nightelf im Standardpfad durch den englischen Namen eines anderen Volks zu ersetzen, um thematisch an deren Hintergrundbilder zu kommen.

Bild

Zusätzlich zum Hintergrund ist es möglich, ein Bild in der Mitte des Dialogs anzuzeigen.


Viel Spaß beim Experimentieren und
:wave: bis zum nächsten Sonntag…

2 Likes

Extended am Sonntag #7


Heute mal etwas für Fortgeschrittene und/oder Unerschrockene:

Der Lua-Skripteffekt

WoW-Addons (und auch Weakauren) sind in der Programmiersprache Lua geschrieben. Auch Extended erlaubt es, Lua-Codeschnipsel in eine Kreation einzubauen, falls die vorgefertigten Effekte nicht ausreichen sollten.
Den Effekt findest du unter „Experte > Eingeschränktes Lua-Skript ausführen“.

Eingeschränkt?

Extended kennt verschiedene Sicherheitsstufen. Der Lua-Effekt ist als niedrig eingestuft, trotzdem bietet das Addon einen gewissen Schutz, denn man kann mit dem Effekt nicht beliebigen Code ausführen. Wir werden gleich sehen, dass der Funktionsumfang trotzdem recht groß ist.
Damit erfüllt der Lua-Effekt seinen Zweck als „Sammelstelle“ für vieles, was mit den anderen Effekten nicht geht.
Die Blizzard-API bleibt dem Effekt allerdings verwehrt.

Das Basispaket

Zunächst kann man neben den Strukturelementen if, for, function, … die globalen Elemente date, ipairs, math, next, pairs, select, string, table, tonumber, tostring, type und unpack benutzen.
string ist hier besonders hervorzuheben, denn darin stecken die üblichen Funktionen zur Manipulation von Zeichenketten.
Auch math kann interessant sein, wenn man bspw. eine Wurzel berechnen muss zur Entfernungsmessung.

Der Eingabeparameter args

Code, den man in das Eingabefeld eingibt, wird letztendlich als Funktion ausgeführt:

function(args)
-- dein Code wird hier eingefügt
end

args ist dabei ein Parameter, den man weiterreichen sollte, wenn man die folgenden Funktionen verwendet.

getVar und setVar

Mit getVar kann man Variablen aus Arbeitsablauf, Objekt oder Kampagne in das Skript laden:

local wfVar   = getVar(args, "w", "workflowVar")
local objVar  = getVar(args, "o", "objectVar")
local campVar = getVar(args, "c", "campaignVar")

Umgekehrt kann man mit setVar ein Ergebnis, das im Skript berechnet wird, in Arbeitsablauf, Objekt oder Kampagne speichern:

setVar(args, "w", "workflowVar", wfVar)
setVar(args, "o", "objectVar", objVar)
setVar(args, "c", "campaignVar", campVar)

Effekte auslösen mit effect

Aus einem Lua-Skript heraus kann man auch Effekte auslösen. Das ist praktisch, denn so kann man sich pro Arbeitsablauf auf ein Skript beschränken, sofern man überhaupt auf Skripte angewiesen ist.
Grundsätzlich löst man Effekte mit

effect("effect_id", args, ...)

aus. Man muss also die Ids der Effekte kennen. Bevor ich mit einer langweiligen Liste aufkreuze, lieber ein paar Beispiele.

effect("text", args, "Gruß aus Luanien", 1)
-- gibt einen Text im Chatfenster aus

effect("item_add", args, nil, "xyz123", "5", false)
-- legt 5 Mal das Item mit der Id xyz123 ins Inventar

effect("sound_id_self", args, "SFX", 1234, false)
-- spielt den Sound mit der Id 1234 im SFX-Kanal ab
Alle Effekt-Ids
cam_load
cam_save
cam_zoom_in
cam_zoom_out
companion_dismiss_critter
companion_dismiss_mount
companion_random_critter
companion_summon_mount
dialog_quick
dialog_start
do_emote
document_close
document_show
item_add
item_bag_durability
item_consume
item_cooldown
item_loot
item_remove
item_roll_dice
item_sheath
item_use
quest_goToStep
quest_markObjDone
quest_revealObjective
quest_start
run_item_workflow
run_workflow
script
secure_macro
signal_send
sound_id_local
sound_id_local_stop
sound_id_self
sound_id_stop
sound_music_local
sound_music_local_stop
sound_music_self
sound_music_stop
speech_env
speech_npc
speech_player
text
var_object
var_operand
var_prompt

Operanden auswerten mit op

result = op("operand_id", args, ...)

wertet den Operanden mit einer vorgegebenen Id aus und gibt das Ergebnis an die Variable result zurück. Auch hier muss man die Ids kennen.
Zum Beispiel:

local playerName = op("unit_name", args, "player")
-- gibt den Namen des Spielers

local playerName = op("time_hour", args)
-- gibt die momentane Stunde

local itemCount = op("inv_item_count", args, "xyz123", nil)
-- gibt an, wieviele Items mit der Id xyz123 im Inventar sind
Alle Operanden-Ids
char_achievement
char_cam_distance
char_facing
char_falling
char_flying
char_indoors
char_minimap
char_mounted
char_resting
char_stealth
char_subzone
char_swimming
char_zone
check_event_var
check_event_var_n
date_day
date_day_of_week
date_month
date_year
inv_container_slot_id
inv_item_count
inv_item_icon
inv_item_id_weight
inv_item_name
inv_item_quality
inv_item_value
inv_item_weight
quest_is_npc
quest_is_step
quest_obj
quest_obj_all
quest_obj_current
random
time_hour
time_minute
unit_class
unit_classification
unit_creature_family
unit_creature_type
unit_distance_inspect
unit_distance_me
unit_distance_point
unit_distance_trade
unit_exists
unit_faction
unit_guild
unit_guild_rank
unit_health
unit_id
unit_is_dead
unit_is_player
unit_level
unit_name
unit_npc_id
unit_position_x
unit_position_y
unit_race
unit_sex
unit_speed
var_check
var_check_n

Benutze den Skript-Effekt sparsam

Wenn der Lua-Effekt alles kann, was die anderen Effekte auch können, könnte man in Versuchung kommen, einfach alles mit einem Skript umzusetzen.
Davon sollte man aus mindestens zwei Gründen absehen:

  1. Der Effekt ist als letztes Mittel gedacht, falls es unmöglich sein sollte, die Kreation auf andere Weise zu erstellen.
  2. Der Effekt umgeht den normalen Schritt-für-Schritt-Ansatz des Addons und macht Arbeitsabläufe schwerer nachvollziehbar.

Überlege also, ob es wirklich ein Skript sein muss, oder ob es vielleicht auch einfacher geht.

Den Überblick behalten

In seiner Rolle als Auffanglösung hat der Skript-Effekt nur ein einfaches Eingabefenster bekommen, in das der Lua-Code hineingeschrieben werden muss.
Ich empfehle, den Code in einem „guten“ Editor, z.B. einem mit Syntaxhervorhebung, zu schreiben, und dann alles zu kopieren und in das Fenster einzufügen.
Verwende Kommentare ausgiebig, damit du auch noch nach Wochen weißt, was dein Code macht oder machen soll.


Viel Spaß beim Experimentieren und
:wave: bis zum nächsten Sonntag…

1 Like

Wunderschöne Guidesammlung!
Vielleicht baue ich damit auch mal weiter an eigenen Ideen.
Vielen lieben Dank dafür!

1 Like

Extended am Sonntag #8


Spielereignisse

Heute soll es um einen Mechanismus gehen, mit dem das Spiel dem Interface (also auch Addons wie Extended) mitteilt, was gerade auf dem Bildschirm passiert: Spielereignisse oder Events. Wer beim Wort „Event“ an ein Rockfestival denkt, den muss ich enttäuschen. Auch simple Dinge wie ein Mausklick sind Ereignisse, und das Spiel wird uns über jeden Mausklick informieren, wenn wir das wollen.

Ereignisse "abhören"

Technisch gesehen ist ein Ereignis einfach nur eine Nachricht, die jedem Addon übermittelt wird, das danach fragt. Wenn ich z.B. informiert werden möchte, sobald meine Spielfigur das Gebiet wechselt, muss sich ein Addon für das Ereignis ZONE_CHANGED registrieren. Extended übernimmt hierbei die Registrierungsarbeit für uns und wir müssen lediglich einen Arbeitsablauf festlegen, der bei einem bestimmten Ereignis starten soll.
Die Auswahl an Ereignissen ist reichlich. Probiere es aus:

/eventtrace

öffnet ein Fenster, das alle Ereignisse in Echtzeit auflistet. Selbst, wenn nichts besonderes auf dem Bildschirm passiert, können Ereignisse im Sekundentakt eintreten. Wenn du kämpfst oder in einer belebten Stadt bist, explodiert das Log förmlich.

Wo kann man Ereignisse einsetzen?

Grundsätzlich können nur Kampagnen auf Ereignisse „hören“, bei Items geht das nicht.
Innerhalb von Kampagnen kannst du Ereignisverknüpfungen auf Kampagnen-, Quest- sowie auf Questschrittebene einstellen.

  • Kampagnenereignisse bleiben solange aktiv, wie die Kampagne aktiv ist. Wird die Kampagne pausiert, wird kein Ereignis verarbeitet.
  • Questereignisse werden verarbeitet, solange die Quest sichtbar und nicht erfüllt ist.
  • Questschrittereignisse werden verarbeitet, solange die zugehörige Quest sich im betreffenden Schritt befindet und nicht erfüllt wurde. Es ist also nicht sinnvoll, einem Endschritt Ereignisse zuzuweisen.

Bedingte Ereignisse

Unter „Ereignisverknüpfungen“ kannst du jedem Ereignis mit STRG+Klick eine Bedingung zuweisen. Diese sorgt dafür, dass das Ereignis nur dann weiterverarbeitet wird, wenn die Bedingung erfüllt ist.
Das ist hilfreich, denn die meisten Ereignisse sind allgemein gehalten. Bspw. informiert das oben erwähnte Ereignis ZONE_CHANGED nur, dass man das Gebiet gewechselt hat, aber nicht, in welches. Die Quest „Reise nach Eisenschmiede“ könnte man also erfolgreich abschließen, wenn das Ereignis ZONE_CHANGED eintritt und der Gebietsname „Eisenschmiede“ lautet.

Ereignisparameter

Manche Ereignisse übermitteln zusätzliche Informationen. Z.B. liefert das Mausklickereignis GLOBAL_MOUSE_UP mit, ob die linke (leftButton) oder rechte (rightButton) Maustaste betätigt wurde.
Der Operand „Experte > Ereignisparameter (Text/Zahl)“ ist sowohl in der Ereignisbedingung als auch im aufgerufenen Arbeitsablauf abrufbar.
Alternativ kannst du das Variablen-Tag ${event.X} benutzen, wobei X für den Argument-Index steht.
Beachte, dass die Argumente nur in unmittelbar aufgerufenen Arbeitsabläufen verfügbar sind.

Spezielle Extended-Ereignisse

Fünf Ereignisse werden nicht vom Spiel generiert, sondern von Extended selbst. Um es ganz genau zu nehmen, reagiert Extended auf ein anderes Spielereignis und erzeugt daraus ein angepasstes Ereignis.
Sie werden genauso behandelt wie die anderen Ereignisse, tauchen aber nicht im /eventtrace-Log auf.

  • TRP3_EMOTE, wenn jemand ein vorgefertigtes Emote wie /hallo verwendet
  • TRP3_ITEM_USED, wenn der Spieler ein TRP-Item benutzt
  • TRP3_KILL, wenn der Spieler oder ein Gruppenmitglied eine Einheit tötet
  • TRP3_ROLL, wenn der „Würfeln“-Effekt verwendet wurde
  • TRP3_SIGNAL, wenn der „Signal senden“-Effekt verwendet wurde

Wie man Ereignisse findet

Wenn du ein neues Ereignis einstellst, hast du die Möglichkeit, den Ereigniskatalog zu durchsuchen. Dort sind viele (aber nicht alle) Ereignisse nach Kategorie aufgelistet, zusammen mit ihren Parametern, d.h. den Informationen, die mitgeliefert werden. Wenn du schon ungefähr weißt, in welche Kategorie dein Ereignis gehören könnte, kann dieser Katalog eine Hilfe sein.

Die „Probiermethode“ kann auch zum Ziel führen. Öffne dazu das /eventtrace-Tool. Dann tust du, was in deiner Quest bzw. Kampagne getan werden soll. Beobachte dabei, welche Ereignisse eintreten. Wenn ein Ereignis immer eintritt, wenn du die Questaufgabe erledigt, hast du einen guten Kandidaten gefunden.

Sei präzise

Bedenke, dass Ereignisse nicht nur für Extended entwickelt wurden. Meistens werden Ereignisse öfter ausgelöst als benötigt. Du kannst Bedingungen einsetzen, um das „richtige“ Ereignis herauszufischen.
Es kann auch vorkommen, dass mehrere Ereignisse bei einer bestimmten Aktion auslösen. Das Aufsteigen auf ein Reittier löst z.B. eine Reihe von Ereignissen aus, darunter UNIT_SPELLCAST_STOP (weil aufmountern als Zauber zählt) und COMPANION_UPDATE. Wenn die Questaufgabe darin besteht, auf ein Mount zu steigen, solltest du COMPANION_UPDATE verwenden, wenn es darum geht, einen Zauber zu wirken, kann UNIT_SPELLCAST_STOP helfen. Versuche also, ein möglichst passendes Ereignis zu wählen.


Viel Spaß beim Experimentieren und
:wave: bis zum nächsten Sonntag…

1 Like

Extended am Sonntag #9


Mehr Einsicht mit TRP3:Intended

Wenn die eigenen TRP3-Kreationen ambitionierter werden, wenn sich in deiner Kampagne eine stattliche Anzahl an Quests gesammelt hat oder wenn dein Item mit mehreren Variablen jongliert, kann es schonmal passieren, dass der Überblick verloren geht, insbesondere, wenn irgendetwas nicht so funktioniert, wie es soll.

Damit ich bei der Erstellung mehr Kontrolle über meine Kreation habe, habe ich mir ein Addon-Modul gebastelt, dass ihr euch bei CurseForge herunterladen könnt:

https://www.curseforge.com/wow/addons/total-rp-3-intended

Ein stiller Helfer

Zunächst wirst du nur eine neue :beetle:-Schaltfläche im TRP3-Menü sehen und so soll es auch sein: Das Modul wird nur aktiv, wenn man es explizit anweist, ein Item oder eine Kampagne zu beobachten, ansonsten bleibt es dezent im Hintergrund.
Kampagnen kannst du mit der Schaltfläche „Aktive Kampagne verfolgen“, Items mit STRG+Klick auf die Beobachtungsliste setzen. Bei einem Item wird nur das ausgewählte Exemplar beobachtet, denn jedes Exemplar kann einen anderen Status besitzen.

Objektdaten

Unter „Objektdaten“ findest du alle Objektvariablen mit ihren momentanen Werten. Außerdem gibt es eine Funktion, um den momentanen Zustand zu exportieren. So kann man bspw. andere Spieler auf den selben Stand in einer Kampagne bringen, um etwa einen Fehler zu untersuchen.

Questübersicht

Bei einer verfolgten Kampagne kannst du dir eine Übersicht mit allen enthaltenen Quests ansehen und diese nach Belieben starten oder zu beliebigen Schritten wechseln.
Das ist hilfreich, wenn du Quests testen möchtest, denn auf diese Weise musst du nicht jedes Mal die Kampagne neu starten.

Arbeitsabläufe

Zu jeder verfolgten Kreation notiert sich Intended alle Arbeitsabläufe, die ausgelöst wurden.
So kannst du nachvollziehen, ob und in welcher Reihenfolge deine Arbeitsabläufe ausgeführt wurden, oder ob sie z.B. öfter bzw. seltener als gedacht auslösen.

Kontrollpunkte

Innerhalb von Arbeitsabläufen ist es möglich, mit einem speziellen Effekt einen Kontrollpunkt anzulegen (Debug-Effekte > Kontrollpunkt). Damit hast du Einsicht in den Arbeitsablauf selbst.
Auch wenn dieser Effekt nur Intended-Benutzern zur Verfügung steht, funktionieren Kreationen weiter, wenn man das Modul nicht installiert hat. Trotzdem solltest du Kontrollpunkte löschen, sobald du sie nicht mehr benötigst, so wie ein Baugerüst abgebaut wird, wenn das Haus fertig ist.

Warnungen

Intended hat eine Bescheidene Form der sog. statischen Analyse, d.h. es kann bestimmte problemantische Konstrukte erkennen.
Wegen der Komplexität von TRP3 kann diese Liste nicht vollständig sein, und es kann mitunter falschen Alarm geben, aber es kann nicht schaden, mal einen Blick auf die Warnungen zu werfen, wenn etwas nicht richtig funktioniert.

Spoilerwarnung

Intended lässt zu, dass du mehr von einem Item oder einer Kampagne siehst, als das normalerweise der Fall wäre. Beim Erstellen, Testen und der Fehlersuche ist das praktisch, für alles andere ist das Modul nicht gedacht.

  • Benutze das Modul nicht, während du eine Kampagne durchspielst!
  • Fordere andere Spieler nicht auf, eine Variable manuell einzustellen, bevor sie ein von dir erstelltes Item benutzen können!
  • Gehe immer davon aus, dass deine Mitspieler Intended nicht installiert haben!

Viel Spaß beim Experimentieren und
:wave: bis zum nächsten Sonntag…

1 Like

Extended am Sonntag #10


Der dynamische Notizblock

Ein Notizblock? Könnte man da nicht einfach ein Dokument-Item erstellen und fertig?

Könnte man.

Aber dann lernen wir ja gar nichts über dynamische Dokumente. Und Variablen. Und man braucht jedes Mal ein neues Item für eine simple Notiz. Und außerdem. Und überhaupt.

Import-Code

Bevor es losgeht findet ihr hier das fertige Item zum Schnell-Importieren:

Notizblock

!1Ev3YPTru4xgFvMMyjHTtqtCNbd4c1oIeV4F60PRqiDSzRxKi6hNyiwpl9POx1RAEX65SlcqGi21tYypIDxT7589D(5BbUjVp3Xe)3OMb3XIZmmTQBw30W61hCYh)yc3PgUdwxh6zyukSCwqKp9r)FJZA1JZoTlolLZoQhzqwNg6PDAZDoWWaxVp)ioJ1KotuyJGG(WNtBkf(3sRW6tpj0WanKWrIao7oVy3jXrJNG2Yl(Me9lzhjstH8bKnYhaIWBGHqOIaEbbGY2e0zrCN9wXFDdNKHVyF6fPQ)y4)srsAX0126JbTOH)j4xgArkyCOY9(rHPqyQce7mB(ShMn5H)9VMT7eAWoZwa4hOLwhwSqoZIwWAtaGzGSXObDtgf9PsyyTSy(ak1LpGszBJ2mXnHpT0XtGZXrYefPNnQMT)dziVJNcc)rHaMVUlkmFWoZsJNypr6DpeBFDMuI0FuTTZ)A)pbZVF4FOGtcYlV0SyqHN2Iqmo4eLkMUvCSzi6hvWNixn(IKW7BSWd9VIIDMySdXNivcu0X8HL1q5)QEmfP1iMDuZt4oVHZExlYcVd7jD6PmR7XC2hYGK0JXd42j7gGZo(mQD8YUyuzFS7SJjTPw4EeH3tBtVRowvD2o1Ov)fVXq)OizQyshWlaIreqeG50aTu0TQOtb1ivIU9x2)FEc8nRZwl6ImnO49Z3Ko97pcWkwMxPuViuKk8KIPqGY7QAZdNlLDhg(JZGcG9SZBBRPmol09trX3ET87dWZ)YxECOV(X3SewnDLn8SBYl6RwfRuN1QiBJ40Ev7KVHWUifKRPSR6dkPQtvrBrm)zRxuH81mPi82xu(sRxOV6zKiCA21F9FUbcjn95BCHw6lOrcigF7wv32Blfspz0wCbtvgFf1f1f0SENxe4WLoNX19KZxI1ahonBC(GtHeafhJb)rPj3subtc4jA2tzKU8HOcZLChu6O15QpiRGGG1LZ2)Z0GZWb0rk(MaAXHwTPBcxikBBJkYQ881Eylr8CT5PawfGkXS3ZqsBw3sHvuW6u84QAdfugQfBw5iQQAC5p0qfSqfvCY5o0ZlAOWzZZOjN1LGHQIY2(TNaeiu29NrN2ICQLrD0mTPn3TjvUFN7yrIVljk4AGH(lv2MDe9SPYPx2M8q6QkWTVQi8RP)s(uYOt8MaXdZcdKGHLNMMxGRibbw9haLclBq9HYislzjZTkyUgJvWC)ryjfKyBBAyuIX6WSM3AUPJERXWNQo(tRiwdgvrmINTQIurlDseg0CfbUjG86sUGD8vKt0rB0ld)U179Ynb92A9Woa0IdxyBC5dESlfCdx)AHcxvCLWBxEHGJXIgCT7hg7f6pIMuHMlwGp2f)(Mp(1Ek)yQJBedXkvuMjk((QyQQn)GT4oKSj4v58kUpcNfaPEcjbLQvO0DsN2J2PQGKXajChK8Y(JI9KyVWf4VVathSwyIS(UgM7AzLpWYWU2BSTOI(sRBwhl4TTEnIe8CQF0trBkRzfgp4cmk8Q9ELQo5zO9v81EQuOTK46pLpG0DrHis3DLU98bEdNMj)6FNOvGta)Syr69NIavsjiT4Fbk5)h

Was das Item können soll

Ich möchte einen handelsüblichen Notizblock modellieren, von dem man Zettel abreißen und einzeln beschreiben kann.

  • Jeder Zettel soll zunächst eine Überschrift bekommen.
  • Man kann danach beliebig viel Text hinzufügen, das muss nicht sofort passieren, d.h. man soll alte Notizen später ergänzen können.
  • Man kann eine Notiz unterschreiben. Wenn man eine Notiz unterschrieben hat, soll es nicht mehr möglich sein, Text anzufügen.
    Bei einem echten Notizzettel würde das natürlich trotzdem gehen, aber… ich will das so :yum:

Objektstruktur

Der Notizblock ist ein Item (wow, Sherlock…), der ein inneres Item enthält, das einen einzelnen Notizzettel modelliert. In diesem befindet sich ein Dokument, dass die eigentliche Notiz anzeigt. Wir haben es also mit einem Dokument in einem Item in einem Item zu tun.
Da ich mehrere Arbeitsabläufe pro Item und Dokument benötigen werde, überführe ich als erste Amtshandlung meine Objekte in den Expertenmodus.

Variablen

Der Notizblock an sich benötigt nur eine Objektvariable: Mit charges speichere ich, wieviele (leere) Zettel der Block noch enthält.

Die einzelnen Zettel brauchen da etwas mehr Information. Beachte, dass die Objektvariablen der Notizzettel nichts mit der des Blocks zu tun haben. Auch wenn der Block zerstört wird, bleiben die abgelösten Zettel erhalten.

  • initialized erhält den Wert true, sobald der Zettel zum ersten Mal benutzt wird.
  • title speichert den Titel bzw. das Thema der Notiz.
  • content enthält den eigentlichen Inhalt, der nach und nach eingegeben wird.
  • controls beinhaltet die Schaltflächen „Text hinzufügen“ und „Signieren“. Nachdem signiert wurde, wird diese Variable mit einem Text „unterschrieben von…“ überschrieben.
  • signature enthält die „Unterschrift“, sobald unterschrieben wurde.
  • addedText ist eine temporäre Variable, um Text zwischenzuspeichern, der hinzugefügt werden soll.

Das äußere Item: Notizblock

Der Notizblock ist ein benutzbares Item. Im Tooltip informiere ich den Spieler mit ${charges::100} darüber, wieviele leere Zettel noch am Block heften. Die ::100 stellt dabei sicher, dass auch dann etwas angezeigt wird, wenn der Block noch nie benutzt wurde und somit die Variable charges noch nicht existiert.
Benutzt man den Notizblock, wird onUse ausgeführt. Achtung: Es gibt einen weiteren Arbeitsablauf mit selbem Namen im Notizzettel-Item.

  1. Initialisiere die Variable charges mit 100. Indem ich „Initialisieren“ statt „Wertzuweisung“ verwende, wird der Effekt nur bei der ersten Benutzung aktiv. Danach wird er ignoriert, da es die Variable charges schon gibt.
  2. Verringere charges um 1, denn wir reißen gleich ein Blatt ab.
  3. Spiele einen passenden Sound ab. Geschenkt.
  4. Füge das innere Item (Notizzettel) dem Spielerinventar hinzu.
  5. Bedingung: wenn charges Null erreicht:
  6. Verbrauche (d.h. Zerstöre) den Notizblock.

Das Dokument

Der Inhalt des Dokuments, also des Objekts, das später meine Notiz auf den Bildschirm bringt, sieht… unspektakulär aus:

{h1:c}${title}{/h1}${content}
${controls}

In diesem Fall liegt die Würze in der Kürze.
${title} wird durch den vom Spieler vergebenen Titel ersetzt, ${content} entsprechend durch den Inhalt.
${controls} beinhaltet die beiden Schaltflächen/Links, mit denen ich Text hinzufügen kann oder signieren.

Die drei Dokument-Arbeitsabläufe onAddTextClick, onAddTextInput und onSignClick heben wir uns für später auf, denn zuerst kümmern wir uns um…

Das innere Item: Notizzettel

Wie der Notizblock ist dieses Item als benutzbar angelegt. Im Tooltip zeige ich mit ${title::<Kein Titel>} den Titel an. Man muss also nicht jede Notiz „durchklicken“, um den Titel zu erfahren.
Außerdem fülle ich das Feld „Beschreibungstext“ mit ${signature::Ein einfacher Notizzettel} aus. Das sorgt dafür, dass eine nicht unterzeichnete Notiz mit der Bemerkung „Ein einfacher Notizzettel“ versehen wird, ein unterschriebener hingegen mit der entsprechenden „Unterschrift“.

Der Notizzettel hat zwei Arbeitsabläufe: onUse und initialize. Wenn man einen Notizzettel benutzt (also rechtsklickt), …

  1. … wird das innere Dokument angezeigt, aber nur, wenn die Variable initialized auf true gesetzt ist.
  2. … wird initialize aufgerufen, aber nur, wenn die Variable initialized nicht auf true gesetzt ist.

Anders ausgedrückt: onUse bereitet den Notizzettel vor, falls das noch nicht geschehen ist, ansonsten zeigt es seinen Inhalt an.

initialize kümmert sich darum, dass beim ersten Benutzen alle Variablen korrekt eingerichtet werden:

  1. Setze initialized auf true.
  2. Lege die Variable content an. In der Datenbank sieht das Konstrukt etwas merkwürdig aus. Dort steht content [=], aber es hat seine Richtigkeit. Der Inhalt soll anfangs leer sein.
  3. Weise der Variable controls den Wert {h3:c}{link*onAddTextClick*Text hinzufügen} {link*onSignClick*Signieren}{/h3} zu. Hier sind also die beiden Schaltflächen, die später im Dokument zu sehen sein werden. Sie stehen deshalb nicht direkt im Dokument, damit ich sie nach dem Signieren entfernen kann.
  4. Eingabeaufforderung für die Variable title. Der Spieler soll hier einen Titel wählen. Sobald das geschehen ist, wird onUse aufgerufen.

Wer aufmerksam gelesen hat, wird feststellen, dass die beiden Arbeitsabläufe sich gegenseitig aufrufen. Das könnte sich zu einer gefährlichen Endlosschleife entwickeln. In diesem Fall ist das kein Problem, denn wir steuern die Aufrufe über die Variable initialized. Indem wir sie im ersten Schritt auf true setzen, stellen wir sicher, dass es kein ewiges hin und her geben kann.

Interaktionen im Dokument

Wie oben erwähnt, bleiben noch die drei Dokument-Arbeitsabläufe zu klären.

onAddTextClick wird ausgelöst, sobald der Spieler auf die entsprechende Schaltfläche unten im Dokument klickt. Als einzigen Effekt enthält der Arbeitsablauf eine Eingabeaufforderung für die Variable addedText.

Ist der Spieler fertig mit Schreiben, wird onAddTextInput aufgerufen.

Hier wird im ersten Schritt die Variable content modifiziert: ${content}{p} {/p}{p}${addedText}{/p}. Der neue Wert besteht aus dem alten Wert (dafür sorgt der erste Teil ${content}), sowie dem neuen Text ${addedText}, der in einen Absatz eingebettet wird (dafür sorgen {p} und {/p}).
Dazwischen habe ich ein komisches Konstrukt {p} {/p} reingemogelt. Dieses erzeugt eine Leerzeile. Das Leerzeichen in der Mitte ist ein geschütztes Leerzeichen, sonst funktioniert der Trick nicht.
Das geschützte Leerzeichen ist über die Tastenkombination ALT+255 erreichbar. Im Gegensatz zum normalen Leerzeichen wird es wie Text behandelt. Ohne dieses spezielle Zeichen würde Extended „denken“, dass mein Absatz leer ist, und ihn nicht anzeigen. Ich habe also einen nicht leeren Absatz und Extended spendiert mir den Zeilenumbruch, den ich haben möchte. Der Absatz an sich ist nicht zu sehen, weil… naja, weil er nur aus Leerzeichen besteht.

Im zweiten Schritt wird das Dokument erneut angezeigt. Bedenke, dass an dieser Stelle das Dokument bereits offen ist, aber indem ich es erneut öffne, wird auch der Inhalt mit dem neuen Wert von content aktualisiert.

Der letzte Arbeitsablauf ist onSignClick, der ausgelöst wird, wenn der Spieler seine Notiz unterzeichnen möchte.
Ähnlich wie bei onAddTextInput werden hier Variablen neu gesetzt.
Zunächst bekommt controls den neuen Wert {h3:c}unterzeichnet von ${trp:player:full}{/h3}. Damit werden die beiden Schaltflächen durch einen Text ersetzt und sind nicht mehr anklickbar. ${trp:player:full} ist ein Variablen-Tag, das den Spielernamen beinhaltet.
Danach wird das Dokument erneut angezeigt, damit die Änderungen sichtbar werden.
Im letzten Schritt wird die Variable signature eingestellt. Dadurch ist dann bereits im Item-Tooltip ersichtlich, dass die Notiz fertiggestellt wurde, und nicht mehr veränderbar ist.


Viel Spaß beim Experimentieren und
:wave: bis zum nächsten Sonntag…

2 Likes

Diese Richtlinie mit nur 3 Posts ist seltsame. Die Guides sind aber gut.

1 Like

Extended am Sonntag #11


Karten und Würfel

Heute geht es um eine häufig vorkommende Frage: Wie kann man Würfel oder das Ziehen von Karten aus einem Kartenstapel modellieren?
Man ahnt es vielleicht schon, es wird um Zufallswerte gehen.

Würfel erzeugen unabhängige Zufallsereignisse. Wenn ich mehrmals würfle, hat das Ergebnis nichts mit den vorherigen Würfen zu tun. Selbst bei einem gezinkten Würfel ist das so, auch wenn dort nicht alle Ergebnisse gleich wahrscheinlich sind. Münzwürfe fallen auch in diese Kategorie.

Im Gegensatz dazu entstehen beim Kartenziehen abhängige Ergebnisse. Wenn ich in einem normalen 32-Karten-Blatt einmal das Pik As ziehe, kann die nächste Karte sicher kein Pik As mehr sein. Beim Lotto ist es ähnlich.

Überlege also zuerst, in welche Kategorie deine zufälligen Ereignisse passen könnten.

Einmal Würfeln, gleiche Chancen

Wenn man „nur“ würfeln möchte, hat Extended das passende Werkzeug: Inventar > Würfeln.
Hier kannst du einstellen, wie gewürfelt werden soll. 1d6 steht z.B. für den klassischen, sechsseitigen Würfel, 1d100 entspricht dem /würfeln-Makro. Das Würfelergebnis wird auf dem Bildschirm ausgegeben. Optional kannst du das Ergebnis in eine Variable speichern.

Wenn das Ergebnis keine Zahl, sondern eine zufällige Begrüßung, ein zufälliger Soundeffekt, o.ä. sein soll, benutzt man einen Trick: Jedes mögliche Ergebnis bekommt eine Nummer. Dann würfelt man die Nummer aus und voilà.
Hierzu sollte man Experte > Dynamischer Wert > Zufallswert einsetzen, denn wir sind nicht am Ergebnis selbst interessiert (der Zahl), sondern dem zugewiesenen Ereignis.

Eine ausführliche Beschreibung zum Erstellen einer Wurfmünze findet ihr hier: [Guide][Wiki-Beitrag] How-To Total RP 3 Extended ❔ - #4 von Enestress-die-aldor .

Das folgende Beispielitem gibt die Worte „EINSicht“, „AbZWEIgung“ oder „RunDREIse“ aus, jenachdem wie man gewürfelt hat. Das Grundprinzip ist immer das selbe: Erzeuge im ersten Effekt einen zufälligen Wert und frage ihn danach in den Effektbedingungen der Reihe nach ab.

Wörterwürfel !9ozuVTjmqC8prRfCGULi1hiatcPoNUCjG2EWjuIxckeycijD7H8XApT36xS()m0TQLSxRWY(8DNV7hN9PSvZusBmSgyPKcfzjSCX4g3HzwXwFujhapOijMBv0SVazSN8zTvLZB0SanJN5yr6UacP8vk6qA9IQVRRtlXM061nDwPv5z6PvffMuEKtcX(uTtjDEHi2gm02)ryuK3G5sfjyfoNNVw9JWqwfsxV6EBDOKTrNTDboFAphhna8hA48WkU92()7d)LGxJ)09LbtdJWppZO9)siwh8MWM4cS59WxtcJwVVC9LHJlFoScXBcI2xaXWijLNTP9)d4RU2xPBtZlA6E)9PaoS(b4DQ71wIRfItlfwJCVzK7qOFmEkQl0h0nVB2M6uGefBECrxWYDt4GJyIvjlhJNWx5CLdqjUVJGOZs1WrqpqXFcJYKi1diejkjCoyUzbnhOctuKICFKfMcb(in6S915T)4oWrHHRXECqUNq6Sh(b0BHJMxEyXU8MSfCDDHLTjvijspfL80VQB11hF631FdHGB8GLp7zk737XBMl55ypdk(t5nbC8f2VhEgACHuJn1eiNyoKVjojH8HAno01K33ItEq8N73DAzsxMlpTSwJBWMTf5zB1LDx9oVuaBvQN)d

Würfeln mit ungleichen Chancen

Wenn ein gezinkter Würfel oder allgemein unterschiedlich wahrscheinliche Ereignisse benötigt werden, kann man sehr ähnlich wie im ersten Teil vorgehen, nur, dass man diesmal den Ergebnisbereich abfragt.

Als Beispiel habe ich eine Schatulle gebaut, die mit 15%-iger Wahrscheinlichkeit ein seltenes Item enthält. Ich habe das Item so konstruiert, dass es nach der Benutzung nicht verschwindet oder „leer“ ist. So könnt ihr den Effekt leichter ausprobieren.

Schatulle !nx12UTnpm4NO1AlNGGvSnG0KITa060f5KIDJSvSzs0IpuiRCO7c)ySNMDxFXgPSttNtXF)3agWsmKLejf)iP(OfUIaHVl(445i8zcUdZPlZ1L50zAqxZEHVhQbFKpnA0YYv0KPCAKpqWlYNwccJGFzFARB54r5(wxRkZf8bJPr)(c(h1p(J8Y7L5ODKlDWFc(N7BDk)ssT76tJZWTqjdMqlgsNhZ1d18kA9i0LQ8THFf2bPXA5cJkFzypNWLqMdlCPga0b3ApOP(weeyp6ROd1yXCWbuhyHsaUn9NWkUZ4rK(3CNfedNAFrbAh81ibV7EAYeCczInTGVVziz6nJXqDmTo4lOmReTudVEgJXEHmwaOsRI2wKxfnotwf9jvAcuwfnujtGStsJEVAA0Pt70ySUyxEOJ7)sPSJZFrpZPBSCO(AlotLi4BL6WI7bTmhxi1llRLYtuXWKI0u7DSD2uePtrMWVZH79Kmkn2esO3XNuvjoI3Ky0gEN6rLbYcLj4S4c0PnIAKxdO4vq86q8mKnOzNfgpHjYx0gFOHITfvQ7bm8SGOfHSkQMfsM6sMoNcgQAc5Mc9dTJcdfe)nX)7E)VBay5e)FXpvf8owCkH4nAL5HRHTqQTI2MzX7Jt)2MSQOh)(If5asF0q8kt56uv8AS9WF292293oqHMxSpKiwh5T84vsZM0uWEJD(tn5Eof7)Sjhgrx(RK5wmYAUZ1i3H62nGugsXes5BcwPLyTHpt43ZEeNiHpeRiDp3HDoJvfXCVWT3fyR)dmrEYmSUCwNZWqYmR57c8bNye7cmOrOKagPkTSPLavjRn2ie)m

Obwohl es in diesem Beispiel nur zwei mögliche Items gibt, würfle ich von 1 bis 100. Wenn ich eine Zahl zwischen 1 und 15 erwürfelt habe (beachte die Effektbedingung), bekommt der Spieler das besondere Item, ansonsten Schrott. 15 von 100 Würfelergebnissen sind also „gut“, das entspricht den 15%, die ich vorher festgelegt habe. Ich hätte auch 86 bis 100 als „gut“ definieren können, nur die Größe des Bereichs ist hier wichtig.

Karten ziehen

Sobald wir mehr als eine Karte aus einem Deck ziehen, müssen wir etwas tiefer in die Trickkiste greifen. Extended muss sich nämlich irgendwie merken, welche Karten bereits gezogen wurden, oder alternativ, welche noch gezogen werden können.

Bevor ich mich darum kümmere, erstelle ich ein Kartendeck-Item für ein Skatdeck, d.h. ich werde 32 innere Items benötigen. Jetzt könnte ich die 32 Items von Hand erstellen… oder ich baue mir fix ein paar Makros.

Kleiner Exkurs in die TRP3-API

Der folgende Teil ist optional. Ihr könnt die inneren Items auch wie gewohnt erstellen.

/run _A = function(id, name) TRP3_ToolFrame.specificDraft.IN[id] = {TY = TRP3_DB.types.ITEM, MD = {MO = TRP3_DB.modes.NORMAL}, BA = {NA = name}} end

Makro Nummer 1 erzeugt eine Funktion, die ein inneres Item mit vorgegebener Id und vorgegebenem Namen erstellt. Das Item muss dabei in der Datenbank geöffnet sein.

/run _V = {"Sieben", "Acht", "Neun", "Zehn", "Bube", "Dame", "König", "As"} _C = {"Herz", "Pik", "Kreuz", "Karo"}

Das zweite Makro enthält die zukünftigen Namen der Karten.

/run local i = 1 for _, v in pairs(_V) do for _, c in pairs(_C) do _A(("card%02d"):format(i), c .. " " .. v) i = i + 1 end end

Das dritte Makro führt letztendlich meine Einfügefunktion 32 Mal aus. Damit man die Items auch sieht, muss man gegebenenfalls einmal ins Übersichtstab und zurück wechseln.

Zurück zum Deck

Wir haben es also irgendwie geschafft, die inneren Items card01 bis card32 zu erstellen.
Bei einem echten Kartenspiel würde man das Deck zuerst mischen, und dann so viele Karten von oben abnehmen, wie benötigt.
Es gibt aber noch eine andere Methode, die zumindest mathematisch gleichwertig ist: Man beginnt mit einem sortierten Deck. Dann würfelt man von 1 bis 32 und entnimmt die Karte an der entsprechenden Position. Für die zweite Karte würfelt man von 1 bis 31 usw.
Diese Methode werde ich vorstellen. In meinem Beispiel soll folgendes passieren:

  • „mische“ den Stapel, d.h. sortiere alle Karten
  • entnehme bis zu 5 Karten
  • nachdem 5 Karten entnommen wurden, entferne alle gezogenen Karten aus dem Spielerinventar und mische neu
Kartendeck !DEv4YnQnq43f3PZKmtQpHSVCjE69dsSN5CsoSRfoPT)qgmOeRAmCJqKEx6uES6lqFX6kjigi1tL7yhzqR(0(PD3Vfc1H6t9CGVObiQhMsqy05ieC7qIJxro1BaScYup1yuOigRqq(8y94mkXBgvsj()cSgyMRCvZ75sjFIjEPmyC4ogyxwHfBh258TDHcSZEOU57b6yjFVvWkac7XksB41JdCt)IFVDqnXPB)7)kL)udwBj6kh)RSnnyn(C7aRJvVXZwMJUnuK1nCHV0oSMZCRS0XKEB7uNHhb02bQbh1zTfF)GDinN0Rkw3OugDHDyR8A0gzdSw636cYwGDSm9ubUnRDSSOYW6ofKdSeRXXTv(iTgCjrnsUMsYsxMRmxH7ExQhcS4txtj)KRQzgzUR6MLEQX5eykNloNsEqp71l02iQXXkBy0aa4eTTzQrYvQX9zpcNTMLcw1U4Hjk)j1CXVMn(Ac4tRc2W(aZmBQA9F(bn)gV0qt4ame(zkL8(VQUybCHcIUbR8GbP6yHLjbtxWwjF8Xv50TTa64sHvXS9vpwwZRjE7cpSLTgmfEDKAw2gTQHuB1ILNyd22f8il7jz4C3GfYY2s6GvxWylJ0gx3nnJpkI3rOAz7fta71M4VQKnk1lXA15v1QXkVjzPXSOTnf64APQryx1iWOVRu2xwRSNc6UWOnC2ZSDSu5QNk4jXFHj2Ukjm(BjfQDUzxdl06eDFj19E6R4XusEKG)fy9HINYngijzrHjLbx7Uy8Q5U((tw4vg8XYGEDErRYavm87r44EL3OW3pB9VXIK9FouKRr82jZeLb)XFwEd)XYG0m5BxsFvmZSUV7a2(ryNXFOmqUHLwEtzWb3KpA8LAfpQ2qUEkNZgGldIZmguFyp(iG8KECjB3kbBx2ZSENz21ZAhhgb7ZUq5j8tbdoie6097ImCDcRppnNjKN8VYiadVcauBuDrLVLSVkB40EJ5mOwxxfvg87fIy1VPSIYGNy745GUVVA5oW(XsYzMnRkZj0NtGNB6lctJZ2DIZzhkCEAlKQeQgS5WyIfh8WioT9zqh)cJJ)pcEkNOJFWFyf)tJRLvW3eEUKw)HeZKH8KCDj8KRxTyIlzM3kqYmDUFv5A3x)xJ7UPkiZw24HVgzozmG483HWVddvbooJqdhHvIqq(syjGAl)h83ictsa9jOyVam1cccnYbnAa8KW7GogQNYkVV6Fgr3dzYpRf5VzZIVh0F9h2FOIl)pEC7NuDCA0DQ7RxqCHlfmOWiFBcpAllfcVf7GSdpTUuQm4fOa6foBJU)ljNfvi4YVDhW0evWus9gUNM0)5

Das ganze funktioniert mit einem Lua-Skripteffekt. Ich habe das Skript kopiert und Zeilennummern hinzugefügt, damit ich jede Zeile einzeln erklären kann. Wenn ihr den Code weiterverwenden wollt, müsst ihr die Zeilennummern löschen.

01 local CARD_PATTERN = "0206001034S1Nus card%02d"
02 args.object.vars = args.object.vars or {}
03 if not args.object.vars.deck or #args.object.vars.deck <= 27 then
04   args.object.vars.deck = {}
05   for i = 1,32 do
06     effect("item_remove", args, CARD_PATTERN:format(i), 1000)
07     table.insert(args.object.vars.deck, i)
08   end
09   effect("text", args, "Die Karten wurden neu gemischt.", 1)
10 else
11   local r = math.random(1, #args.object.vars.deck)
12   local card = table.remove(args.object.vars.deck, r)
13   effect("item_add", args, CARD_PATTERN:format(card), 1, 2)
14 end

Zeile 1
Hier speichere ich die Id einer Spielkarte ab %02d steht als Platzhalter für die Kartennummer. Der erste Teil ist die Id des Kartendecks. Wenn ihr ein eigenes Item baut, müsst ihr diese entsprechend ändern.

Zeile 2
Mit args.object.vars habe ich direkten Zugriff auf die Objektvariablen. Ich muss getVar nicht verwenden und in diesem Fall könnte ich es auch gar nicht, denn meine Variable deck wird eine Tabelle enthalten. Dieser Fall wird von getVar nicht richtig behandelt.
Diese Zeile übernimmt den Fall, dass es noch keine Variablen im Objekt gibt (also Initialisierung).

Zeile 3
Hier prüfe ich, ob mein Deck gespeichert wurde, und wenn ja, wieviele Karten noch darin sind. Es muss gemischt werden, wenn die Variable deck nicht existiert oder 27 oder weniger Karten im Deck sind.

Zeile 4
Bevor ich mische, lege ich einen leeren Kartenstapel an.

Zeile 5
Ich betrete eine Schleife über alle meine 32 möglichen Karten.

Zeile 6
Innerhalb der Schleife entferne ich jede Karte aus dem Inventar. Sollte die Karte gar nicht im Inventar liegen, passiert nichts. Als Vorsichtsmaßnahme werden bis zu 1000 Exemplare einer Karte entfernt. Es könnte nämlich sein, dass der Spieler mehrere Decks im Inventar hat und simultan zieht.

Zeile 7
Hier wird die Tabelle mit verfügbaren Karten gefüllt. nachdem das passiert ist, stehen dort einfach nur die Zahlen 1 bis 32 der Reihe nach.

Zeile 9
Ich gebe dem Spieler den Hinweis, wenn gemischt wird, damit sich niemand wundert, warum die ausgegebenen Karten verschwinden.

Zeile 10
Ab hier wird der Fall behandelt, dass eine Karte gezogen werden soll anstatt gemischt.

Zeile 11
Zuerst würfle ich aus (math.random), welche Karte vom Stapel genommen werden soll. Diese Zahl ist die Kartenposition, nicht die Kartennummer.

Zeile 12
Mit table.remove entnehme ich die Karte an der zuvor ausgewürfelten Position. In der Variable card steht jetzt eine Kartennummer.

Zeile 13
Schließlich muss ich noch die Karte ins Spielerinventar legen. Mit CARD_PATTERN:format(card) erzeuge ich aus der Kartennummer eine Karten-Id.

Uff, so ein Kartendeck zu bauen war dann doch ein ganzes Stück schwieriger als ein paar Würfel. Das liegt daran, dass sich Extended die verfügbaren Karten merken muss. In diesem Fall ist der Lua-Effekt kaum zu vermeiden, denn das ist momentan die einzige Möglichkeit, in Extended Tabellen bzw. Listen zu verarbeiten.


Viel Spaß beim Experimentieren und
:wave: bis zum nächsten Sonntag…

1 Like

Extended am Sonntag #12


Kampagnen in Aktion - Echte Beispiele

Dieser Beitrag wird weniger ein Tutorial und mehr eine Vorstellung meiner eigenen veröffentlichten Extended-Kampagnen.
Vielleicht dienen sie dem einen oder anderen als Inspiration für eigene Projekte oder als Musterlösung für eigene Quests.
Wer wissen möchte, wie die Quests umgesetzt wurden, darf selbstverständlich gern einen Blick in die Datenbank riskieren. (Spoilerwarnung und so)

Was man benötigt

Für jede der vier Kampagnen ist ein Hordecharakter erforderlich, dieser muss aber nicht die Maximalstufe erreicht haben.
Wegen der Größe der Kampagnen kann der Import-Code nicht direkt ins Forum eingebettet werden, stattdessen gebe ich einen Wago.io-Link an. Auf Wago könnt ihr den Import-Code mit Hilfe der Schaltfläche „Import-String kopieren“ rechts oben abrufen.
Jenachdem, mit welcher Hardware ihr ausgestattet seid, kann das Spiel beim Importieren für einige Sekunden einfrieren. Wenn ihr bereits sehr viele Extended-Kreationen gesammelt habt, ist es ratsam, vorher eine Sicherheitskopie eurer Extended-Datenbank zu machen. (Okay, das ist eigentlich immer ratsam.)

"Die Waldläuferin Seleves"

https://wago.io/ZJwzNecYd

Mit dieser Kampagne habe ich mir selbst Extended beigebracht. Sie ist gespickt mit Rätseln und vom Schwierigkeitsgrad höher angesiedelt als die anderen Kampagnen.
Als Mischung aus Prototyp und Probieren-was-geht werden beim Durchspielen sicherlich einige Ecken und Kanten auffallen.

"Jagd auf Velaves"

https://wago.io/EmDGBbUUV

Wenn der Main eine Kampagne bekommt, warum nicht auch die Twinks? Wie in allen vier Kampagnen geht es thematisch um einen Charakterkonzept und dessen Umgebung.

"Azeroth ist nicht genug"

https://wago.io/HzQHtU3Vu

Die Antwort auf die Frage, ob man mit Extended auch Parodien machen kann. Sie lautet: Ja, es geht. Ob man es auch machen sollte, bleibt offen :wink:

"Söhne der Steppe"

https://wago.io/NLBslCmbY

Wer nicht genug vom Brachland bekommt, ist hier genau richtig. Wer Quests mit inhaltlichen Entscheidungen mag, auch.


Ich hoffe, diese kleine Sammlung dient als Inspiration für ein ähnliches Projekt. Vielleicht eine Charakterkampagne? Vielleicht eine Gildenkampagne? Oder eine eventbegleitende Kampagne?

An dieser Stelle sei auch darauf hingewiesen, dass es auf Wago noch weit mehr interessante Kreationen von anderen Autoren gibt. Klickt euch einfach mal ein wenig durch https://wago.io/totalrp.


Viel Spaß beim Experimentieren und
:wave: bis zum nächsten Sonntag…

1 Like

Extended am Sonntag #13


Wie man seine Extended-Daten rettet

Zur Abwechslung gibt es jetzt mal was total langweiliges, aber gleichzeitig auch total wichtiges.
Wenn man sich einloggt und plötzlich keine Profile mehr hat, oder alle eigenen Extended-Kreationen verschwunden sind, ist es meistens schon zu spät.
Daten muss man sichern, bevor das Unheil eintritt. In diesem Beitrag erkläre ich, wie, warum und wogegen ihr eure Extended-Daten schützen solltet.

Warum muss ich mich darum kümmern?

Deine Profile, dein Inventar und auch deine Extended-Kreationen werden auf deinem eigenen Computer gespeichert und nirgendwo sonst (es sei denn, du sorgst manuell dafür).
Wenn diese Daten aus irgendeinem Grund verschwinden, kann dir niemand helfen, selbst wenn er/sie es wollte.
Sich eigene Kreationen auszudenken kann durchaus Spaß machen, aber das ganze nochmal abzutippen oder einzugeben macht dann schon weniger Spaß.
10 Minuten Backup-Verwaltung können hier stundenlangen Frust ersparen.

Wieso können die Daten überhaupt verloren gehen?

Man sollte meinen, dass Datenverlust ein Problem aus den 90ern ist.

Meistens ist WoW selbst schuld

Ein typisches Szenario: WoW stürzt ab und danach sind alle Addon-Einstellungen futsch. Der Spielabsturz ist in diesem Fall oft nicht das Problem, erst mit dem darauf folgenden Spielneustart gehen die Addondaten verloren. Aber wer denkt bei einem Absturz im Eifer des Gefechts schon daran, zuerst nach rettbaren Daten zu sehen? Auch hier wieder mein Mantra: Daten vorher sichern, nicht erst warten, bis das Spiel abstürzt!
Bedenke, dass nicht nur Spielabstürze ein Problem verursachen können. WoW verwaltet für uns den verfügbaren Speicher. Das ist ein Sicherheitsmechanismus, damit Addons die Festplatte nicht zumüllen können. Wenn du viele Addons verwendest, die viele Daten abspeichern, kann es passieren, dass WoW sich weigert, all diese Daten auf der Festplatte zu speichern. Extended muss dabei nichtmal der Verursacher sein, denn alle Addons teilen sich denselben Speicher.

Andere Ursachen

Natürlich kann es auch zu Hardware-Fehlern kommen (d.h. deine Festplatte geht kaputt).

Auch wenn es banal klingt, es kommt hin und wieder vor, dass man selbst Kreationen oder Profile löscht, die man später wiederhaben möchte. Mitunter hast du dich bei der Erstellung eines Items verhaspelt und möchtest dieses auf einen früheren (funktionstüchtigen) Stand zurückversetzen.

Wo speichert Extended seine Daten ab?

In deinem WoW-Installationsverzeichnis (unter Windows standardmäßig C:\Programme\World of Warcraft\) gibt es das Unterverzeichnis World of Warcraft\_retail_\WTF\Account\[AccountName]\SavedVariables. Den grün hinterlegten Teil musst du dabei durch deinen Account bzw. deine Accounts ersetzen.
Besonders drei Dateien sind für Extended wichtig.

  • totalRP3.lua speichert deine eigenen Profile, deine TRP3-Einstellungen und das Extended-Inventar sowie das Extended-Questlog deiner Charaktere.
  • In totalRP3_Data.lua werden die Profile anderer Spieler abgespeichert.
    AHA! Mein Profil wird also doch auch woanders abgespeichert! … Mag sein, aber es ist nicht ohne weiteres in ein eigenes Profil umwandelbar.
  • totalRP3_Extended.lua enthält deine eigenen Items und Kampagnen sowie solche von anderen Spielern, und außerdem alle Verstecke und sonstige Drops aus dem Dropsystem.

Diese drei Dateien sind das Minimum, dass du sichern solltest. Wenn du dann schonmal dabei bist, kannst du selbstverständlich auch großzügig den gesamten WTF-Ordner sichern. Dann ist nicht nur Extended gesichert, sondern auch alle anderen Addons.

Backup-Lösungen

Cloudservices

Das jedes Backup darauf hinausläuft, die Daten irgendwo hinzukopieren, wo sie sicher(er) sind, kann man einen Cloudservice benutzen. Diese kann man üblicherweise so einstellen, dass sie die Daten automatisch synchronisieren, man muss sich also nur ein einziges Mal wirklich darum kümmern. Außerdem kann man relativ komfortabel beliebige ältere Versionen wiederherstellen.

Die TRP3-Entwickler haben unter https://github.com/Total-RP/Total-RP-3/wiki/How-to-backup-and-synchronize-your-add-ons-settings-using-a-cloud-service einen englischsprachigen Guide bereitgestellt, wie man soetwas aufsetzen kann.

Manuelles Backup

Wer einen Cloudservice zu teuer/zu aufwändig/zu vertrauensunwürdig findet, kann die Dateien auch einfach selbst regelmäßig irgendwohin kopieren. Idealerweise ist das „irgendwohin“ ein anderes Gerät (andere Festplatte/USB-Stick/Handy).
Hierbei sollte man darauf achten, dass man das Backup auch wirklich regelmäßig macht, z.B. einmal im Monat, oder immer, nachdem man etwas größeres erstellt hat.

Ein Backup anwenden

Sollte der Fall der Fälle eingetreten sein, empfehle ich folgende Vorgehensweise:

  1. Atme beruhigt auf, denn du hast ja ein Backup gemacht.
  2. Sichere den aktuellen Stand deiner Addon-Daten, selbst wenn du ihn als „kaputt“ erachtest. Das ist für den seltenen Fall, dass das Backup nicht funktioniert.
  3. Wichtig: Beende das Spiel.
  4. Ersetze die Addon-Dateien im SavedVariables-Ordner durch dein Backup.
  5. Starte das Spiel neu.
  6. Überprüfe, ob sich TRP3 (und ggf. andere Addons) wieder in einem akzeptablen Zustand befindet.

Viel Spaß beim… ähm Datensichern… und
:wave: bis zum nächsten Sonntag…

4 Likes

Juhuu! Ich sollte öfters mal Backups machen… allein dafür, sollte ich einen neuen PC kaufen.
Arigatou Sensei Seleves! :wink: :smile_cat:

1 Like

Extended am Sonntag #14


Neue Funktionen in Extended 1.5.0

Im Zuge von Patch 9.2 wurde Extended um einige Features angereichert. Auch wenn es sich hierbei um kein großes Release handelt, ist für den einen oder anderen bestimmt etwas nützliches dabei.

Id-Operanden

Zwei neue Operanden erlauben es, die Id der aktuellen Kampagne sowie die Id von Items in einem Behälter festzustellen.
Ersteres ist nützlich, wenn man sicherstellen will, dass Kampagnen-Items nur benutzt werden können, während eine bestimmte Kampagne läuft.
Den zweiten Operanden kann man benutzen, um zu erkennen, ob sich ein bestimmtes Item in einem Behälter befindet, oder ob es sich an einem bestimmten Platz befindet.

Item-Eigenschaften

Mit einer weiteren Reihe von neuen Operanden lässt sich der Name, das Icon, der Wert, die Qualität und das Gewicht eines Items mit vorgegebener Id ermitteln. In Kombination mit den oben genannten Id-Operanden kann man jetzt sehr viel mehr über den Inhalt einer Tasche erfahren, als es vorher möglich war.

Datums-Operanden

Während man bisher nur die Tageszeit (Stunde und Minute) ermitteln konnte, kommen jetzt auch Jahr, Monat, Monatstag und Wochentag hinzu.
Wer schon immer Dailys und Timegating in Extended umsetzen wollte, kann das jetzt tun :wink: .
Beachte, dass sich alle Zeitangaben auf die Ortszeit des Spielers beziehen.

Ausklingdauer bei Sounds

Mit der optionalen Ausklingdauer können Sounds nun auch sanft ausgeblendet werden. Sie werden dann über einen festgelegten Zeitraum kontinuierlich leiser, statt abrupt zu enden.

Dynamische Grenzen für Zufallswerte

Der Bereich, aus dem der Zufallszahlen-Operand auswählt (z.B. 1 - 100), kann nun auch mit Variablen festgelegt werden, z.B. 1 - ${maxHP}.

Verbesserungen bei Dokumenten

Es wurden zwei Schaltflächen hinzugefügt, mit denen man zur ersten bzw. letzten Seite gelangt.
Außerdem können Links in Dokumenten, die auf Arbeitsabläufe verweisen, optional Parameter enthalten. Jeder Parameter in einem Link wird zu einer Arbeitsablauf-Variablen, die im aufgerufenen Arbeitsablauf verfügbar ist.

Beispiel
{link*onLinkClicked(a=1,b=2)*Linktext} ruft den Arbeitsablauf onLinkClicked auf, und versieht ihn mit den Variablen a und b.

Gleichartige Arbeitsabläufe werden somit gruppierbar.

Lua-Effekt

Allen neuen Operanden können auch im Lua-Effekt verwendet werden. Zusätzlich ist es jetzt möglich, die Funktionen date, tonumber und tostring zu benutzen.


Viel Spaß beim Experimentieren und
:wave: bis zum nächsten Sonntag…

3 Likes

Extended am Sonntag #15


Ein Minispiel: Pairs

In Zereth Mortis gibt es gar keine neuen Puzzlespiele (hust), also muss wohl mit Extended nachgeholfen werden.
Diesmal geht es um das Kartenspiel Pairs. (auch unter dem Markennamen Memory bekannt)

  • Das Spiel besteht aus 32 Kartenpaaren mit unterschiedlichen Bildmotiven auf der einen Seite. Die Rückseite sieht bei allen Karten gleich aus.
  • Vor dem Spiel werden alle Kartenpaare gemischt und mit der Rückseite nach oben in einem Rechteck angeordnet.
  • Der Spieler darf pro Zug zwei Karten umdrehen, d.h. das Bild wird sichtbar.
  • Wenn beide Karten das selbe Motiv zeigen, dürfen die Karten aufgedeckt bleiben. (Im Originalspiel werden diese Karten aus der Anordnung entfernt und der Spieler erhält sie als Punkte.)
  • Wenn die Karten nicht das selbe Motiv zeigen, müssen sie wieder umgedreht werden und der nächste Spielzug beginnt.
  • Sobald alle Karten aufgedeckt wurden, ist das Spiel zuende.

Import-Code

Vor der Erklärung findet ihr hier das fertige Item zum Schnell-Importieren:

Pairs !LJvBZTnUr4)lA6hStVtMsQo1XZKpyl7ulxh5CbYj3nxdHbbxjItGaQaG2rrJ1V9UaK6DkL761V1rAiXlp4bl2DXIfmUv8G4(TW)rDWNTJjrDIoTDNorrD6pA6DM4(DqeKE99pt0mt6vAUV8GFjMC19XK76H1CXKlV3Zd5MlkREZ1X9)BNgHTpi(YycPRFmAvxKGUsbFSVkzG)PxciqPyGLePXel3iMGKWmJSLDqKAoto)roo(EQu4RZF8TZF0Pvf5jG5OrG7tmZrE8)W8hB8Cd)ZLyBC8XZVTIGNcd0dSPo53aUR5tmJD(TZVvme7T5qHX68sjIdbgHtsgOW(FS83MiwxGUfKwOKelW1Q0dYYgq2GMfykPY3H9xxBw)str16)TR3)k(wcyZPC1uxdL2m9ZQsvQPao0GwFE((JAtDvuDq2srudgy4q0oDudRUqLsfPulih6TWlm3K39Z(QV51D(74RHm0oC8kA8ML)uKEwDKQsln4)U8mo0QnW0s3ZWoSqxnASSr(cSd1g0ViuR1p4P7zrQlB(JVYxodeJYCZFmvxVpKyPbBblVDlHEJ2xxsR3tALSwvQztuSNjWXDEJYAp10xZ73SugcoNFPc85DA)sJVNPApZJuOg)Q1IOC0sf(BRMDrf0JF1wcvcJp2ksH1KIneJGjPQsPYhF(xrL(MAw(cDvLz4pIA6FPASlu(2BbkDZ8p2oIvZTOfJ56)rW)sHfFQIjT9n0E3WRPAEroOCuV)Wgrz3k4Ff3(i(Br)IFKpCXsQh8ZXKzzToN)YhyOt1StYA9YSjy153(xMficln7KjVuoYl7(pJ7Fwm59x5h87XJs6FFGr67Ij)dwomqRLoXKBawkyIjV7JXjXKp3R6CLBA5XDfyDc103PvUBkgbyZT9n)tfy7(gPvT2zbP(g7Rn5m5D46g76s)cG0)cKl94GAzXsZFcxVbRo76bl8h9uRDoNP2dFcB8M9IpmWoM5kxlCyNvtVl2Zx2DDEjl909HueQNOcvPCk0kAkZmoxRv(DoudmrBHg1styxCGJzRCoBWsesHBknfY1QScLdmurEUwY8S7JEwd4kCCJ2AXypWHH9SqM(VlepbM9GdN5Xu7eGzYyQ09cczJMZqzZLrtKOsH2Xcm3EPDctYsfkelgVsOgj9659G1W4cMKMykSzcNE4W9HtpQaOS8ee3EGyhp1amEgDOCkoRuEM3jDpGFMzmcTX)MBMUniEMaEccBZtqvnDmyWnUgM9BSdanTqncqpdUKzTcEv1CMTgvvnddLFoBIASHnA0bGpYl5weVtaMOwuMukyk(2luV76VbpdsUHn051hJ0YuqHkL6GMlSCAcYf6rtJAFG5xPtKakeixOkwZ9ESafoOmByBB)xUkskqVuV4LGT43WvJW96Of6ifWh3oPgimjpdYNsFteTWvAIDatwhstoA3nOOPsnGlJRT5GtWPP46MMaYTf1WG(kqBLrN80KudduAJTLhFRAGMWsM6kmoj0Mofqf6Z1bcNgQe3eLH7tnmrAP)TQEk5A9yVkcxCCHsXW9TjAfmuyZqFR64pfEsxyaJfJvlZlW5QM9GEGGAKqbO7Dj9JeFlxxdSHadZXB)RNHO83EFA8aPuwklNPCchm0GNLudUmqMJBEcHzqfXeHX7zvTBcJTgcYxLwNQ2tdwlNU9fU)21Umuvu5x2j5q1jT3mxqhdD6X0VSGXfYvYNM7mXYltjWQRYOpKW7lh)NE4BMERdYNG4gkftgO3vK)XwBkYv489NJ(znnyiED(r(PsTUOHSUmLB7VwoQVSQ)nBEfqXoyeLDhiCHOVJvyLAVSuDy25Ip7GOM798F1LauBQY(FDYYhiJIAZD(7NU8(C4))XSNtbhtiTH0kVUl9JxFb5((us3p27ddQN0W3OzdEl)cmK7FyroQytpqIltCTQjYfyrdWZC2XEZpOqpNICufHroN)izIaqxSVvGImGbtvGk8nCQ(woORAHbpo6o8ahzqOktA(deSsR3GcupK(FhjxsrODV3NgVpF7WTec5tJn8txG51hUobw5H((NFcBct0VBiV)R8Zv7O3GiVoaHe(SsxgUtqyqDd885R9dYT4AfKRqn4RpjQZjTXWHrrN35SZBFkc2pyqIli7poiZGNWGZxC)oTcCUtxD90C6cAA358orNh1P8wlxJx7X9PQVGgj9t4DdAEAtuWVd7SurIRzVfQNxaF)NdRQREi8YBIWLnPxm50V6l8rSqWS61gLe5IJ)pp

Das Item verwendet den Lua-Effekt. Um es zu benutzen, müsst ihr mit ALT+Rechtsklick Lua-Skripte für dieses Item erlauben.

Struktur

Das Item ist als Dokument-Item aufgebaut. Der Arbeitsablauf onUse im Item sorgt für das Mischen der Karten, während das innere Dokument sich um die Darstellung des Spielbretts sowie die einzelnen Spielzüge kümmert.
Das Spieldokument wird hierbei dynamisch erzeugt und nach jedem Zug aktualisiert. Dafür sorgt der Arbeitsablauf onCardClick im Dokument.

Einstellen des Spielbretts (onUse)

Grundeinstellungen

Im Lua-Effekt des Item-Arbeitsablaufs lege ich zunächst einige Variablen fest. Das erkennt man am vorangestellten args.object.vars.

  • width und height stellen die Breite und Höhe des Spielbretts ein.
  • backside ist das Icon, das die Rückseite der Karten darstellt.
  • icons ist die Liste der Motive.

Modellierung der Karten

Alle Karten werden in der Liste cards gespeichert. Jede einzelne davon hat zwei Eigenschaften:

  • index gibt an, um welche Karte es sich handelt. Ich verwende also keine Namen wie Kaninchenkarte, sondern simple Nummern von 1 bis 32, denn um 8x8 Karten zu belegen, brauche ich 32 Paare. Dieser Index wird sich nicht mehr ändern.
  • shown ist ein Wahrheitswert, der angibt, ob die Karte schon aufgedeckt wurde. Am Anfang ist dieser Wert bei allen Karten false, aber im Verlauf des Spiel werden diese nach und nach auf true gesetzt.
local n = args.object.vars.width * args.object.vars.height
local cards = {}
for i = 1, n/2 do
    table.insert(cards, {index = i, shown = false})
    table.insert(cards, {index = i, shown = false})
end

In diesem Code-Teil erkennt man, wie die Karten nach Paaren geordnet in die Liste eingefügt werden. table.insert steht zwei mal dort, denn für jedes Motiv gibt es zwei Karten.

Mischen der Karten

Wären die Karten bereits geordnet, wäre das Spiel ziemlich leicht, also sorgt der nächste Teil fürs Mischen:

local temp, flipTo
for i = 1, n-1 do
    flipTo = math.random(i, n)
    temp = cards[flipTo]
    cards[flipTo] = cards[i]
    cards[i] = temp
end

Alle Karten müssen vollständig gemischt werden, also benutze ich eine Abwandlung der Vorgehensweise aus dem Beitrag zum Kartenmischen.

  • Um festzustellen welche Karte an die erste Stelle soll, würfle von 1 bis 64. Vertausche dann die Karte an Position 1 mit der an der erwürfelten Position.
  • Für die zweite Karte, würfle von 2 bis 64, denn die Karte an Position 1 wurde bereits ausgewürfelt. Danach wird wie im ersten Schritt getauscht.
  • Fahre fort, bis alle Karten gemischt sind.

Vorbereiten des ersten Spielzugs

Schließlich speichere ich meine nun gemischte Kartenanordnung als Objektvariable (args.object.vars.cards = cards). Außerdem lege ich zwei weitere Variablen firstCard und secondCard fest. Darin halte ich fest, welche Karten der Spieler umdreht. Beide Variablen sind zum Anfang 0, d.h. der Spieler hat noch keine Karte angerührt.
Ganz am Ende des Lua-Codeblocks zeichne ich das Spielbrett board. Die Erläuterung dazu kommt weiter unten.

Auswerten der Spielzüge im Dokument (onCardClick)

Jedes Mal, wenn der Spieler auf eine Karte klickt, muss das Spiel angemessen reagieren. Das hängt einerseits davon ab, welche Karte angeklickt wurde, und andererseits davon, wieviele Karten bereits aufgedeckt sind.
Ganz am Anfang des Lua-Skripts importiere ich die Arbeitsablauf-Variable cardIndex:

local cardIndex = tonumber(getVar(args, "w", "cardIndex"))
local v = args.object.vars

cardIndex steht für die Position der angeklickten Karte, nicht für das Motiv.
In der zweiten Zeile lege ich eine Abkürzung fest, das erspart Tipparbeit.

Spielzuglogik

Danach folgt ein kleines Monster. Dieses Monster sind die in Code gegossenen Spielregeln:

if v.firstCard == 0 then -- 1
    v.firstCard = cardIndex
elseif v.secondCard == 0 then -- 2
    v.secondCard = cardIndex
    if v.cards[v.firstCard].index == v.cards[v.secondCard].index then -- 2A
        v.cards[v.firstCard].shown = true
        v.cards[v.secondCard].shown = true
        v.firstCard = 0
        v.secondCard = 0
        effect("sound_id_self", args, "SFX", 9637, false)
    else -- 2B
        effect("sound_id_self", args, "SFX", 9638, false)
    end
else -- 3
    v.firstCard = cardIndex
    v.secondCard = 0
end

Okay, einmal kurz durchatmen, wir haben es mit einer Wenn-Dann-Sequenz zu tun.

  • 1 beschreibt die Situation, wenn noch keine Karte umgedreht wurde. In diesem Fall setzen wir die Variable firstCard. D.h. die erste Karte ist die soeben umgedrehte Karte
  • Bei 2 wurde die zweite Karte umgedreht. Jetzt muss das Spiel überprüfen, ob ein Paar gefunden wurde.
  • 2A behandelt den Fall, dass ein Paar gefunden wurde. Wir setzen die Marke shown für beide Karten auf true. Dann setzen wir unsere beiden Variablen firstCard und secondCard wieder auf 0 zurück. Somit beginnt ein neuer Zug.
    Schließlich lasse ich noch einen Sound abspielen, in dem eine freundliche Elfe darauf hinweist, dass ein Paar gefunden wurde.
  • 2B behandelt den Fall, dass kein Paar gefunden wurde. Auch dieser Fall wird von der überaus freundlichen Bluthelfe kommentiert.
    Beachte, dass hier die Variablen firstCard und secondCard nicht zurückgesetzt werden, sonst würde der Spieler das falsche Paar nicht sehen.
  • Der letzte Fall 3 behandelt die Auswirkungen eines falschen Zuges. Sobald eine dritte Karte gezogen wird, werden die anderen beiden verdeckt.

Darstellung des Spielbretts

Die zweite Hälfte des Lua-Effekts befasst sich mit dem sichtbaren Teil des Spiels.

local board = ""
local c = 0
for i = 1, v.width * v.height do
    if v.cards[i].shown or i == v.firstCard or i == v.secondCard then -- 1
        board = board .. "{icon:" .. v.icons[v.cards[i].index] .. ":32}"
    else -- 2
        board = board .. "{link*onCardClick(cardIndex=" .. i .. ")*{icon:" .. v.backside .. ":32}}"
    end
    c = c + 1 -- 3
    if c == v.width then
        board = board .. "\n"
        c = 0
    end
end
args.object.vars.board = board

Für jede Karte wird ein passendes Icon angezeigt.

  • An der Stelle 1 überprüfe ich, ob die Karte gerade sichtbar ist. Eine Karte ist sichtbar, wenn sie bereits als Paar gefunden wurde (shown) ODER wenn sie die erste (firstCard) oder zweite (secondCard) eines Spielzugs ist.
    Eine sichtbare Karte kann man nicht anklicken (d.h. umdrehen), also wird die Karte als normales Icon dargestellt.
  • Wenn die Karte nicht sichtbar ist (Stelle 2), muss die Rückseite angezeigt werden (v.backside). Außerdem muss die Karte anklickbar sein. Das übernimmt der Teil {link*onCardClick(cardIndex=" .. i .. ")*. Das ist ein parametrisierter Dokument-Link, ein neues Feature mit Extended 1.5.0.
  • Damit das Spielbrett schön rechteckig aussieht, füge ich in regelmäßigen Abständen (3) einen Zeilenumbruch ein: board = board .. "\n". Die Sequenz \n erzeugt einen solchen Zeilenumbruch.

Platz für Verbesserung

Nachdem du das Spiel ausprobiert hast, kannst du dir eine Kopie des Items erstellen und dich an folgendem probieren:

  • Verändere die Motive, verwende z.B. nur Bilder, die zu einer bestimmten Thematik passen.
  • Vergrößere oder verkleinere das Spielbrett. Wenn du das Spielbrett vergrößerst, brauchst du auch mehr Motive.
  • Verwende andere Soundeffekte, z.B. ein Kommentar eines zufälligen Volks.
  • Füge eine besonderen Effekt ein, wenn der Spieler alle Karten aufgedeckt hat. Dazu wirst du ein paar Codezeilen brauchen, die das Spielende feststellen.

Viel Spaß beim Experimentieren und
:wave: bis zum nächsten Sonntag…

3 Likes

Extended am Sonntag #16


Geheime Dokumente

Heute geht es darum, geheime Informationen oder wertvolle Gegenstände vor den Blicken oder Händen Unbefugter zu schützen. Das kann ein neugieriger Bote sein, der eine Nachricht überbringen, aber nicht lesen soll. Das kann ein Teilnehmer einer Schnitzeljagd sein, der die Trophäe erst bekommen soll, wenn bestimmte Vorbedingungen erfüllt sind. Oder es kann irgendetwas anderes sein, was der Extended-Benutzer (noch) nicht sehen können soll.
In den folgenden Beispielen wird der Schutzmechanismus immer ein Passwort sein, man könnte die Information aber auch hinter einem Rätsel oder allgemein einer Aufgabe verbergen.

:warning: Beachte, dass die Sicherheit hier lediglich im Spielkontext gewährleistet ist. Du solltest mit den folgenden Items auf keinen Fall echte Daten schützen!

Level 1: Statische Daten, statisches Passwort

Importcode: Geheimes Dokument !Trv4sjoqm4NL7b402c4CYm(dSG2ohwqtb88hHwBxHouAz2Db17g5z)s2f6nC6aZg2Szt(Y3(fqxmgJCPVoTOvpeiRRxRoT98E8(Tp5GrTOiGWiEnVoJnX)cH(JqyyiTtJWD9zV3rEIgX7d6z9hmaJUWXbHRJXRra8TUh3ZwtotpIWF20n7JBtR(9(KfILII1c5(KyXB6Z(Z5B(GUaDLR9)jg9dYoIVie0A(niCB6AXn1v6OA560YHPYfceU5b8zeMfIrT7qvoWLJSVqPlQENdoylhvGh7((TKF25CR3XhZACDDPUytGinxiPQYagI6rjQE121IknA)yyIW4dTguxnrj4FaX8QPdfn9Aroc7sLZ3iRxVHUlHxL9qyCQs9ATuBEa2y3KZmput9bczlfzRg34Vd7)acOVLfQgaDAKNcf64NLPvzljBdQYQRYpU5aoTW0KjcLhGy9PyJlg74QRoiq2rTAvrQC12Jq5L0IY7ekvktTpTDHS4Lx2NStiFvuSqi1FdHke8ogU3NzlsUzy75QL1VEcH9FI09jSY8lzeANsKTvwOFFOyNO0WQgHlmAYXNSgnm0N4k3ZDADUN3(eVwD7CzxNlqWNLVIskbQVhVuMwwIWuEOHC)fhLpLsZzDoZXovmGu56PhMXGHKNCIs8)uTA31JPdWFKbEHSsgEab69gcjZBTnknGm9NGrC2NXgnNqnr3k7a2eGVFp))Px3NukuIk71B6zRUEmqiZ9s6XmKoSOA38sHwlKZDVWaLNTs)BTZMQ9jndbS4Io9(EgPanwtBMeXRt7zGNVzySpxapNlPihycb4)nyMjCI9OvFtEMnW2mAJM3YFAe)7d

Der einfachste Fall ist ein Dokument, dass sich nur dann öffnet, wenn man ein Passwort eingibt.

  1. Erstelle einen Dokument-Gegenstand. Wenn du die Vorlage „Dokument-Gegenstand“ benutzt, wird automatisch ein vorbereitetes, inneres Dokument angelegt, dass sich bei Benutzung (onUse) öffnet.
  2. Überführe den Gegenstand in den Experten-Modus, denn es wird ein zweiter Arbeitsablauf benötigt.
  3. Füge dem Gegenstand neben onUse einen zweiten Arbeitsablauf hinzu: checkPassword.
  4. Entferne den Effekt „Dokument öffnen“ aus dem onUse-Arbeitsablauf, denn das Dokument soll erst nach der Passwortkontrolle angezeigt werden.
  5. Füge den Effekt „Experte > Eingabeaufforderung“ in den Arbeitsablauf onUse ein. Stelle darin die Objektvariable password ein sowie den Rückruf-Arbeitsablauf checkPassword.
  6. Der erste Effekt in checkPassword wird eine Bedingung sein: "Objektvariable password ist gleich dem direkten Text-Wert eniarku"
    In der Bedingung steht also das gesuchte Passwort. Als Fehlermeldung bei Nichterfüllung wähle eine Phrase wie „Zugriff verweigert“. Dieser Text wird angezeigt, wenn das falsche Passwort eingegeben wurde.
  7. Der zweite Effekt ist der „Dokument öffnen“-Effekt, der vorher aus dem Arbeitsablauf onUse entfernt wurde. Das Öffnen des Dokuments wird also hinter die Passwortkontrolle verlegt.

Das ist schonmal ein guter Anfang, aber das Passwort ist fest an das Item gebunden. Wenn sich das Passwort einmal herumgesprochen hat, benötigt man eine neue Version mit einem neuen Passwort.

Level 2: Statische Daten, dynamisches Passwort

Importcode: Ganz Geheimes Dokument !nsv3YPTsm4NLEBNPn2MqtdZKladjqkyiznH(ZCwSXwaUXExgVlesZe)003K(IvP1GZa9KZPJ9S)ODL0N(KwXT5(CpB83Qgo6Wz4SJLLvTtR7fwBBg3RgEdwppAmwgrt(FHZApKZ63d3P5SbTjPdqjEdP9DBwkVBhU3hSS4Sw(8wC2KECVtRJBh1S0PKP(mN90Qgrp3zRohYkcwalHKmiViWh2QFZtNS65IRlU2CNNste3)2OLHIfWOqL6bzE8B3Tqxe8RFkIHCXZKoO7ra0Y9tCVpIZKdzEnrylVFDgimNoA6LC2vHzGVuMQtw1fcr95SlVLpJZyUKoh6mscZNgnGhQcJKyoBty(0v5YSvOPdZxOkpK5bRbvrWEtueajOfNbcdBR0YCiUY(izZKilXzCV60sDzGG)PjknF)hRRnb(2GsNiE8sPq3D9caf7qIVb9OMeoDN0A7JusONmplmTpcr8OwdjqwswgsAe6zB7ZrOnMrjn3Hezqu3vHIFueCvz(bJOkQKOe8o300aFwlAZypA8oueMVDneABYYowNJ3SdTVNlYBIntZsurtfsnmxMgdX2XMce8ctmJUgJpPdzj9(0Iumwb)Vzd5SVdrhMnKgw)Bx8pgSEm7t8(rmotWzoKaN)6m((ksJRseRwR)xYVrlHO7Fr(RNSp6MhgZZQWtKueVFZoewcqJ6i(oGaoevKBiPxCXUx7)xQEeNvbtdpXMhMKoauQqQ46RRxKNmFErWgi)bizbKRFtviolpueT8vywSrJP2AQAP8Hdi3JApveq9KETxjkiADEI(X(Wgi1q(MwwSHJ3xcv19Qp29kgXSlwZZGuub178xMhMMILXCVZmf2)XjS2yIW5eRAN44ueyz1W2UHZzL9c7GT203TRZkl(o8MVV(7PNdhRKvTgNwNGc(yJqxpQIFWeZBN2JntyzpdRAy94S6BPf3IlivOEX98nVwXXMUV0IRiifuyBgJUvrBmOXuKY0GwBQelrLMZ)n

Um das obige Dokument zu verbessern, soll ein Mechanismus eingebaut werden, mit dem man das Passwort ändern kann. Das wird über einen Dokument-Link geschehen, d.h. wenn das Dokument geöffnet ist, hat man die Möglichkeit, das Passwort zu verändern.
Das Passwort wird dann nicht mehr in der Datenbank gespeichert, sondern individuell in jedem Item. Man kann also auch verschiedene Passwörter vergeben.
Ausgehend vom oben dargestellten Dokument-Item, gehe folgendermaßen vor:

  1. Im Arbeitsablauf onUse, füge den Effekt „Experte > Variablenoperation (Initialisierung)“ an erster Stelle ein. In diesem Effekt setzen wir die Objekt-Variable storedPassword. Das Standardpasswort soll zunächst leer bleiben.
  2. Im Effekt „Eingabeaufforderung“ ändere den Variablennamen zu inputPassword. Das gesuchte Passwort wird also in der Variable storedPassword gespeichert, während das eingegebene Passwort in inputPassword steht.
  3. Die Bedingung im Arbeitsablauf checkPassword muss dann entsprechend angepasst werden. Statt das eingegebene Passwort mit einem festen Text zu vergleichen, steht nun auf der einen Seite inputPassword und auf der anderen storedPassword.
  4. Jetzt fehlt nur noch die „Passwort ändern“-Funktion. Dazu legen wir einen dritten Arbeitsablauf changePassword an. Dieser liegt jedoch im inneren Dokument und nicht im Item selbst.
    Einziger Effekt in diesem Arbeitsabaluf ist „Experte > Eingabeaufforderung“ mit der Objektvariable storedPassword.
  5. Damit changePassword auch aufgerufen werden kann, fügen wir dem Dokument einen Dokument-Link hinzu.

Wir haben jetzt ein Dokument-Item, bei dem wir jedem Exemplar ein individuelles Passwort zuweisen können, bevor es verteilt wird. Aber das reicht mir noch nicht, denn der Inhalt ist festgelegt und kann nur in der Datenbank geändert werden.

Level 3: Die allesverschlingende* Schließkassette

* allesverschlingend-aber-danach-auch-wieder-ausspuckend-sofern-man-sich-das-passwort-gemerkt-hat

Importcode: Schließkassette !TF1xtnUnq8plDM(wBZz78hMlZKhcjP9YvWHdLaxBNQyh71jUySzKKdCCZ5Vk9f(MWxSURSXGdoPqkp2jzSLwjT)2D1U)Km3KpLBBI)nAIpT4m8TLHHLPHXYpOoiGB3eNbBSn(uXzt)nSn2NnGKMeptcud2u6jPlgKRqSvOpNT2vmpzXFbE4ADflL5dYs0q9h9(ts9mPYvLkNc3O42T4Sjbbqmcg9JH)JcL4ZyoZIe0CpbjkX7cWxdqGBeA21aqlsG1EcGoyu6ecWBLsEruiIA8pM5KEzMdeRw5gPGyiZ5xGLqSuD)DX(ypim(2uP3QOq4()UENVjjOnzrlkTTa3WOZtexeeLCnoBXxMftUjN5Le7)WSkCJCVWBfqJ7wXdkcneKu3E9k20xVrOcTIoLg2cHBS3kQtR9mGjvjcW)exP86er(otDoEBsWb1JXvIKlVQkg2qkiZCkuBUhTjsn1McHNDBQ5gOQi)C6t9YTgZ3r4omE9CCaLBymiMlJsuZjZUi0J)RlEhhgvk)hYf)svO1UvylTcB)kuyZDRWoAfEWRqHT2PcZ3TpOOTUVo6U30l92SUxjsRTSFV4v6vtr)TuvE)0GhRKZCQqeuh67fPtV6iopdeeYjs5)gfsvKKjPX(4o1Cjefubm2p)zco73BA0Pdb5In1B91)spr4g1LuZg5(td01KnOefKrmZPxMZth8b5FSoH0K)63QZ5AxkSKgSAMZJLW)F56lsHVKYvRCcXJbP0DjWzhcRU)o8iorMZLPsKhEDc20hEEDreqtsIN81OCZ8XZu2s9qn89vi6dJVkvvdppwMMNsSf(ED3Yj9QYB26PQvTLNfk31s348QslSsO(3txkcdcWqmiUgcxcc13vsNTz88TGD7n)knVDmFB9kJBLYB3euBJBQcX1h3jL2tQtEQbrxG6vFJPNDs2wVbR(YsDQXFFru8T3cfFHaj4LkcvF5iynePx8rJjaMm7HpfaN0mMU(zWdIy9XMF)xltL629)uEeX9Z(qFU(Rrgmrd)y0MzStP6vgBm(6Mw5wa(A4mUTbND850lCjhslLnCervfNQUfrWpeYPJWx)kwZbkfuyw(Up5QKzo3MM5OnlbsAXobV(OP57rqhpiNm9YqP3CABArYnlxLivHIeCt5Orue4Xu2UD15RFt7aOPB3hn3cp8IcdqtbHJ9P(6n8t6tDMztppRV2LgCk1zizewMy6XNgPNcJFiNDUE6SdPNdMQLmQiaC8qkaC0eoZh0tHXGiCdv(ttxjCJIq9JzbiKdgIrsR3z08DwwzoggDTm7AG46FgkVr7gytfov9hoYog13OpJ6Q6Im7AA0Tno(GNJJISa8SNiPoHz0G5NoQpBI9C0ZgFY0I0ZN95O18jQ5PNuyk3UuC()a

Das letzte Item ist ein Behälter, in den man beliebige Gegenstände einschließen kann.
Um das Passwort einzustellen, benutzt man den leeren, geöffneten Behälter. Wenn man Items in den Behälter legt und ihn dann benutzt, werden die Items eingeschlossen. Sie sind dann nicht mehr im Behälter zu sehen. Um die Items wieder auszuschließen, muss man den Behälter nochmals benutzen und das vorher festgelegte Passwort eingeben.

Damit das ganze funktioniert, braucht es etwas Luarkanmagie.

  1. Im onUse-Arbeitsablauf initialisiere ich zunächst einige Variablen, die wichtigste davon ist locked, die festhält, ob der Behälter gerade auf- oder zugeschlossen ist.
  2. Im fünften Effekt von onUse prüfe ich, ob der Beählter geöffnet ist. Wenn ja, prüfe im nächsten Effekt, ob der Behälter leer ist. Wenn der Behälter leer ist (und geöffnet), erfrage ein neues Passwort.
  3. Der Arbeitsablauf lock kümmert sich um das Einschließen. Zunächst werden die Zustandsvariablen aktualisiert, dann kommt das Herzstück, ein Luaskript:
    args.object.vars.content = args.object.content
    args.object.content = {}
    
    Der gesamte Inhalt (args.object.content) wandert in die Objektvariable content. Das was der Code macht, ist quasi ein Etikettentausch, so wie ein cleverer Arbeiter, der Zementsäcke vom Keller ins Lager schleppen soll, und daraufhin einfach "Lager" auf die Kellertür schreibt.
  4. Das Aufschließen funktioniert sehr ähnlich, nur, dass die Passwortabfrage vorgeschaltet wird. Außerdem prüfe ich, ob der Behälter leer ist, damit die eingeschlossenen Items keine anderen Items ersetzen. tryUnlock prüft, ob aufgeschlossen werden kann, onUnlock überprüft das Passwort, ändert die Zustandsvariablen und führt dann ein sehr ähnliches Luaskript wie oben aus.

Die Schließkassette ist sehr vielseitig, da man beliebige Items, sogar ganze Taschen, einschließen kann.
Hierbei gibt es einen kleinen Schönheitsfehler: Der Behälter wird nicht aktualisiert, während er benutzt wird, d.h. man kann Items sehen, die nur scheinbar darin liegen, bzw. leere Slots, die in Wirklichkeit belegt sind. Man kann sich behelfen, indem man die Tasche mit Doppelklick erneut öffnet.
Wer diesen Anzeigefehler beheben kann, darf sich einen Keks aussuchen.


Viel Spaß beim Experimentieren und
:wave: bis zum nächsten Sonntag…

4 Likes

Juhuuu!
Vielen Dank für die Mühe und die vielen Guides und Tipps! :smiley:

1 Like

Extended am Sonntag #17


Die Konzeptomate

Kennst du das auch? Du möchtest einen neuen Charakter erstellen aber dir fällt einfach kein Konzept ein?
Hadere nicht länger, iss eine Konzeptomate!

Kostprobe:

Der Charakter verbrachte die Jugendjahre in einem Wanderzirkus in Unterstadt.
Eine im Alkohol ertrunkene Handelsreise machte schließlich überdeutlich, worauf es ankommt:
Geld. Und im Zweifelsfall richtet man sich nach Velen.

Importcode: Konzeptomate !LZv3UTnUs4xMfO3C22yN2KUfyVWn)3M)ALtsp7fYM2I2I10KzjPIBsr9RYEZ(mSxL78l2zgkhBlhYeVahymafiqrswI8JdhoZ8nIKP1sBMEAn4Vn2eowpnb()21RxV2gBZhT136ME6MWtKC0P4XmDx8Fn)VPj7EwAYXhbx5stE)zyrKCyJYlpCp4LEZgW9BM((0KKDkV95nkRkSa(sAY3V(hJ)WUCZ427KZmSbo80B4Mogw3ChFC7mbC4df95QSVYYnWf)Y31grFH6hJBlu4LsDxMtOv)4LJ)W3FfwG(sDpHY)0)zbtk6j4MFGxXVHRCWzdNw(2U5sbFYFjfDZh3EY9D4MmEHdV8)mU9iTHv0BCBUDCBMAGE4q37Quj)Y3DgMWbvD7luzaIgoU9FmIl6XL2EmPCCBJaRihwJaAT(QrXWJ)Y3fzA5dOgeoOqCNpME6BH)JIPKtBaIy9GIHaM9Y0nBTFAYbSH891k3PAZqM8yMPppnz)pN2jn5QJsp91Oq)WA4tUl36eQBXh(Wc8PoSoE7pva3hVzRY7EEOBEYUicob6Gp9mp2CLD5h1CANzIL72dLM45jnXJVbpWN1blYstUHzAP78vEx417Qvzp8JtFIYhOBoV7GwQ0ew5VKmYReA81kE2V)7t1aVbAFpGgOHBN(86YNcFOeFpm(yGGY44QRHJ3(W7a)jfw4iuzBH341RdiV5kd5Df8oq)GUWecXVbVr9ARdixFJvgZxPHsUu1)aEVj)TQVsyxg(iW3yDa8A)2kd8l5gaPwgOUhqydYz4KARffKARUgYN5zbHBnVYrmDJR5gga0flEJV4h5lE8h1dXYV83kDcmthyzjJVMwld2RT6J2t6Ml61ZA4cBybKF8(MRduxFLb9o6UdCmHmQrkS9dc81aORTYG(9CWjPOFHQFieVPx743wlq(TRmMtUwBC3GJcSoM0fb7En(eOyxhGF7vh8DZlKwa0rg6JM8s2EDa6TwzmFa3h5JfK55G1fzejo2dcEIxdq)n)lGENcJd0t6B7XHahdHBSZlzTOKV664hcoIVJlCb1r8A2Rff7vxV(qqXacuoQjBVEDT1I2rTvx9yQJghWmi8WrVUrT1Y4XAR(asa2sK0tqi7hgwBT4CS2Q7D8CZK77ZLCrqm7DnwB94BC1DoEoqJnIz6spJ1wlaE1dF)eU1YFwpJ1kd6BTec)Qhb)XGOwXnt(NE9uXa(SUoGV6XttvawreIY6dzWOKcOwbnjmbcHAo0H0AvqZmkM1weeZuI2AfuFLq54M)SGlLlJBhz4RwbXxGaggNM5cjOjfL1k4(mtFJy4qwWyP(jL6Afb0NaLWx4YzswWHqeI86sJ7LG)oviithMRvqCJcmfVcvqx0uI7AvlvCRdZNCiqtksRvqDIRWmCKaQ4qQ00H1Avv6cJ2f2qfDiRUeIvd4YCMi44q6WuTcOpGL1N7UlSTdcXwTcO3diQQSDZhkIKfwkXyTcY)mZb4M7ckTPeH1QgqesWA9qDeliuI1AfCFsHSV2eMfiLOTwb0FmND342NOZImMKs0xRcCEmZieI0AvJFAzwm71Z700QlSiSNsvnGK3uOAnsBg0tQhfOMN9fAdunErtGHopFroJeDGsnwqFpFPEuMoy0nETUabS)8L4NE4d)hQyJXJ(5l2Z8Z(GqLPNgZ2Lkq4R8nOWTGdd41GR3ERT2(TPjz(YbEWmUKDlO95V(jcU45rutCkiecqXC9NP76NtbTS5lvMlnVpg3gNShHusJ5G2QluzTezTSCzVkfDY(Fbb8PBbb(bdi6eQylDFgy8QWXh2cgOAbCx91MwkZednjvMD8ZoKYqhK6)SGRU7FJY4))X7ZrAFb8MBWjbZGiFpbkLtN5G(kwF(WIhbyhzsMZCOEP2GtgOGcxsLhN5q(ymB8H9z9ZzgCMlA(mh6kh3UaNdyNzYIMmA6KgN5yFxH9oX1YW(0OtwCMd4gkMPBUG8zWzoIbxtzIyXmrQ83mhZjoEUmYWD6K6M54DF2qHmSsbDYBZc(x9rggaS0jFnZb7b8Sczyo40jtnlQkOCmByDbkLHMfhSHtfcBh(OcR1z5rOgsPe1Si4N83MbHZ2bLsrZCeFKYbS4IyCJsjOPcK5sjc6Guiiv2zw0WHf8u3DqqitOSZSiIJyOBX5rGpzfnjfttCTe4BaVFeqtMnml4KMHomnNJxwKpghLOyodTxQLV4Rp26SJmmmNJuEKO3if7YzWn5w5nmvKV(9pN0lNjBAMZK3ATgwqHdD4uodWnuzfuNp5CWkLCJiOSLsSjNH3lC5HZPnPisox59wCei1N46ZG7bS7K6reNg5cO1y028qOLo8iNH2pMZY6hzoGrhEKZG7hGitcAwGsCixWjHjYeeIu0gNJ3caV3goLyKI24meFsbMgp6tACoGzYEfMiPDKumgNb5J1Mxa(3IntrjeLX5qwif4A7(sTnC0RlYCC(hLUjPOpoBvY7BsSclWB3Vo2J46MoejFeYL4IcimQPeLYQ4UqnAY94QQ8r42rgQLvrSRW0PaOy6O)QNUkWLmvFq1wgqw)tmzZLKr8CJHlGQiOiIouoxE0FpCd9aSEfh80Hb6JWUH3pMLlkXeTkUVwlfoHD22NI38ByBcuIFA1gHs4)(9O0xHB7lszSoccXzTAtiJpCY9oruni6WETkU7ykCmzqithkSvHm34mS(pH9r6qMDjGJQhmJlIRpkXRTkWhYuIRlKWLHd3GuuCxc6t(htg3GwiP)NiTk0hi9OMNZ6frStjAVvXoUDe1qoqNRLGDDyalUizc7xIumHR2k6vihkuSibztj6WlzOP46C9tOZViL4PtO6MKIpC5EmxzGzs742FuGtTpUqHBfCjAzgZf(RRrhIXpztyXTEdmONqnfkXwEHgtH6HDjqMzOdJxBFVIMHWFv2hd)ZfMyQqKI78cih3Ufr1ha9mPdoRp36xGdyFqJm)wEy05G3pP0Qdl(6x46m5EtFUFo27vHFcjhDyBVSjLVo5EvFRdnOCJgAf12c3daXuhcGpWasAX)E5wZ7zfaMhez9ktjg4p2CYHfDaXUHHRUDUmMSNumWFCJWt(UbUzVoBKI1z4k)noqxaM8JhleD4LVSEfo7YM8x8OAw0HzEmKNj4bxVw0HG(YiVqXZ5EJRtJ8jOodD4PVm(BYToBbaHbUfc78obtY)g4SuGlFVhS6MbrXnU9iwUYkukr5OfLEy4OlOej)WEhXythXnd4MNkEckX4pC7qIBMV34ZL4t7GNszaiqtbysFfsxWCNWmi8w8ePseWYJLUIHKCIz9LuS)xg6GhVrt(NCLpeR9eQ74YbEAC(b(LzGeozVOE8Pukcc04Son6F5jns)q3TdZwq3cJWD7X8B4sFz6395to7I0PRwE3d7C5hFgMs80KeCZNNlHxW(RtNImjxMIeot2jWpLSlAu5vBS5RQxFC76B(UnQ)oWmMFJqFVVaf5LWV)Y38s41DxMwUH5NSt1xQ(7Qx7DB4TpTZzE4DeU5SFYvPNcV2Ux4)xYoyOWjjhb8S)gEYNNs4UCRFF39G6t5YN83sWbW75o2V(rn09FTdKGjNNGddE7wPjxKG7U(hdp9PSCdUSdX6St5Eh)03qpeyA6ZUIVz)Pg((KZB43X49hVSHht743e53fl86Bac3pThE9r7GMcUP1qGLDREADwRxVPxUc)2fNIh3PPVO2dleNhtqlOb8A3va2oUe6MV2NNbuJf3tyhaoMhGRlEuimRFlJJ7eYOIJx561piODPP)V

Wie es funktioniert

Man kann es sich sicherlich schon denken: Das Item benutzt vorgefertigte Textbausteine und fügt sie zufällig zusammen.

Ein Blick ins innere Dokument offenbart, welche Teile des Textes sich ändern können und welche nicht:

{p}
Der Charakter verbrachte die Jugendjahre ${origin} in ${location}.
{/p}
{p}
Eine ${qualifier} ${event} machte schließlich überdeutlich, worauf es ankommt:
{/p}
{p}
${trait}. Und im Zweifelsfall richtet man sich nach ${idol}.
{/p}

Die mit ${} markierten Stellen sind Variablen, die vor der Anzeige im Item-Arbeitsablauf onUse ihre Werte zugewiesen bekommen.

Das Auswürfeln der sechs Variablen habe ich auf einen Arbeitsablauf pro Variable aufgeteilt. Das ist nicht notwendig, aber übersichtlicher. Jeder der sechs Arbeitsabläufe (z.B. setEvent) funktioniert ähnlich: Würfle eine Zufallszahl zwischen 1 und 20 aus und weise dann, abhängig vom Ergebnis, einen der vordefinierten Werte zu.

All diese sechs Arbeitsabläufe werden im onUse-Arbeitsablauf der Reihe nach ausgeführt, zum Schluss noch etwas Deko und ganz am Ende das Anzeigen des Ergebnis-Dokuments.


Viel Spaß beim Experimentieren und
:wave: bis zum nächsten Sonntag…

4 Likes

Extended am Sonntag #18


Hinter den Kulissen der Datenbank

In diesem Beitrag von Enestress werden bereits alle wichtigen Funktionen der Objektdatenbank vorgestellt.
Im Folgenden wird es um das Konzept dahinter gehen, denn wenn man das Prinzip versteht, fällt es leichter, Kreationen zu verstehen.

Item ist nicht gleich Item

Wenn von „Item/Kampagne erstellen“ die Rede ist, ist üblicherweise das Festlegen von Eigenschaften, Arbeitsabläufen, etc. gemeint.
Mit einem Item in der Datenbank hat man aber noch kein Item in Inventar, denn die Datenbank ist keine Sammlung von Items, sondern von Itemvorlagen, man spricht hier üblicherweise von Klassen.
Dass die Datenbank kein „Lager“ ist, wird auch klar, wenn man die Datenbank-Funktion „Zu Inventar hinzufügen“ verwendet. Das betreffende Item verschwindet nicht aus der Datenbank, sondern ein Exemplar (Instanz) entsteht. Wenn dieses erstellte Exemplar zerstört wird, bleibt es in der Datenbank erhalten. Umgedreht bleibt ein Item im Inventar erhalten, wenn der zugehörige Datenbankeintrag verschwindet. Das Item ist dann aber nicht mehr benutzbar. Extended meldet uns „Missing Class“.

Datenbank = Bauplanbibliothek

Während das Inventar speichert, welche Items in meinem Besitz sind, speichert die Datenbank, was diese Items können, also ihre Eigenschaften.
Ein typischer Itemdatensatz ist sehr klein:

  • Item-Klasse
  • Taschenplatz
  • Anzahl (falls stapelbar)
  • ggf. Item-Variablen

Wenn das Item benutzt wird, konsultiert Extended die Datenbank:

  1. Gibt es die Item-Klasse in der Datenbank?
  2. Wenn ja, ist ein Verhalten „Bei Benutzug“ angegeben?
  3. Wenn ja, gibt es den angegebenen Arbeitsablauf?
  4. Wenn ja, führe den Arbeitsablauf aus.

Ohne Datenbankeintrag gibt es also kein Verhalten und auch keine Eigenschaften.

Austausch von Items

Wenn man einem anderen Spieler ein Item gibt, müssen folglich beide Teile (Klasse und Instanz) übertragen werden.
Wenn der Empfänger den Datenbankeintag bereits besitzt, wird die Klasseninformation ausgespart, aber halt:
Hier kommt die Version ins Spiel. Wer sich jemals gefragt hat, warum Extended zu jeder Item-Klasse eine Versionsnummer abspeichert, bekommt hier die Antwort. Die Versionsnummer wird verwendet, um nachzuprüfen, ob Absender und Empfänger eines Items oder einer Kampagne auf dem selben Stand sind. Sollte das nicht der Fall sein, fragt Extended nach, ob man die Version des Senders übernehmen möchte.
Die Datenbank kann immer nur eine einzige Version eines Objekts abspeichern, jedes Item der selben Klasse verhält sich also gleich. Wenn man eine neue Version eines Items erhält (entweder, weil man abspeichert, oder weil man einen neuen Import-Code einfügt), werden automatisch alle Inventar-Instanzen des Items aktualisiert.

Durchbrochene Hierarchien

In der Datenbank wird über innere Objekte eine Hierarchie aufgebaut. Diese Objekthierarchie hat genau zwei Aufgaben:

  • Übersicht beim Erstellen verschaffen
  • dafür sorgen, dass beim Handeln alle notwendigen Klassendaten mitgeliefert werden

Und das war’s. Im Inventar hat sie keinerlei (*) Bedeutung. Das einzige Ordnungsprinzip, das das Inventar kennt, ist die Anordnung der Taschen.
Jedes innere Item wird im Inventar zu einem eigenständigen Gegenstand, selbst, wenn das äußere Item suggeriert, dass das innere Item von diesem produziert/erschaffen/etc. wird oder auf sonstige Weise mit ihm zu tun hat.

(*) Bis auf eine Ausnahme: Wenn man bei einer Tasche festlegt, dass sie nur innere Items enthalten darf, wird es nicht möglich sein, ein anderes Item darin abzulegen.

Jedes Item steht für sich

Dass jedes Item (d.h. jede Instanz) losgelöst von der Objekthierarchie in der Datenbank existiert, hat zwei Konsequenzen.
Einerseits ist es möglich, jedem einzelnen Item einen individuellen Satz von Variablen zu verpassen, also einen individuellen Zustand.
Andererseits ist es nicht mehr möglich, mit einem Item im Inventar Einfluss auf ein anderes zu nehmen.

Typische Fragestellungen:

Wie kann ich die Variablen eines inneren Items verändern?

  • Es ist nicht klar, welches innere Item gemeint ist, denn es könnten mehrere Exemplare im Inventar liegen.
  • Hier liegt ein kategorisches Missverständnis vor: Innere Items sind Eigenschaften der Klasse, aber Variablen gehören zur Instanz.

Wie kann ich das äußere Item löschen?

  • Wie bei der ersten Frage ist nicht klar, welches Exemplar gelöscht werden soll.
  • In diesem konkreten Fall kann man sich behelfen, indem man das Item direkt über die Id anspricht, statt sich auf die Eigenschaft „äußeres Item“ zu verlassen.

Viel Spaß beim Experimentieren und
:wave: bis zum nächsten Sonntag…

2 Likes

Extended am Sonntag #19


Texturen und Bilder

Dokumente können Bilder enthalten, ebenso wie Zwischensequenzen. Bei Zwischensequenzen kann man außerdem noch ein Hintergrundbild einstellen.
Während Extended bei Dokumenten eine Bildersuche anbietet, muss man bei Zwischensequenzen den Bildpfad angeben.
Heute wird es darum gehen, wie man an diese Bildpfade kommt.

Grundsätzliches

In Extended können nur Bilder, Artworks oder Texturen aus dem Spielclient verwendet werden, eigene Kreationen (wie z.B. eine Charakterzeichnung) können nicht angezeigt werden.
Die Experten unter uns werden einwenden, dass man Bilder, die im Addons-Verzeichnis liegen, sehr wohl im Spiel anzeigen kann. Das würde dann aber nur auf dem eigenen Rechner funktionieren, was dem Zweck von Extended, nämlich dem Austausch von Items, zuwiderläuft.

Die Bildersuche im Dokument-Editor enthält bereits eine ganze Reihe an Bildpfaden, die man verwenden kann, sie ist aber nicht vollständig.

Die einfache Methode

Im einfachsten Fall ist das gewünschte Bild bereits in der Bildersuche hinterlegt. Wenn man solch einen Bildpfad benötigt, kann man wie folgt vorgehen:

  • Erstelle ein Dummy-Dokument.
  • Suche das Bild mit der eingebauten Bildersuche und füge es ins Dokument ein.
  • Der Bildpfad steht nun als Teil des {img}-Tags im Dokument, z.B. {img:Interface\QuestionFrame\answer-warboard-classic-StonetalonMountains:512:256}. Hier ist der gesuchte Pfad Interface\QuestionFrame\answer-warboard-classic-StonetalonMountains.

Möchte man dieses Bild für eine Zwischensequenz verwenden, benutzt man genau diesen Pfad.

Die fortgeschrittene Methode

Sollte man kein passendes Bild in der Bildersuche finden, kann man zunächst „informiert raten“. Wenn der Standard-Hintergrund für Zwischensequenzen bspw. Interface\DRESSUPFRAME\DressUpBackground-NightElf1 ist, dann gibt es bestimmt auch Interface\DRESSUPFRAME\DressUpBackground-Orc1
Wer einen besseren Überblick haben möchte, kann sich auch auf vorgefertigten Ressourcensammlungen im Internet umsehen. Auf diversen Projektseiten haben sich Addon-Autoren die Mühe gemacht, alle im Spiel enthaltenen Bilder aufzulisten.
:warning: Beachte, dass alle Bilder aus dem Spielclient geistiges Eigentum von Blizzard sind!

Die Expertenmethode

Texturensammlungen im Internet können veraltet oder unvollständig sein. Für alle, die es wirklich wissen wollen, hat WOW eine eingebaute Exportfunktion. Damit kann man alle Bilder aus dem Spiel in ein separates Verzeichnis extrahieren, wie aus einer ZIP-Datei, um sie anschließend zu betrachten.

  1. Besorge dir ein Bildbetrachtungsprogramm, das in der Lage ist, BLP-Dateien anzuzeigen.
  2. Stelle sicher, dass genügend Platz auf deiner Festplatte ist. Du wirst ca. 6 GB benötigen.
  3. Starte das Spiel mit der Konsolenoption:
    Öffne die Spieloptionen im Battle.net (Zahnrad neben dem blauen Startknopf).
    Setze einen Haken in „Zusätzliche Befehlszeilenargumente“. Ein Eingabefeld erscheint.
    In dieses schreibst du -console.
  4. Logge dich auf einem beliebigen Charakter ein.
  5. Gib den Makrobefehl /run SetConsoleKey("z") in den Chat ein. Dieser Schritt ist notwendig, weil die Standardtaste, um die Konsole aufzurufen, sich mit dem deutschen Tastaturlayout beißt.
  6. Logge dich aus. „Ausloggen“, nicht „Spiel verlassen“.
    Du landest wieder im Charakterbildschirm.
  7. Drücke die Taste z, also die eben festgelegte Konsolentaste.
    Ein Konsolenfenster öffnet sich.
  8. Gib ExportInterfaceFiles art ein und drücke dann die Eingabetaste.
    Dieser Befehl braucht seine Zeit. Das Bild kann für mehrere Minuten einfrieren, denn hier werden mehrere GB an Bilddaten entpackt.
    Übrigens: Mit ExportInterfaceFiles code bekommt man den Lua-Code des Standardinterfaces.
  9. Entferne das zusätzliche Argument aus Schritt 3 wieder. Der Makrobefehl aus 5. setzt sich nach einem Spielneustart von selbst zurück.

Nun sollten alle Texturen in _retail_\BlizzardInterfaceArt\ im WOW-Installationsverzeichnis liegen. Wenn du ein passendes Bild gefunden hast, entspricht der Pfad, den du in Extended angeben musst, dem Teil, der mit Interface anfängt, aber ohne die Dateiendung .BLP.


Viel Spaß beim Experimentieren und
:wave: bis zum nächsten Sonntag…


(OT) Edit/Nachtrag: Defekte Dokument-Links in Version 1.5.0

In Version 1.5.0 hat sich ein Fehler eingeschlichen, der bewirkt, dass externe Links in Dokumenten nicht mehr angezeigt werden.
Wer diese Feature ausgiebig benutzt, kann auf einen Bugfix warten, oder, im Geiste dieses Threads, die defekte Datei vorab selbst austauschen.
Die Korrektur ist bereits auf dem GitHub von Extended verfügbar. GitHub ist eine öffentlich zugängliche Code-Bibliothek für viele Software-Projekte, darunter auch WoW-Addons wie Extended.

  1. Lade die Datei https://raw.githubusercontent.com/Total-RP/Total-RP-3-Extended/8656bced78199dde22792df5823e5569b7ae99e1/totalRP3_Extended/document/document.lua herunter.
    Auch zu erreichen unter https://github.com/Total-RP/Total-RP-3-Extended/blob/master/totalRP3_Extended/document/document.lua. Von dort klickt man auf „History“ und dann auf das Commit vom 18. März („Document URL fix“). Dort klickt man rechts auf der Titelleiste der geänderten Datei auf weiteres „(…)“ und dann „View file“. Zum Schluss führt ein Klick auf „Raw“ zur gesuchten Datei.
  2. Speichere die Datei in deinem WoW-Installationsverzeichnis unter _retail_\Interface\AddOns\totalRP3_Extended\document\document.lua.

Wer so vorgeht, bekommt das Beste aus beiden Welten, die aktuellste Version, aber ohne den nervigen Bug.
Sobald die nächste Extended-Version erscheint, werden alle Dateien regulär mit der neuesten veröffentlichten Version überschrieben, es ist nicht notwendig, diesen kleinen Vorab-Fix „aufzuräumen“.

2 Likes

Jeah! Vielen dank für die Infos!

1 Like