Effekte
Es ist möglich, an jedes Objekt variable Mengen an Zusatzeffekten zu binden ohne dafür zusätzliche Objekte zu benötigen. Dieses System ist besonders für Zauber interessant.
Einleitung
Effekte sind, grob gesehen, dynamische Timer mit Eigenschaften, die sich an ein Zielobjekt binden lassen. Effekte an sich bieten keinerlei graphische oder akustische Funktionen - dafür sind Partikel oder Objekte zuständig - sondern sind eine reine Scripthilfe. Zudem liefern sie ein allgemeines Interface, über das sich Statusveränderungen an Objekten untereinander abstimmen lassen.
Dazu ein Beispiel eines Unsichtbarkeitszaubers ohne Effekte:
/* Invisibility spell without effect system */ local remaining_time; // time the spell is still in effect local target; // the clonk that has been made invisible local old_visibility; // previous visibility local old_modulation; // previous color modulation func Activate(object caster, object caster2) { // get caster if (caster2) caster = caster2; target = caster; // save previous visibility and color modulation of the caster old_visibility = caster.Visibility; old_modulation = caster->GetClrModulation(); // make caster only visible to himself and allies, color him like a ghost caster.Visibility = VIS_Owner | VIS_Allies | VIS_God; caster->SetClrModulation(ModulateColor(old_modulation, RGBa(127,127,255,127))); // start timer: 30 seconds invisible remaining_time = 30; } func TimerCall() { // count down if (remaining_time--) return; // done: remove object RemoveObject(); } func Destruction() { // spell is being removed: end invisibility target->SetClrModulation(old_modulation); target.Visibility = old_visibility; }
Das Zauberobjekt bleibt hier einfach so lange erhalten, bis die Zeit abgelaufen ist, und macht den Clonk dann wieder sichtbar. Die Sichtbarmachung im Destruction-Callback macht das Objekt auch wieder sichtbar, wenn das Objekt aus irgendwelchen Gründen (z.B. Wechsel der Szenariensektion) entfernt wurde - ansonsten bliebe der Clonk in dem Fall auf ewig unsichtbar. Außerdem wird ein Timer verwendet, bei dem davon ausgegangen wird, dass er in der DefCore definiert ist und jede Sekunde aufgerufen wird. Ein Timer mit einem Intervall in der Dauer der Unsichtbarkeit wäre übrigens nicht möglich gewesen, da die Objekt-Timer je nach Spielzeit an unterschielichen Zeiten im Intervall beginnen können. Um den Timer zu sparen, hätte man also eine Aktivität definieren müssen.
Dieses Script hat allerdings auch einige Probleme: Beispielsweise kann der Zauberer keinen weiteren Unsichtbarkeitszauber sprechen, während er unsichtbar ist. Der zweite Zauber wäre praktisch wirkungslos, weil der erste Zauber bei seinem Ablauf schon den Clonk sichtbar macht. Der Zauber müsste also eine Spezialbehandlung für diesen Fall einführen - aber nicht nur für diesen, sondern für alle anderen Zauber, die Sichtbarkeit oder Färbung des Clonks verändern. Zwar berechnet das Script eine vorherige Verfärbung mit ein, betrachtet aber nicht den Fall, dass ein anderer Effekt diese zwischenzeitlich ändern könnte. Dieselben Probleme ergäben sich, wenn mehrere Effekte auf Clonk-Physicals (Sprunghöhe, Laufgeschwindigkeit, Kampfstärke, usw.), Sichtradius, Energie, Zauberenergie oder sonstigen Status einwirken. Über Effekte kann dies umgangen werden.
Anwendung
Effects are created using CreateEffect and removed with RemoveEffect. If an effect was successfully created, the callback Construction is made. Depending on the parameters, there can also be an Timer call for continuous activity such as casting sparks, adjusting energy etc. Finally, when the effect is deleted, the callback Destruction is made.
Now, the invisibility spell implemented using effects:
/* Invisibility spell with effect system */ // visibility - previous visibility // old_mod - previous color modulation func Activate(object caster, object caster2) { // get caster if (caster2) caster = caster2; // start effect caster->CreateEffect(InvisPSpell, 200, 1111); // done - the spell object is not needed anymore RemoveObject(); return true; } local InvisPSpell = new Effect { Start = func() { // Save the casters previous visibility this.visibility = Target.Visibility; this.old_mod = Target->GetClrModulation(); // Make the caster invisible Target.Visibility = VIS_Owner | VIS_Allies | VIS_God; // Semitransparent and slightly blue for owner and allies Target->SetClrModulation(ModulateColor(this.old_mod, RGBa(127,127,255,127))); }, Stop = func() { // restore previous values Target->SetClrModulation(this.old_mod); Target.Visibility = this.visibility; } }
Hier startet das Zauberobjekt nur noch den Effekt, und entfernt sich dann. Die Engine sorgt dafür, dass keine Probleme bei der Sichtbarkeit auftreten: Effekte werden in einem Stapel angelegt, der sicher stellt, dass jeder Effekte immer in der umgekehrten Reihenfolge entfernt werden, in der sie hinzugefügt wurden. Dazu sind ein paar zusätzliche Start- und Stop-Aufrufe notwendig, auf die später noch eingegangen wird.
Der Effekt hat außerdem keinen Timer-Aufruf, aber trotzdem ein angegebenes TimerIntervall von 1111. Das sorgt dafür, dass mit dem ersten Aufruf nach 1111 Frames der Standard-Timer ausgelöst wird, der den Effekt löscht. Alternativ hätte man auch eine Timerfunktion definieren können:
Timer = func() { // return value of -1 means that the effect should be removed return -1; }
To store the previous status of the target object, properties of the effect are used. This way effects are independant of other objects and effects - remember that the magic spell object which has created the effect is already deleted. If you need to call functions in the context of the target object or other objects, use
->
.Prioritäten
When creating an effect you always specify a priority value which determines the effect order. The engine ensures that effects with lower priority are added before effects with a higher priority - even if this means deleting an existing effect of higher priority. So if one effect colors the clonk green and another colors the clonk red, the result will be that of the effect with higher priority. If two effects have the same priority, the order is undefined. However, it is guaranteed that effects added later always notify the
Effect
callback of the same priority.In the case of the red and green color, one effect could also determine the previous coloring and then mix a result using ModulateColor. But priorities also have another function: an effect of higher priority can prevent the addition of other effects of lower priority. This is done through the
Effect
callback. If any existing effect reacts to this callback with the return value -1, the new effect is not added (the same applies to the Start callback of the effect itself). Here an example:/* Spell of immunity against fire */ func Activate(object caster, object caster2) { // get caster if (caster2) caster = caster2; // start effect caster->CreateEffect(BanBurnPSpell, 180, 1111); // done - the spell object is not needed anymore RemoveObject(); return true; } local BanBurnPSpell = new Effect { Construction = func() { // On start of the effect: extinguish clonk Target->Extinguish(); }, Effect = func(string new_name) { // block fire if (WildcardMatch(new_name, "*Fire*")) return -1; // everything else is ok return 0; } };
This effect makes the clonk fire-proof for 30 seconds. The effect is implemented without any Timer or Stop callbacks as the complete functionality is achieved by simply blocking other effects which might have "Fire" as part of their name. This especially applies to the engine internal fire which has exactly the name "Fire". Of course, you could still add a Timer callback for graphic effects so the player can see that his clonk is immune. Also, you could create special visual effects when preventing incineration in
Effect
. For the like:[...] Effect = func(string new_name, var1, var2, var3, var4) { // only handle fire if (!WildcardMatch(new_name, "*Fire*")) return 0; // with fire, the three extra parameters have the following meaning: // var1: caused_by - player that is responsible for the fire // var2: blasted - bool: if the fire has been created by an explosion // var3: burning_object - object: incineratable object // extinguish burning object if (var3 && GetType(var3) == C4V_C4Object) var3->Extinguish(); // block fire return -1; }
Dies würde sogar alle brennenden Objekte löschen, die das Zielobjekt ansonsten anzünden würden. Der Typecheck für var3 ist enthalten, weil sich andere Effekte ebenfalls Fire in den Namen setzen und andere Parameter haben könnten. Es ist offensichtlich, dass man dies vermeiden sollte, weil Funktionen wie die obige dann im ungünstigsten Fall ein völlig anderes Objekt löschen könnten.
Die folgende Tabelle enthält grobe Richtlinien für Prioritäten von Originalpackeffekten:
Effekt | Priorität |
---|---|
Kurzer Spezialeffekt | 300-350 |
Nicht bannbare Effekte | 250-300 |
Magie-Bannzauber | 200-250 |
Andauernde Magie-Bannzauber | 180-200 |
Kurzfristige, positive Zaubereffekte | 150-180 |
Kurzfristige, negative Zaubereffekte | 120-150 |
Normale Effekte | 100-120 |
Engineinternes Feuer | 100 |
Permanente Zaubereffekte | 50-100 |
Permanente, sonstige Effekte | 20-50 |
Interne Effekte als Datenspeicher, etc. | 1 |
Allgemein richten sich Effekte natürlich erst einmal nach den Abhängigkeiten: Wenn ein Effekt einen anderen verhindern soll, braucht der verhindernde Effekt höhere Priorität (Selbst wenn es ein permanenter Effekt ist). Dann sollten kurzfristige Effekte gegenüber den längerfristigen eine höhere Priorität bekommen, damit die kurzfristigen Statusänderungen bei demselben Statuselement gegenüber den langfristigen Statuselementen eher zu sehen sind.
Das engineinterne Feuer liegt natürlich fest bei 100. Ein magisches Feuer, das die Eigenschaften des engineinternen Feuers auch benutzt, sollte entsprechend leicht darüber liegen, und in allen seinen Callbacks die entsprechenden FxFire*-Aufrufe mit aufrufen. Dabei sollten stets alle Callbacks (also Start, Timer und Stop) weitergeleitet werden, da diese voneinander abhängen und sich diese Abhängigkeiten auch in verschiedenen Engineversionen verschieben können. Wenn das nicht geht, sollte das Verhalten besser gleich komplett per Script emuliert werden.
Effekte mit Priorität 1 sind ein Spezialfall: Für sie werden nie andere Effekte temporär entfernt und sie selber werden ebenfalls nie temporär entfernt.
Spezielle Add/Remove-Aufrufe
Damit die Engine sicherstellen kann, dass Effekte immer in umgekehrter Reihenfolge entfernt werden, wie sie hinzugefügt wurden, müssen zuweilen Effekte temporär entfernt und wieder hinzugefügt werden. In diesen Aufrufen sollte der Scripter natürlich alle Statuszustände löschen und wiederherstellen, damit sich die anderen Effekte danach ausrichten können. Aktionen, die nur einmal beim Starten oder enden des Effektes ausgeführt werden sollen. Dazu gehört zum Beispiel das Löschen des Zielobjektes beim letzten Beispielscript, oder auch Soundeffekte.
Effekte werden auch dann entfernt, wenn das Zielobjekt entfernt wird oder stirbt - der Grund wird im reason-Parameter an die Remove-Funktion der Effekte übergeben. Auf diese Weise kann man beispielsweise dafür sorgen, dass ein Clonk nach dem Sterben sofort wiederbelebt wird:
/* Resurrection spell */ func Activate(object caster, object caster2) { // get caster if (caster2) caster = caster2; // start effect caster->CreateEffect(ReincarnationPSpell, 180, 0); // done - the spell object is not needed anymore RemoveObject(); return true; } local ReincarnationPSpell = new Effect { Construction = func() { // Only at the first start: message Target->Message("%s gets an extra life", Target->GetName()); return true; }, func Stop(int reason, bool temporary) { // only when the clonk died if (reason != 4) return true; // the clonk has already been resurrected if (Target->GetAlive()) return -1; // resurrect clonk Target->SetAlive(true); // give energy Target->DoEnergy(100); // message Target->Message("%s has been resurrected.", Target->GetName()); // remove return true; } };
Dieser Effekt belebt den Clonk beim Tod so oft wieder, wie er den Zauber gesprochen hat.
Globale Effekte
There are two global effect types: Scenerio effects and global effects. They are bound to the
Scenario
and Global
proplists. With these effects, too, priorities are observed and temporary Add/Remove calls might be necessary to ensure order.Hiermit lassen sich zum Beispiel Änderungen an der Gravitation, Himmelsfärbung, etc. durchführen. Ein Beispiel für einen Zauber, der die Gravitation reduziert und mit der Zeit wieder an den regulären Wert anpasst:
/* Gravitation spell */ // grav - previous gravitation // change - change by the spell func Activate(object caster, object caster2) { // start global effect AddEffect("GravChangeUSpell", nil, 150, 37, nil, GetID(), -10); // done - the spell object is not needed anymore RemoveObject(); return true; } func FxGravChangeUSpellStart(object target, proplist effect, bool temporary, change) { // search for other gravitation effects if (!temporary) { var otherEffect = GetEffect("GravChangeUSpell", target); if (otherEffect == num) iOtherEffect = GetEffect("GravChangeUSpell", target, 1); if (otherEffect) { // add gravitation change to other effect otherEffect.change += change; SetGravity(GetGravity() + change); // and remove self return -1; } } // save previous gravitation effect.grav = GetGravity(); // for non-temporary calls change is passed and added to the changed value if (change) effect.change += change; // set gravitation change // the change can be not equal to change in temporary calls SetGravity(effect.grav + effect.change); return true; } func FxGravChangeUSpellTimer(object target, proplist effect) { // slowly return to normal gravitation if (Inside(effect.change, -1, 1)) return -1; var iDir = -effect.change/Abs(effect.change); effect.change += iDir; SetGravity(GetGravity() + iDir); return true; } func FxGravChangeUSpellStop(object target, proplist effect) { // restore gravitation SetGravity(effect.grav); return true; }
target
wird hier in allen Effektaufrufen nil
sein. Trotzdem sollte der Parameter immer an Aufrufe wie EffectCall() übergeben werden, da es dann auch möglich ist, den Effekt an den Zauberer oder ggf. den Zauberturm zu binden. In diesem Fall würde die Gravitation automatisch zurückgesetzt, sobald der Zauberer stirbt oder der Turm gelöscht wird.Zusammenfassen von Effekten
Im letzten Beispiel wurden mehrere Gravitationseffekte zusammen gefasst, so dass die Änderung der Gravitation länger andauert, wenn mehrmals gezaubert wurde. Die Zusammenfassung durfte nicht im Effect-Callback passieren, da der Gravitationseffekt immer noch von einem Effekt mit höherer Priorität (beispielsweise ein keine-globalen-Zauber-erlauben-Effekt) abgelehnt werden könnte. Über den speziellen Fx*Add-Callback kann man dasselbe Ergebnis aber auch einfacher (oder zumindest übersichtlicher) erreichen:
[...] func FxGravChangeUSpellEffect(string new_name) { // If the newly added effect is also a gravitation change, ask to take over the effect if (new_name == "GravChangeUSpell") return -3; } func FxGravChangeUSpellAdd(object target, proplist effect, string new_name, int new_timer, change) { // this is called when the effect has been taken over // add the gravitation change to this effect effect.change += change; SetGravity(GetGravity() + change); return true; }
Die Rückgabe von -3 an den Fx*Effect-Callback, sorgt dafür, dass der Fx*Add-Callback für den neuen Effekt ausgeführt wird. Der neue Effekt wird dabei nicht erzeugt, und die entsprechende AddEffect-Funktion gibt die Effektnummer des Effektes zurück, der den neuen Effekt übernommen hat. Die Methode hat gegenüber der weiter oben verwendeten also den Vorteil, dass der Rückgabewert von AddEffect benutzt werden kann, um festzustellen, ob der Effekt überhaupt erzeugt werden konnte.
Eigenschaften-Referenz
Effekte haben folgende Standard-eigenschaften
Name | Datentyp | Beschreibung |
---|---|---|
Name |
string | Kann geändert werden. |
Priority |
int | Siehe Prioritäten |
Interval |
int | Of the Timer callback. |
Time |
int | The age of the effect in frames, used for the Timer callback. Can be changed. |
CommandTarget |
proplist |
nil when created by CreateEffect, as the effect gets the callbacks itself. When created by AddEffect either the command object or the command definition, depending on which is used. |
Target |
proplist | The object the effect belongs to, or the proplists Scenario or Global for scenario and global effects. |
Benutzerdefinierte Eigenschaften
Viele Klassifizierungen von Effekten können einfach über den Namen geregelt werden. Auf diese Weise können beispielsweise schnell alle Zaubereffekte über Wildcards gesucht und entfernt werden. Falls man aber zum Beispiel eigene Eigenschaften definieren will, die auch für existierende Effekte gelten, kann man zusätzliche Effektfunktionen definieren:
global func FxFireIsHot() { return true; } // Function that removes all "hot" effects from the caller global func RemoveAllHotEffects() { var target = this; if(!this) return; var effect_num, i; while (effect = GetEffect("*", target, i++)) if (EffectCall(target, effect, "IsHot")) RemoveEffect(nil, target, effect); }
Über EffectCall() können natürlich auch Funktionen im Effekt ausgelöst werden; beispielsweise um bestimmte Effekte zu verlängern.
Blindeffekte
Manchmal müsste ein Effekt nur erzeugt werden, um die entsprechenden Callbacks in anderen Effekten auszuführen - beispielsweise bei Zaubern, die keine längere Animation benötigen, aber trotzdem durch andere Effekte blockiert können werden sollen. Ein Beispiel ist der Erdbebenzauber:
/* Earthquake spell */ func Activate(object caster, object caster2) { // check effect var result; if (result = CheckEffect("EarthquakeNSpell", nil, 150)) { RemoveObject(); return result != -1; } // execute effect if (caster->GetDir() == DIR_Left) CastLeft(); else CastRight(); // remove spell object RemoveObject(); return true; }
Der Rückgabewert von CheckEffect() ist -1 wenn der Effekt abgelehnt, und positiv oder -2 wenn er aufgenommen wurde. In beiden Fällen sollte der Effekt selber nicht ausgeführt werden; aber in letzterem Fall kann die Activate-Funktion Erfolg signalisieren und 1 zurückgeben.
Erweiterte Möglichkeiten
Da jeder Effekt seinen eigenen Datenspeicher hat, ist dies eine Möglichkeit, extern Daten an Objekte zu binden, ohne dabei die Definitionen verändern zu müssen. Außerdem können so einfache Aufrufe verzögert durchgeführt werden - beispielsweise erst ein Frame nach der Zerstörung eines Objekts, wie an einer Stelle im Ritterpack:
// The call CastleChange must be delayed so that the castle part is really gone when it is called // otherwise, the FindObject()-calls would still find the castle part func CastlePartDestruction() { if (basement) basement->RemoveObject(); // Global temporary effect, if not already there if (!GetEffect("IntCPW2CastleChange")) AddEffect("IntCPW2CastleChange", nil, 1, 2, nil, CPW2); return true; } func FxIntCPW2CastleChangeStop() { // notice all castle parts for(var obj in FindObjects(Find_OCF(OCF_Fullcon), Find_NoContainer()) obj->~CastleChange(); return true; }
Bei derartigen Effekten sollte der Name mit "Int" beginnen; insbesondere falls sie mit globalem Callback erzeugt werden, sollte darauf die ID des Objekts folgen, um Namenskollisionen zu vermeiden.
Zudem können bestimmte Aktionen beim Tod von Lebewesen ausgeführt werden, ohne dafür gleich eine neue Objektdefinition zu benötigen. In einem Szenarioscript kann beispielsweise stehen:
/* scenario script */ func Initialize() { // manipulate all wipfs for(var obj in FindObjects(Find_ID(WIPF), Find_OCF(OCF_Alive))) AddEffect("ExplodeOnDeathCurse", obj, 20); } global func FxExplodeOnDeathCurseStop(object target, proplist effect, int reason) { // died? boom! if (reason == 4) target->Explode(20); return true; }
Alle Wipfe, die von Anfang an im Szenario waren, explodieren beim Tod.
Benennung
Damit sich Effekte untereinander erkennen und manipulieren können, sollten folgende Benennungsschemata verwendet werden ("*abc" steht für Endungen, "abc*" für Namensanfänge und "*abc*" für Zeichenketten, die irgendwo im Namen vorkommen sollten.
Namensteil | Bedeutung |
---|---|
*Spell | Magischer Effekt |
*PSpell | Für das Zielobjekt positiver, magischer Effekt |
*NSpell | Für das Zielobjekt negativer, magischer Effekt |
*USpell | Neutraler, magischer Effekt |
*Fire* | Feuereffekt - die Funktion Extinguish() entfernt alle Effekte dieser Maske. |
*Curse* | Fluch |
*Ban* | Effekt, der andere Effekte bannt (z.B. Feuer- oder Zauberimmunität) |
Int* | Interner Effekt (Variablenspeicher, etc.) |
*Potion | Zaubertrank |
Effect names are case sensitive. Also, you should avoid using any of these identifiers in your effect names if your effect doesn't have anything to do with them.
Callback-Referenz
The following callbacks are made by the engine and should be implemented in your effect prototype as necessary.
Start
int Start (int temporary, any var1, any var2, any var3, any var4);
Called at the start of the effect.
this
is the effect itself. It can be used to manipulate the effect, for example with this.Interval=newinterval
.Der Parameter temporary ist 0 beim normalen Hinzufügen des Effektes, 1 wenn der Effekt nur hinzugefügt wird, weil er vorher temporär entfernt wurde, und 2 wenn der Effekt hinzugefügt wird, weil er zuvor temporär entfernt wurde aber jetzt selber gelöscht werden soll (in dem Fall folgt dann ein Remove-Aufruf).
Wenn temporary 0 ist, entsprechen die Werte var1 bis var4 den übergebenen Parametern an CreateEffect().
If temporary is 0 and this callback returns -1 the effect is not created and the corrsponding CreateEffect() call returns
nil
.Stop
int Stop (int reason, bool temporary);
When the effect is temporarily or permanently removed.
this
is the effect itself.reason gibt den Grund für das Entfernen des Effektes an, und kann einer der folgenden Werte sein:
Scriptkonstante | reason | Bedeutung |
---|---|---|
FX_Call_Normal | 0 | Effekt wird regulär entfernt |
FX_Call_Temp | 1 | Effekt wird nur temporär entfernt. temporary ist in dem Fall 1. |
FX_Call_TempAddForRemoval | 2 | nicht verwendet |
FX_Call_RemoveClear | 3 | Effekt wird entfernt, weil das Objekt gelöscht wird |
FX_Call_RemoveDeath | 4 | Effekt wird entfernt, weil das Objekt stirbt |
Wenn der Effekt nicht gelöscht werden soll, kann in der Funktion -1 zurückgegeben werden, um das Löschen zu verhindern. Bei temporären Aufrufen oder wenn das Zielobjekt gelöscht wird, bringt dies natürlich nichts.
Construction
int Construction (any var1, any var2, any var3, any var4);
Called when the effect is first created, before it is started. The parameters
var1
to var4
are passed through from CreateEffect.The return value is ignored.
Destruction
nil Destruction (int reason);
Callback when the effect is removed.
reason
is the same as in the preceding Stop
call, see above.The return value is ignored.
Timer
int Timer (int time);
Periodic timer call, if a timer interval has been specified at effect creation.
time gibt die die Zeit an, die der Effekt schon läuft. Diese lässt sich auch über effect.Time herausfinden.
Ein Rückgabewert von -1 bedeutet, dass der Effekt nach dem Aufruf gelöscht wird. Dasselbe passiert, wenn die Funktion nicht implementiert wird.
Effekt
int Effect (string new_name, any var1, any var2, any var3, any var4);
A call to all effects of higher priority if a new effect is to be added to the same target object. new_name is the name of the new effect;
this
is the effect being called.Achtung: Der neue Effekt ist noch nicht fertig initialisiert, und sollte daher nicht manipuliert werden. Insbesondere das Priority-Feld ist möglicherweise noch nicht initialisiert.
Die Funktion sollte -1 zurückgeben, wenn sie den neuen Effekt ablehnt. Da der Effekt auch noch von einem anderen Effekt abgelehnt werden kann, sollte dieser Callback nicht dazu verwendet werden, um beispielsweise Effekte zusammenzufassen (siehe Beispiel zum Gravitationszauber). Überhaupt sollte es möglichst vermieden werden, in diesem Aufruf die Effektliste zu manipulieren.
Return -2 or -3 to accept the new effect. As long as the new effect is not rejected by any other effect, the
Add
call is then made to the accepting effect, the new effect is not actually created, and the calling CreateEffect function returns the accepting effect. The return value -3 will also temporarily remove all higher prioriy effects just before the Add
callback and re-add them later.var1 bis var4 sind die Parameter, die an die CreateEffect()-Funktion übergeben wurden.
Add
int Add (string new_name, int new_timer, any var1, any var2, any var3, any var4);
Callback to the accepting effect if that has returned -2 or -3 to a prior
Effect
call. this
identifies the accepting effect to which the consequences of the new effect will be added.new_timer ist das Timer-Intervall des neu erzeugten Effektes; var1 bis var4 die an AddEffect übergebenen Zusatzparameter. ACHTUNG: Diese Zusatzparameter werden natürlich nicht bei temporären Aufrufen übergeben, sondern sind dann 0.
If -1 is returned, the accepting effect is deleted also. Logically, the calling CreateEffect function will then return
nil
.Damage
int Damage (int damage, int cause, int by_player);
Every effect receives this callback whenever the energy or damage value of the target object is to change. If the function is defined, it should then return the damage to be done to the target.
Der Callback wird bei Energiewertänderungen bei Lebewesen, sowie bei Schadenswertänderungen bei nicht-Lebewesen durchgeführt - nicht aber umgekehrt. cause gibt den geänderten Wert und den Grund an:
Scriptkonstante | cause | Bedeutung |
---|---|---|
FX_Call_DmgScript | 0 | Schaden durch Scriptaufruf DoDamage() |
FX_Call_DmgBlast | 1 | Schaden durch Explosion |
FX_Call_DmgFire | 2 | Schaden durch Feuer |
FX_Call_DmgChop | 3 | Schaden durch Fällen (nur Bäume) |
FX_Call_EngScript | 32 | Energieänderung durch Scriptaufruf DoEnergy() |
FX_Call_EngBlast | 33 | Energieverlust durch Explosion |
FX_Call_EngObjHit | 34 | Energieverlust durch Objekttreffer |
FX_Call_EngFire | 35 | Energieverlust durch Feuer |
FX_Call_EngBaseRefresh | 36 | Energieaufnahme in der Basis - auch Abgabe und Kauf der Basis, wenn die Basis ein Lebewesen ist |
FX_Call_EngAsphyxiation | 37 | Energieverlust durch Ersticken |
FX_Call_EngCorrosion | 38 | Energieverlust durch Säure |
FX_Call_EngStruct | 39 | Energieverlust von Gebäuden (Nur lebende Gebäude) |
FX_Call_EngGetPunched | 40 | Energieverlust im Clonk-zu-Clonk-Kampf |
Allgemein kann der Ausdruck "cause & 32" verwendet werden, um festzustellen, ob Energie oder Schadenswert verändert wurden.
Über diesen Callback kann zum Beispiel Schaden an einem Objekt verhindert, abgeschwächt oder verstärkt werden; man kann Lebensschaden zunächst nur von der Zauberenergie abziehen, gleichmäßig auf verbundene Clonks verteilen und so weiter.
Funktions-Referenz
Es gibt folgende Funktionen sind zum Manipulieren und Abfragen von Effekten:
- CreateEffect() - zum Erzeugen von Effekten
- RemoveEffect() - zum Entfernen von Effekten
- GetEffect() - zum Suchen nach Effekten
- GetEffectCount() - um Effekte zu zählen
- EffectCall() - für Benutzeraufrufe in Effekten
- CheckEffect() - um Effekt-Callbacks auszuführen, ohne den Effekt selber zu erstellen