|
-
AOE Damage
Moin Zusammen,
ich wollte mir nun noch ein letztes Feature meiner Modifikation vornehmen. Es geht um eine Art 'AOE Damge'. Also Flächenschaden.
Hat jemand da zufällig schon mal etwas probiert und teilt hier seine bisherigen Erfahrungen? Wo treten Probleme auf? Muss man auf etwas besonderes Achten?
Bin gespannt auf Eure Kommentare.
Beste Grüße
Das Wappen -Eine fantastische Spielwelt erwartet dich- -bis zu 100 Stunden Spielzeit-
-
Eins meiner absoluten Top-Themen, da ich mich viel mit neuen Zaubern beschäftigt habe und dort auch der ein oder andere AOE Zauber am Start ist.
Jetzt gibt es natürlich verschiedene Möglichkeiten Flächenschaden umzusetzen, je nachdem, was dein konkretes Ziel ist. Deshalb hole ich einfach mal etwas aus.
1) Broadcasts
Broadcasts sind klasse. Du rufst damit eine Funktion aus, die für alle Npcs (meistens mit Einschränkung "in der KI-Glocke") aufgerufen wird. Dort kannst du dann lustig Dinge prüfen wie "stehe ich nah genug am hero dran, um Flächenschaden zu kassieren"?
Soeinen Broadcast kann man dann zum Beispiel für Nahkampf/Fernkampf-Flächenschaden in einem damageHook (falls du sowas hast) oder auch in der B_AssessDamage() aufrufen.
Die Broadcasts selber sind von Sektenspinner implementiert worden.
https://forum.worldofplayers.de/foru...1#post17232705
Einsatzweise:
Code:
// Aufruf zum Beispiel in B_AssessDamage()
broadcast(self, broadcastLightningWeaponEnchantmentSplash);
[...]
const int LIGHTNING_WEAPON_ENCHANTMENT_SPLASH_RANGE = 160;
func void broadcastLightningWeaponEnchantmentSplash(var C_NPC me, var C_NPC caster) {
// lustige Prüfungen, damit sich Nahkampf-Flächenschaden auch einigermaßen nativ anfühlt (Gegner sollten im Kampf sein etc.)
if(Npc_GetDistToNpc(me, caster) <= LIGHTNING_WEAPON_ENCHANTMENT_SPLASH_RANGE)
&& (Npc_IsInState(me, ZS_Attack) || Npc_IsInState(me, ZS_MM_Attack)) // sollte im Kampf sein
&& (!me.aivar[AIV_PARTYMEMBER]) { // sollte dazu kein Partymember sein wie z.B. beschworenes Skelett
var int lightningWeaponEnchantmentSplashDamage;
lightningWeaponEnchantmentSplashDamage = lustigeSchadenKalkulierungsfunktionFuerDenZauber();
// hier kann man dem Gegner dann den Schaden hinzufügen
};
};
2) Flächenzauber über die Partikeleffekte
Jetzt haben die Piranhas das Ganze ja auch irgendwie ohne Brotkasten hingekriegt. Nämlich bei den Zaubern (Eiswelle, Todeswelle, ...). Für Zauber kann man sich diese Funktionalitäten auf jeden Fall zu nutze machen. Dafür müssen dann passende Partikeleffekte bereitgestellt werden, die entsprechende Parameter gesetzt haben müssen.
Hier ein beispielhafter Flächenzauber.
VisualFXInst.d
Code:
INSTANCE spellFX_ArcaneExplosion (CFx_Base_Proto)
{
visname_S = "MFX_ENERGYBALL_INIT";
emtrjmode_s = "FIXED";
emTrjOriginNode = "ZS_RIGHTHAND";
emtrjloopmode_s = "NONE";
emtrjeasefunc_s = "LINEAR";
};
INSTANCE spellFX_ArcaneExplosion_KEY_CAST (C_ParticleFXEmitKey)
{
visname_S = "MFX_ENERGYBALL_INIT";
emCreateFXID = "spellFX_ArcaneExplosion_CAST";
pfx_ppsIsLoopingChg = 1;
};
INSTANCE spellFX_ArcaneExplosion_CAST (CFx_Base_Proto)
{
visname_S = "MFX_ArcaneExplosion_Circle";
emTrjOriginNode = "Bip01";
emFXCreate_S = "spellFX_ArcaneExplosion_Sphere";
emFXCreatedOwnTrj = 1;
emFXCollDyn_S = "spellFX_ArcaneExplosion_COLLIDEDYNFX";
emActionCollDyn_S = "CREATEONCE"; // WICHTIG FÜR FLÄCHENZAUBER
emFXCollDynPerc_S = "spellFX_ArcaneExplosion_SENDPERCEPTION"; // WICHTIG FÜR FLÄCHENZAUBER
emFXCollDynAlign_S = "COLLISIONNORMAL"; // WICHTIG FÜR FLÄCHENZAUBER
emCheckCollision = 1; // WICHTIG FÜR FLÄCHENZAUBER
emtrjmode_s = "FIXED";
emtrjoriginnode = "="; // Ausgangspunkt für Pfx (hier: Mitte des Helden)
lightpresetname = "AURA"; // Licht-Preset (leuchtet lustig)
sfxid = "MFX_ArcaneExplosion_Cast"; // Sound
sfxisambient = 1;
emfxlifespan = 1.5; // Zauber hält 1.5 Sekunden
};
INSTANCE spellFX_ArcaneExplosion_COLLIDEDYNFX (CFx_Base_Proto)
{
visname_S = "MFX_ARCANEEXPLOSION_TARGET";
sfxid = "ARCANE_MISSILES_1";
};
INSTANCE spellFX_ArcaneExplosion_SENDPERCEPTION (CFx_Base_Proto) // Send perception
{
visname_S = "";
sendAssessMagic = 1;
};
PFXInstMagic.d
Code:
INSTANCE MFX_ArcaneExplosion_Circle (C_PARTICLEFX)
{
ppsvalue = 200;
ppsscalekeys_s = "3 4 5 6 7 7 8 8"; // Wird mit der Zeit größer
ppsissmooth = 1;
ppsfps = 14; // Wie schnell wird es mit der Zeit größer?
shptype_s = "CIRCLE"; // Hier ist entweder CIRCLE oder SPHERE interessant
shpfor_s = "WORLD";
shpoffsetvec_s = "0 0 0";
shpdistribtype_s = "BOX";
shpdim_s = "120"; // Wirkungsradius
shpscalekeys_s = "1 2 3 4 5 6 6 6"; // Wird mit der Zeit größer #2
shpscaleissmooth = 1;
shpscalefps = 3; // Wie schnell wird es mit der Zeit größer? #2
dirmode_s = "RAND";
dirfor_s = "object";
diranglehead = 90;
dirangleheadvar = 45;
dirangleelev = 90;
dirangleelevvar = 45;
velavg = 0.150000001;
lsppartavg = 500; // Wie viele Millisekunden überlebt ein Partikel (fix)
lsppartvar = 200; // Wie viele Millisekunden überlebt ein Partikel (variabel, wird random auf fix gerechnet)
flygravity_s = "0 0.00003 0"; // Partikel dürfen über die Zeit etwas nach oben fliegen
visname_s = "Kopfball2.TGA";
visorientation_s = "VELO";
vistexisquadpoly = 1;
vistexanifps = 30;
vistexaniislooping = 2;
vistexcolorstart_s = "102 0 204";
vistexcolorend_s = "30 0 60";
vissizestart_s = "8 8"; // Größe der Textur beim Start des Effekts
vissizeendscale = 15; // Größe der Textur beim Ende des Effekts
visalphafunc_s = "ADD";
visalphastart = 255;
trlfadespeed = 0.00999999978;
trltexture_s = "Kopfball2.TGA";
};
Das wäre jetzt ein Beispiel für einen "Wellen-Zauber". Natürlich kriegt man genauso gut ein größeres Projektil damit hin, was durch Gegner hindurchfliegt und jedem Gegner Schaden hinzufügt. Wichtig dabei sind auf jeden Fall die folgenden Parameter im SpellFX_XYZ:
Code:
emactioncollstat_s = "COLLIDE CREATE";
emActionCollDyn_S = "CREATEONCE"; // Erreiche alle
emFXCollDynAlign_S = "COLLISIONNORMAL";
Ein ABER gibt es an dieser Stelle: Flächenzauber haben leider das Problem, dass sie Gegner bei einer einzigen Anwendung häufiger treffen können, wenn zum Beispiel der Effekt etwas länger ist (wie zum Beispiel der Todeswelleneffekt). Hier habe ich eine etwas hackige Lösung bei mir eingebaut, das Problem löst. Dabei setze ich den Initialschaden des Zaubers auf 0 und füge den Schaden erst in der B_AssessMagic() zu. Dann setze ich den Wert einer neuen AIVAR. Falls dieser gesetzt ist, füge ich keinen Schaden mehr hinzu. Der AIVAR wird dann nach einer gewissen Zeit resetted. Mit FrameFunctions aus LeGo geht das ganz gut.
Zusätzlich sind in dem Code auch noch ein paar Tweeks, damit das gegnerische Verhalten auch vernünftig ist/bleibt.
B_AssessMagic.d
Code:
[...]
if (Npc_GetLastHitSpellID(self) == SPL_ArcaneExplosion) {
if(!self.aivar[AIV_WasHitByAOESpell]) { // Hier die erwähnte Klausel, damit nur einmalig Schaden zugefügt wird
self.aivar[AIV_WasHitByAOESpell] = true;
if(mayIAttackHim(self, other)) { // Prüfung, ob Gegner zum Beispiel eingefroren
if (self.guild < GIL_SEPERATOR_HUM) { // Bin ich ein Mensch?
Npc_ClearAIQueue(self);
B_ClearPerceptions(self); // Sonst reagiert der NPC manchmal nicht!
// Das ist wichtig, falls self noch nicht im Kampfmodus (hostile) ist
Npc_SetTarget(self, other);
B_AssessDamage();
};
// Und das ist wichtig, damit self nicht plötzlich aufhört mit dem Kämpfen
Npc_SetTarget(self, other);
Npc_SetTempAttitude(self, ATT_HOSTILE); // Falls nicht schon Gilden-Attitüde hostile ist
};
// Hier füge ich den Schaden zu
};
return;
};
"Aber was ist denn jetzt besser von den beiden Varianten?"
Broadcasts sind super, wenn man konkrete Abfragen für zum Beispiel Distanz machen möchte. So kann man implementieren, dass eine Flammenwelle von nahem mehr Schaden anrichtet, als wenn ein Gegner am äußersten Rand der Welle ist.
Vorteil an der Effekt-Geschichte ist ganz klar, dass man sich keine großen Sorgen um das Treffen machen muss. Das regelt dann der Effekt selber. Es fühlt sich häufig schöner an, wenn der Schaden genau DANN zugefügt wird, wenn der Effekt visuell auch wirklich trifft. Das ist bei broadcasts meistens nur bedingt machbar.
Ich hoffe, das hilft dir erstmal weiter Das Ganze war natürlich nicht ganz uneigennützig, ich habe großes Interesse daran in "Das Wappen" auf tolle Magie zurückzugreifen
-
Zitat von Draxes
Eins meiner absoluten Top-Themen, da ich mich viel mit neuen Zaubern beschäftigt habe und dort auch der ein oder andere AOE Zauber am Start ist.
Jetzt gibt es natürlich verschiedene Möglichkeiten Flächenschaden umzusetzen, je nachdem, was dein konkretes Ziel ist. Deshalb hole ich einfach mal etwas aus.
1) Broadcasts
Broadcasts sind klasse. Du rufst damit eine Funktion aus, die für alle Npcs (meistens mit Einschränkung "in der KI-Glocke") aufgerufen wird. Dort kannst du dann lustig Dinge prüfen wie "stehe ich nah genug am hero dran, um Flächenschaden zu kassieren"?
Soeinen Broadcast kann man dann zum Beispiel für Nahkampf/Fernkampf-Flächenschaden in einem damageHook (falls du sowas hast) oder auch in der B_AssessDamage() aufrufen.
Die Broadcasts selber sind von Sektenspinner implementiert worden.
https://forum.worldofplayers.de/foru...1#post17232705
Einsatzweise:
Code:
// Aufruf zum Beispiel in B_AssessDamage()
broadcast(self, broadcastLightningWeaponEnchantmentSplash);
[...]
const int LIGHTNING_WEAPON_ENCHANTMENT_SPLASH_RANGE = 160;
func void broadcastLightningWeaponEnchantmentSplash(var C_NPC me, var C_NPC caster) {
// lustige Prüfungen, damit sich Nahkampf-Flächenschaden auch einigermaßen nativ anfühlt (Gegner sollten im Kampf sein etc.)
if(Npc_GetDistToNpc(me, caster) <= LIGHTNING_WEAPON_ENCHANTMENT_SPLASH_RANGE)
&& (Npc_IsInState(me, ZS_Attack) || Npc_IsInState(me, ZS_MM_Attack)) // sollte im Kampf sein
&& (!me.aivar[AIV_PARTYMEMBER]) { // sollte dazu kein Partymember sein wie z.B. beschworenes Skelett
var int lightningWeaponEnchantmentSplashDamage;
lightningWeaponEnchantmentSplashDamage = lustigeSchadenKalkulierungsfunktionFuerDenZauber();
// hier kann man dem Gegner dann den Schaden hinzufügen
};
};
2) Flächenzauber über die Partikeleffekte
Jetzt haben die Piranhas das Ganze ja auch irgendwie ohne Brotkasten hingekriegt. Nämlich bei den Zaubern (Eiswelle, Todeswelle, ...). Für Zauber kann man sich diese Funktionalitäten auf jeden Fall zu nutze machen. Dafür müssen dann passende Partikeleffekte bereitgestellt werden, die entsprechende Parameter gesetzt haben müssen.
Hier ein beispielhafter Flächenzauber.
VisualFXInst.d
Code:
INSTANCE spellFX_ArcaneExplosion (CFx_Base_Proto)
{
visname_S = "MFX_ENERGYBALL_INIT";
emtrjmode_s = "FIXED";
emTrjOriginNode = "ZS_RIGHTHAND";
emtrjloopmode_s = "NONE";
emtrjeasefunc_s = "LINEAR";
};
INSTANCE spellFX_ArcaneExplosion_KEY_CAST (C_ParticleFXEmitKey)
{
visname_S = "MFX_ENERGYBALL_INIT";
emCreateFXID = "spellFX_ArcaneExplosion_CAST";
pfx_ppsIsLoopingChg = 1;
};
INSTANCE spellFX_ArcaneExplosion_CAST (CFx_Base_Proto)
{
visname_S = "MFX_ArcaneExplosion_Circle";
emTrjOriginNode = "Bip01";
emFXCreate_S = "spellFX_ArcaneExplosion_Sphere";
emFXCreatedOwnTrj = 1;
emFXCollDyn_S = "spellFX_ArcaneExplosion_COLLIDEDYNFX";
emActionCollDyn_S = "CREATEONCE"; // WICHTIG FÜR FLÄCHENZAUBER
emFXCollDynPerc_S = "spellFX_ArcaneExplosion_SENDPERCEPTION"; // WICHTIG FÜR FLÄCHENZAUBER
emFXCollDynAlign_S = "COLLISIONNORMAL"; // WICHTIG FÜR FLÄCHENZAUBER
emCheckCollision = 1; // WICHTIG FÜR FLÄCHENZAUBER
emtrjmode_s = "FIXED";
emtrjoriginnode = "="; // Ausgangspunkt für Pfx (hier: Mitte des Helden)
lightpresetname = "AURA"; // Licht-Preset (leuchtet lustig)
sfxid = "MFX_ArcaneExplosion_Cast"; // Sound
sfxisambient = 1;
emfxlifespan = 1.5; // Zauber hält 1.5 Sekunden
};
INSTANCE spellFX_ArcaneExplosion_COLLIDEDYNFX (CFx_Base_Proto)
{
visname_S = "MFX_ARCANEEXPLOSION_TARGET";
sfxid = "ARCANE_MISSILES_1";
};
INSTANCE spellFX_ArcaneExplosion_SENDPERCEPTION (CFx_Base_Proto) // Send perception
{
visname_S = "";
sendAssessMagic = 1;
};
PFXInstMagic.d
Code:
INSTANCE MFX_ArcaneExplosion_Circle (C_PARTICLEFX)
{
ppsvalue = 200;
ppsscalekeys_s = "3 4 5 6 7 7 8 8"; // Wird mit der Zeit größer
ppsissmooth = 1;
ppsfps = 14; // Wie schnell wird es mit der Zeit größer?
shptype_s = "CIRCLE"; // Hier ist entweder CIRCLE oder SPHERE interessant
shpfor_s = "WORLD";
shpoffsetvec_s = "0 0 0";
shpdistribtype_s = "BOX";
shpdim_s = "120"; // Wirkungsradius
shpscalekeys_s = "1 2 3 4 5 6 6 6"; // Wird mit der Zeit größer #2
shpscaleissmooth = 1;
shpscalefps = 3; // Wie schnell wird es mit der Zeit größer? #2
dirmode_s = "RAND";
dirfor_s = "object";
diranglehead = 90;
dirangleheadvar = 45;
dirangleelev = 90;
dirangleelevvar = 45;
velavg = 0.150000001;
lsppartavg = 500; // Wie viele Millisekunden überlebt ein Partikel (fix)
lsppartvar = 200; // Wie viele Millisekunden überlebt ein Partikel (variabel, wird random auf fix gerechnet)
flygravity_s = "0 0.00003 0"; // Partikel dürfen über die Zeit etwas nach oben fliegen
visname_s = "Kopfball2.TGA";
visorientation_s = "VELO";
vistexisquadpoly = 1;
vistexanifps = 30;
vistexaniislooping = 2;
vistexcolorstart_s = "102 0 204";
vistexcolorend_s = "30 0 60";
vissizestart_s = "8 8"; // Größe der Textur beim Start des Effekts
vissizeendscale = 15; // Größe der Textur beim Ende des Effekts
visalphafunc_s = "ADD";
visalphastart = 255;
trlfadespeed = 0.00999999978;
trltexture_s = "Kopfball2.TGA";
};
Das wäre jetzt ein Beispiel für einen "Wellen-Zauber". Natürlich kriegt man genauso gut ein größeres Projektil damit hin, was durch Gegner hindurchfliegt und jedem Gegner Schaden hinzufügt. Wichtig dabei sind auf jeden Fall die folgenden Parameter im SpellFX_XYZ:
Code:
emactioncollstat_s = "COLLIDE CREATE";
emActionCollDyn_S = "CREATEONCE"; // Erreiche alle
emFXCollDynAlign_S = "COLLISIONNORMAL";
Ein ABER gibt es an dieser Stelle: Flächenzauber haben leider das Problem, dass sie Gegner bei einer einzigen Anwendung häufiger treffen können, wenn zum Beispiel der Effekt etwas länger ist (wie zum Beispiel der Todeswelleneffekt). Hier habe ich eine etwas hackige Lösung bei mir eingebaut, das Problem löst. Dabei setze ich den Initialschaden des Zaubers auf 0 und füge den Schaden erst in der B_AssessMagic() zu. Dann setze ich den Wert einer neuen AIVAR. Falls dieser gesetzt ist, füge ich keinen Schaden mehr hinzu. Der AIVAR wird dann nach einer gewissen Zeit resetted. Mit FrameFunctions aus LeGo geht das ganz gut.
Zusätzlich sind in dem Code auch noch ein paar Tweeks, damit das gegnerische Verhalten auch vernünftig ist/bleibt.
B_AssessMagic.d
Code:
[...]
if (Npc_GetLastHitSpellID(self) == SPL_ArcaneExplosion) {
if(!self.aivar[AIV_WasHitByAOESpell]) { // Hier die erwähnte Klausel, damit nur einmalig Schaden zugefügt wird
self.aivar[AIV_WasHitByAOESpell] = true;
if(mayIAttackHim(self, other)) { // Prüfung, ob Gegner zum Beispiel eingefroren
if (self.guild < GIL_SEPERATOR_HUM) { // Bin ich ein Mensch?
Npc_ClearAIQueue(self);
B_ClearPerceptions(self); // Sonst reagiert der NPC manchmal nicht!
// Das ist wichtig, falls self noch nicht im Kampfmodus (hostile) ist
Npc_SetTarget(self, other);
B_AssessDamage();
};
// Und das ist wichtig, damit self nicht plötzlich aufhört mit dem Kämpfen
Npc_SetTarget(self, other);
Npc_SetTempAttitude(self, ATT_HOSTILE); // Falls nicht schon Gilden-Attitüde hostile ist
};
// Hier füge ich den Schaden zu
};
return;
};
"Aber was ist denn jetzt besser von den beiden Varianten?"
Broadcasts sind super, wenn man konkrete Abfragen für zum Beispiel Distanz machen möchte. So kann man implementieren, dass eine Flammenwelle von nahem mehr Schaden anrichtet, als wenn ein Gegner am äußersten Rand der Welle ist.
Vorteil an der Effekt-Geschichte ist ganz klar, dass man sich keine großen Sorgen um das Treffen machen muss. Das regelt dann der Effekt selber. Es fühlt sich häufig schöner an, wenn der Schaden genau DANN zugefügt wird, wenn der Effekt visuell auch wirklich trifft. Das ist bei broadcasts meistens nur bedingt machbar.
Ich hoffe, das hilft dir erstmal weiter Das Ganze war natürlich nicht ganz uneigennützig, ich habe großes Interesse daran in "Das Wappen" auf tolle Magie zurückzugreifen
Hi Draxes,
danke für die von dir zur Verfügung gestellten Informationen. Ich werde mir das genauer angucken
Das Wappen -Eine fantastische Spielwelt erwartet dich- -bis zu 100 Stunden Spielzeit-
-
So, habe mich jetzt mal mit deinem Post auseinander gesetzt.
Problem für mich:
Der Gegner wird überall in Range getroffen (auch hinter dem Helden). Ich würde gerne im Nahkampfbereich abfragen wollen ob Npc XY von meiner Waffe getroffen wurde.
Ich glaube man müsste hierzu abfragen ob die Waffe die in der ZS_RightHand getragen wird mit dem NPC kollidiert. Gibt es dafür ne Lösung?
Das Wappen -Eine fantastische Spielwelt erwartet dich- -bis zu 100 Stunden Spielzeit-
-
Zitat von aebo
So, habe mich jetzt mal mit deinem Post auseinander gesetzt.
Problem für mich:
Der Gegner wird überall in Range getroffen (auch hinter dem Helden). Ich würde gerne im Nahkampfbereich abfragen wollen ob Npc XY von meiner Waffe getroffen wurde.
Ich glaube man müsste hierzu abfragen ob die Waffe die in der ZS_RightHand getragen wird mit dem NPC kollidiert. Gibt es dafür ne Lösung?
Argh, ich habe vergessen dir zurückzuschreiben Das wird jetzt nachgeholt.
So spontan fällt mir da keine konkrete Lösung ein. Das wäre auch ein komplizierter Ansatz. Aber ich habe Alternativvorschläge, die dir vermutlich reichen könnten.
1) Du prüfst in dem Broadcast nicht die Distanz vom Helden zu potentiellen Gegnern, die du triffst, sondern von dem Gegner, den du mit deinem "normalen" Angriff getroffen hast zu den potentiellen Gegnern. Da dieser auf jeden Fall getroffene Gegner vor dir steht sollten mit der richtigen Distanz keine Gegner hinter dir getroffen werden.
2) Du prüfst mit
Code:
Npc_CanSeeNpc(hero, me)
ob du den Gegner siehst bzw. ob der Gegner dich sieht.
-
Zitat von aebo
So, habe mich jetzt mal mit deinem Post auseinander gesetzt.
Problem für mich:
Der Gegner wird überall in Range getroffen (auch hinter dem Helden). Ich würde gerne im Nahkampfbereich abfragen wollen ob Npc XY von meiner Waffe getroffen wurde.
Ich glaube man müsste hierzu abfragen ob die Waffe die in der ZS_RightHand getragen wird mit dem NPC kollidiert. Gibt es dafür ne Lösung?
Inwiefern ist es dann noch Flächenschaden? Wie soll es sich von herkömmlichem Schaden unterscheiden?
-
Zitat von Milky-Way
Inwiefern ist es dann noch Flächenschaden? Wie soll es sich von herkömmlichem Schaden unterscheiden?
Ich glaube fast hier handelt es sich um eine Verwechslung? Ich denke Aebo möchte gern Schaden wie in G3 (mit dem Schwert nach vorn schlagen und ggf. 2/mehrere Gegner treffen) und nicht Flächenschaden im Sinne von Zaubern.?
-
Zitat von Fisk2033
Ich glaube fast hier handelt es sich um eine Verwechslung? Ich denke Aebo möchte gern Schaden wie in G3 (mit dem Schwert nach vorn schlagen und ggf. 2/mehrere Gegner treffen) und nicht Flächenschaden im Sinne von Zaubern.?
Du triffst den Nagel auf den Kopf
Ich befürchte aber, dass es nur mit diesem Trick (einen "Zauber") gehen wird, dieses umzusetzten. Bin aber auch noch nicht so 100% von der Lösung überzeugt.
Ich habe mal einen Post hier von Thanduriel aus dem Jahre 2014 gefunden. Hier der Post
Code:
For a clean solution you need to hook melee attacks. This functions could work(just guessed from their names):
oCNpc::EV_AttackForward(oCMsgAttack *) 0x0074F400
oCNpc::EV_AttackLeft(oCMsgAttack *) 0x00750160
oCNpc::EV_AttackRight(oCMsgAttack *) 0x00750D00
oCNpc::EV_AttackRun(oCMsgAttack *) 0x007517D0
oCNpc::EV_AttackFinish(oCMsgAttack *) 0x00751AF0
In the hook you can use broadcasts to get other near targets. On those you can either try out some enginefunctions or build your own attack with rangecalculations, dmg and animations.
Leider weiß ich damit nicht wirklich viel anzufangen.
Ich habe bereits ja einen Damage-Hook eingerichtet, weil ich ja sowieso eine eigene Schadensberechnung inplementiert habe.
Das Wappen -Eine fantastische Spielwelt erwartet dich- -bis zu 100 Stunden Spielzeit-
-
Wenn du schon einen damage hook hast, könntest du dort einen broadcast starten um weitere Ziele zu ermitteln. Wie schon vorgeschlagen mit Abstand eines NPCs zu dem NPC welcher geschädigt wurde. Und dann evt. auch Sichtcheck vom hero aus:
Lustige skizze:
[Bild: attachment.php?s=37c5b69bb768df5fcb015812b6e4ca79&attachmentid=47397&d=1540467753&thumb=1]
Wenn du Wolf 1 mit einem Schwert schlägst, könntest du dann feststellen das Wolf 2 nah genug ist das er auch Schaden abbekommen soll.
Du kannst zum testen ja erst mal mit B_MagicHurtNpc Schaden verteilen und dann Schauen ob/wie du das noch verschönern kannst.
-
Oder pfx an jede Waffe hängen und dann schaffen darüber verteilen
-
Zitat von Cryp18Struct
Wenn du schon einen damage hook hast, könntest du dort einen broadcast starten um weitere Ziele zu ermitteln. Wie schon vorgeschlagen mit Abstand eines NPCs zu dem NPC welcher geschädigt wurde. Und dann evt. auch Sichtcheck vom hero aus:
Lustige skizze:
[Bild: attachment.php?s=37c5b69bb768df5fcb015812b6e4ca79&attachmentid=47397&d=1540467753&thumb=1]
Wenn du Wolf 1 mit einem Schwert schlägst, könntest du dann feststellen das Wolf 2 nah genug ist das er auch Schaden abbekommen soll.
Du kannst zum testen ja erst mal mit B_MagicHurtNpc Schaden verteilen und dann Schauen ob/wie du das noch verschönern kannst.
Ja, das wäre eine Option. Aber relativ aufwändig. Wüsste da gar nicht wo ich anfangen sollte :-D
Zitat von Milky-Way
Oder pfx an jede Waffe hängen und dann schaffen darüber verteilen
Das klingt doch sehr gut. Pfx kann man ja auch dann für den Spieler nicht sichtbar machen. Wie könnte das aussehen?
Hast du nen Vorschlag?
Das Wappen -Eine fantastische Spielwelt erwartet dich- -bis zu 100 Stunden Spielzeit-
-
Ich versuch jetzt doch dir die broadcast Lösung aufzuschwatzen, weil man da doch recht schnell ein funktionierendes Grundgerüst bauen kann.
Im damage hook(https://forum.worldofplayers.de/foru...1#post19002341)
ganz unten:
Code:
if(dmg > 0){
if(Hlp_GetInstanceID(attackerNpc) == Hlp_GetInstanceID(hero)){
if(Npc_HasReadiedMeleeWeapon(attackerNpc)){ // wäre besser im oSDamageDescriptor nachzuschauen wie Schaden zugefügt wurde
broadcastEx(victimNpc, doAOEDamage, 1, 0, 0); // exclude caster:1, includeDead:0, includeShrinked:0
};
};
};
return dmg;
}; // Ende von DMG_OnDmg()
Und dann die Funktion die von broadcast für alle NPCs aufgerufen wird:
Code:
func void doAOEDamage(var c_npc me, var c_npc caster){
if(Npc_GetDistToNpc(me, caster) > 150){return;};
if(Npc_GetDistToNpc(me, hero) > 250){return;}; // Distanzwerte jetzt nur PI * Daumen, man könnte auch Waffenreichweite berücksichtigen
if(!Npc_CanSeeNpc(hero, me)){return;};
var int dam;
dam = 1000; // Schadenswert kann auch beliebig anders berechnet werden, Waffenschaden - Rüstungsschutz oder so, Grundschaden könnte man auch im damage hook vorbereiten und über globale variable hierher reichen
dam = dam - me.protection[DAM_INDEX_MAGIC];
if(dam < 1){return;};
MEM_PushInstParam(hero);
MEM_PushInstParam(me);
MEM_PushIntParam(dam);
MEM_Call(B_MagicHurtNPC);
};
Berechtigungen
- Neue Themen erstellen: Nein
- Themen beantworten: Nein
- Anhänge hochladen: Nein
- Beiträge bearbeiten: Nein
|
|