server/src/doc/triggers.txt

112 lines
4.3 KiB
Plaintext

==-------------------==
New Style Eventhandling
==-------------------==
Zweck des ganzen ist es, möglichst frei Reaktionen auf Ereignisse zu
implementieren. Dazu muß natürlich defineirt sein, was so ein Ereignis
ist. Sowohl die Eriegnisse als auch das, was daraufhin geschieht, muß
möglichst flexibel erweiterbar sein. außerdem sollen solche
Ereigniss-Behandlungen zur Laufzeit defineirt werden können. Die möglichen
Events kann man nur zur Compilezeit definieren, und auch die Klassen von
Behandlungsroutinen, aber festzulegen wer wann auf was reagiert sollte
durch einen Spruch, das auftauchen eines Drachen, einen Event oder den Tod
einer Einheit ausgelöst werden können, und beliebiges anderes.
Wie's geht:
Wenn durch den Code ein Event "event" ausgelöst wird, dann wird für das
betroffene Objekt X die Funktion handle_event(X->attribs, "event")
aufgerufen. Ja, der Event ist ein String.
handle_event(a, e) sucht in der Liste der attribute nach einem
at_eventhandler Objekt. So ein at_eventhandler verwaltet eine Liste von
Trigger-Objekten trigger_list mit Daten und handle() Funktion, die im Fall
des Events aufgerufen wird. Für jeden event-typ (string) gibt es ein
solches at_eventhandler Attribut in der Attributliste, das mehrere
Trigger-Funktionen beinhalten kann. Ich glaube, die hat Ingo in seinem
Ansatz "action" getauft.
Wurde ein Passendes gefunden, dann wird der Reihe nach jeder Trigger
ausgeführt.
Das ganze wird im Datenfile sogar ziemlich lesbar, wie man hier an diesem
Magier sieht:
eventhandler destroy killunit LeL end
Hier ist ein eventhandler, der im falle eines "destroy" Events auch die
Einheit LeL killt (LeL ist der Vertraute des Magiers).
Neue Trigger-Typen machen:
Neue Trigger zu definieren ist ziemlich leicht, und ich habe schonmal ein
paar flexible vordefiniert. Sie sollten möglichst im Verzeichnis triggers/
landen. Dran denken, das jeder in Eressea verwendete trigger-typ mit
tt_register() angemeldet werden muß. Das passiert in der Datei
eressea/triggers.c
Dabei lohnt es sich, die trigger etwas genereller zu mchen. Für viele von
ihnen sollte man resolve.[hc] verstanden haben, da man das zum Speichern
von Referenzen auf Parteien, Einheiten, usw. benötigt.
Trigger aktivieren:
Der Trigger sollte jeweils in der Attributliste des Objektes landen,
dessen Existnez für die Ausführung nötig ist. z.B. der Trigger zum Töten
des Familiars beim Magier, der zum übergeben eines item an eine person die
ein gebäude betritt, in das Gebäude.
Beispiel: Wenn die verzauberte Burg b zerstört wird, soll der zaubernde
Magier einen Schock erleiden:
add_trigger(&b->attribs, "destroy", trigger_shock(mage));
Steht die Burg jedoch nach 10 Runden noch an ihrem Fleck, bekommt er einen
Schatz von 100 Silber:
trigger * ttreasure = trigger_giveitem(mage, &i_silver, 100);
trigger * ttimer = trigger_timetrigger(10, ttreasure);
add_trigger(&b-attribs, "timer", ttimer);
Wie man sieht, kann ein trigger einen anderen auslösen, und mit etwas
Geschick kann man ganze Ketten von Ereignissen hinbekommen, die wieder
neue Trigger setzen, usw.
Bisher definierte Events: (NI=Not Implemented)
{building|faction|unit|ship}:"destroy" - Das Objekt verschwindet.
{building|faction|unit|ship|region}:"timer" - einmal pro Runde in
eressea.c::ageing()
{building}"enter" - Gebäude oder Schiff wird betreten (NI)
Bisher definierte trigger:
- timeout: meta-trigger, aktiviert eine liste von triggern nach einer
zeitspanne.
- changerace: ändert race/irace für eine einheit
- giveitem: gibt items eines typs an eine einheit.
- killunit: tötet die angegebene einhiet.
- shock: schockt einen magier.
- changefaction
- removecurse
adaptierte alte trigger:
- famililars:
familiar: on "destroy" shock(mage)
mage: on "destroy" killunit(familiar)
- toad:
mage: on "timer" timeout([changerace(), giveitem(toadslime)])
- summondragon:
region: on "timer" timeout([createunit()])
- magicboost:
mage: on "timer" timeout(createcurse())
- charm:
target: on "timer" changefaction(target)
new faction: on "destroy" destroy(target)
problems to be solved:
- propagation of triggers/attributes in general
- was, wenn ein removecurse(c) ausgefuehrt werden soll, aber der curse
sich propagiert hat? dafür waere wohl ein forwarding-graph ganz geeignet.
(spells:5066, alp)
TODO:
- fprintf/fscanf nochmal checken.