Zeige Ergebnis 1 bis 5 von 5
  1. #1
    Sektionsleiter Maps Benutzerbild von WaterKnight
    Registriert seit
    Aug 2003
    BNet Account
    WaterKnight
    Beiträge
    4.420

    [Concepts] Buffs

    Ich weiß zwar mittlerweile, dass auch schon andere was ziemlich Ähnliches erarbeitet haben, aber auf Inwc sah ich bisher dazu nichts. Außerdem bin ich selbst auf den Trichter gekommen und habe somit eigene Vorstellungen miteinfließen lassen. Ich habe zwar auch eine Umsetzung, aber die ist nicht als Library abkapselbar, wie das meiste bei mir. Nutze selber keine unintegrierten Libaries, weil ichs Käse finde. Die müssen oft mit der Map kooperieren, sobald man mal was anderes als 08/15 macht. Und wenn sie für bestimmte Spezialfälle Lösungen anbieten, sind die meist umständlicher und der Code sieht sonstwie aus. Habe mir meinen imho komfortablen eigenen Schreibstil auch schon länger zugelegt. Ich stelle also wieder mal nur Konzept und Pseudocode vor. Letztendlich wollte ich auch mal ausführlicher deskriptiv das Thema anbieten und nicht einfach nur Code hinwerfen, wie es oft praktiziert wird, denn Ersteres sollte auch mal zum Mitdenken anregen, wie die Dinge im Grundsätzlichen funktionieren, und nicht einfach nur stur einen umgesetzten Standard vorlegen.

    Es geht um Buffs. Was sind Buffs? Das sind Objekte, die von Fähigkeiten gesteuert werden. Sie werden auf anderen Objekten abgelegt, überlicherweise Einheiten, um diese für die Fähigkeit/den Code zu indizieren, Daten zu lagern oder auch kosmetische Sachen anzubringen wie das Bufficon in der Statusleiste des Einheitenfensters oder attachte Spezialeffekte. Das Objekt, das die Buffs tragen kann, hat entweder einen bestimmten Buff oder nicht, zweimal geht nicht, obwohl man auch sowas wie Stacks machen könnte.

    Es kam immer mal wieder die Frage auf, warum man Buffs nicht direkt per Trigger zu einer Einheit hinzufügen kann ohne Dummies. Das ist recht wahrscheinlich, weil Buffs wie gesagt nicht nur ihre eigenen Daten aus dem Objekt-Editor anbringen, sondern Fähigkeiten dienen, von ihnen verwaltet werden und für sie Sachen speichern. Das heißt, man müsste den Zauberverstärker über eine Fähigkeit anbringen, Fähigkeiten kann man wieder nicht direkt über Trigger runnen, sondern müssen geordert werden und wenn mans könnte, wären je nach Spell unterschiedliche Sachen von Nöten. Manchmal ist ja sogar die Order/der Castprozess ansich wichtig wie bei Channel-Spells.

    Zumindest, wie ich bereits hier schrieb, triggere ich Fähigkeiten selber und benötigte von den Blizzard-Buffs damit bislang nur das Buff-Icon mit Tooltip in der Statusleiste. Ich sagte auch, dass ich das oft vergaß, weils nicht direkt ausschlaggebend für den Spell war. Ich habe jedoch eine Methode entwickelt, die da Aushilfe schafft und auch für anderes gut ist.

    Ich drehe den Spieß einfach um und ahme die Funktionalitäten von Blizzard-Buffs nach. Die Icons werden nicht mehr unabhängig zu Einheiten hinzugefügt/entfernt, sondern das Hinzufügen/Entfernen von Buffs löst gleichzeitig bestimmte Codeteile der Fähigkeit aus. Blizzard-Spells verpufften auch, wenn man den Buff removte.

    Ein Beispiel:

    Es soll eine Buff-Fähigkeit erstellt werden, die einer Einheit 10% ihres eigenen aktuellen maximalen Lebens zu Angriffsschaden gibt. Die Fähigkeit soll enden, wenn die Einheit stirbt, 15 Sekunden vergangen sind oder die Einheit dispelt wird.

    Für Bufferstellung nutze ich das.

    struct Tantrum
    static constant real DAMAGE_ADD_FACTOR = 0.1
    static Buff DUMMY_BUFF
    static constant real DURATION = 15.
    static Event DEATH_EVENT
    static Event DISPEL_EVENT
    //! runtextmacro GetKey("KEY")
    static Spell THIS_SPELL

    real damageAdd
    Timer durationTimer
    Unit target

    method Ending takes Timer durationTimer, Unit target returns nothing
    local real damageAdd = this.damageAdd

    call durationTimer.Data.Integer.Remove(KEY)
    call durationTimer.Destroy()
    call target.Buffs.Remove(DUMMY_BUFF)
    call target.Data.Integer.Remove(KEY)
    call target.Event.Remove(DEATH_EVENT)
    call target.Event.Remove(DISPEL_EVENT)
    call this.deallocate()

    call target.Damage.Bonus.Subtract(damageAdd)
    endmethod

    static method EndingByTimer takes nothing returns nothing
    local Timer durationTimer = Timer.GetExpired()

    local thistype this = durationTimer.Data.Integer.Get(KEY)

    call this.Ending(durationTimer, this.target)
    endmethod

    static method Event_Death takes nothing returns nothing
    local Unit target = UNIT.Event.GetTrigger()

    local thistype this = target.Data.Integer.Get(KEY)

    call this.Ending(this.durationTimer, target)
    endmethod


    static method Event_Dispel takes nothing returns nothing
    local Unit target = UNIT.Event.GetTrigger()

    local thistype this = target.Data.Integer.Get(KEY)

    call this.Ending(this.durationTimer, target)
    endmethod

    static method Event_SpellEffect takes nothing returns nothing
    local Unit caster = UNIT.Event.GetTrigger()
    local Timer durationTimer = Timer.Create()
    local Unit target = UNIT.Event.GetTarget()

    local real damageAdd = target.MaxLife.GetAll() * DAMAGE_ADD_FACTOR
    local integer level = caster.Abilities.GetLevel(THIS_SPELL)
    local thistype this = target.Data.Integer.Get(KEY)

    if (this != NULL) then
    call this.Ending(this.durationTimer, target)
    endif

    set this = thistype.allocate()

    set this.damageAdd = damageAdd
    set this.durationTimer = durationTimer
    set this.target = target

    call durationTimer.Data.Integer.Set(KEY, this)
    call target.Buffs.Add(DUMMY_BUFF, level)
    call target.Data.Integer.Set(KEY, this)
    call target.Event.Add(DEATH_EVENT)
    call target.Event.Add(DISPEL_EVENT)

    call target.Damage.Bonus.Add(DAMAGE_ADD)

    call durationTimer.Start(DURATION, false, function thistype.EndingByTimer)
    endmethod

    static method Init takes nothing returns nothing
    //! runtextmacro Spell_Create("/", "THIS_SPELL", "ATan", "Tantrum", "NORMAL")

    //! runtextmacro Spell_SetAnimation("/", "spell")
    //! runtextmacro Spell_SetCooldown3("/", "11.", "11.", "11.")
    //! runtextmacro Spell_SetIcon("/", "ReplaceableTextures\\CommandButtons\\BTNBloodLust.blp")
    //! runtextmacro Spell_SetManaCost3("/", "75", "75", "75")
    //! runtextmacro Spell_SetOrder("/", "bloodlust")
    //! runtextmacro Spell_SetRange3("/", "600.", "600.", "600.")
    //! runtextmacro Spell_SetTargets3("/", "ground,notself,organic")
    //! runtextmacro Spell_SetTargetType("/", "UNIT")

    set DEATH_EVENT = Event.Create(UNIT.Damage.Events.DUMMY_EVENT_TYPE, EventPriority.SPELLS, function thistype.Event_Death)
    set DISPEL_EVENT = Event.Create(UNIT.Dispel.Events.DUMMY_EVENT_TYPE, EventPriority.SPELLS, function thistype.Event_Dispel)
    //! runtextmacro Buff_Create("/", "DUMMY_BUFF", 'Tan', "Tantrum", "3", "true", "ReplaceableTextures\\CommandButtons\\BTNBloodLust.blp", "This unit is enraged.")
    call THIS_SPELL.Event.Add(Event.Create(UNIT.Abilities.Events.Effect.DUMMY_EVENT_TYPE, EventPriority.SPELLS, function thistype.Event_SpellEffect))
    endmethod
    endstruct


    So hätte es vorher aussehen können. Man sieht, dass das mit den Event-Funktionen und EndingByTimer, die die Ending-Funktion aufrufen, etwas unglücklich ist. Ich hätte zwar noch eine Zwischenfunktion einbauen können, aber trotzdem hätte man jedesmal einen eigenen Adapter gebraucht. Und Death und Dispel zusammenwerfen in eine Funktion, nur weil sie denselben Aufbau haben, ist auch nicht das Wahre, weil sie grundsätzlich semantisch ja was ganz anderes sind und man eventuell noch was Besonderes bei Dispel einbauen möchte, was bei Death nicht der Fall wäre, wie dass die Einheit 100 Schaden erleidet. Für das Vermindern dieser Adapterfunktionen bietet mein System teilweise eine Lösung, die sind übrigens auch recht fehleranfällig. Schließlich hätte ich im Zuge des Schreibens dieser Fähigkeit auch fast wieder das Bufficon vergessen.

    Nun also, wie es aussähe, würde man das hier beschriebene Konzept anwenden.

    struct Tantrum
    static constant real DAMAGE_ADD_FACTOR = 0.1
    static Buff DUMMY_BUFF
    static constant real DURATION = 15.
    //! runtextmacro GetKey("KEY")
    static Spell THIS_SPELL

    real damageAdd

    static method Event_BuffLose takes nothing returns nothing
    local Unit target = UNIT.Event.GetTrigger()

    local thistype this = target

    local real damageAdd = this.damageAdd

    call target.Damage.Bonus.Subtract(damageAdd)
    endmethod

    static method Event_BuffGain takes nothing returns nothing
    local Unit target = UNIT.Event.GetTrigger()

    local real damageAdd = target.MaxLife.GetAll() * DAMAGE_ADD_FACTOR
    local thistype this = target

    set this.damageAdd = damageAdd

    call target.Damage.Bonus.Add(damageAdd)
    endmethod

    static method Event_SpellEffect takes nothing returns nothing
    local Unit caster = UNIT.Event.GetTrigger()
    local Unit target = UNIT.Event.GetTarget()

    local integer level = caster.Abilities.GetLevel(THIS_SPELL)

    call target.Buffs.Timed.Start(DUMMY_BUFF, level, DURATION)
    endmethod

    static method Init takes nothing returns nothing
    //! runtextmacro Spell_Create("/", "THIS_SPELL", "ATan", "Tantrum", "NORMAL")

    //! runtextmacro Spell_SetAnimation("/", "spell")
    //! runtextmacro Spell_SetCooldown3("/", "11.", "11.", "11.")
    //! runtextmacro Spell_SetIcon("/", "ReplaceableTextures\\CommandButtons\\BTNBloodLust.blp")
    //! runtextmacro Spell_SetManaCost3("/", "75", "75", "75")
    //! runtextmacro Spell_SetOrder("/", "bloodlust")
    //! runtextmacro Spell_SetRange3("/", "600.", "600.", "600.")
    //! runtextmacro Spell_SetTargets3("/", "ground,notself,organic")
    //! runtextmacro Spell_SetTargetType("/", "UNIT")

    //! runtextmacro Buff_Create("/", "DUMMY_BUFF", 'Tan', "Tantrum", "3", "true", "ReplaceableTextures\\CommandButtons\\BTNBloodLust.blp", "This unit is enraged.")
    call DUMMY_BUFF.Event.Add(Event.Create(UNIT.Buffs.Events.Gain.DUMMY_EVENT_TYPE, EventPriority.SPELLS, function thistype.Event_BuffGain))
    call DUMMY_BUFF.Event.Add(Event.Create(UNIT.Buffs.Events.Lose.DUMMY_EVENT_TYPE, EventPriority.SPELLS, function thistype.Event_BuffLose))
    call DUMMY_BUFF.SetLostOnDeath(true)
    call DUMMY_BUFF.SetLostOnDispel(true)
    call THIS_SPELL.Event.Add(Event.Create(UNIT.Abilities.Events.Effect.DUMMY_EVENT_TYPE, EventPriority.SPELLS, function thistype.Event_SpellEffect))
    endmethod
    endstruct


    Hier gibt es nun ein Event BuffGain und Eines BuffLose, die eben entsprechend reagieren, was im Init eingestellt wurde. Die Adapterfunktionen und der Timer sind in diesem Fall komplett weggefallen, weil das alles Standardsachen sind, bei denen Buffs entfernt werden können, da machts also Sinn, das zentral zu steuern, dass Buffs nach einer Zeit ablaufen, bei Dispel hops gehen oder wenn der Träger stirbt. Dazu setze ich die zwei Flags SetLostOnDeath/Dispel auf true, wobei ich OnDeath standardmäßig auf true schalten würde. Wenn also nun eine Einheit stirbt, werden alle ihr attachten Buffs durchgegangen, die bei Tod entfernt werden und das Entfernen wiederum löst dann das spezielle BuffLose-Event aus.

    Ich muss nun nicht mehr extra prüfen, ob die Einheit den Buff vorher schon hatte, weil das im Header gemacht wird. <unit>.Buffs.Timed.Start ersetzt automatisch den vorherigen Buff/runnt BuffLose. Auch würde ich nun den Index für die neue Structinstanz anhand von target bestimmen, wie man sieht, weil in diesem Fall jetzt klar ist, dass es pro gebuffte Einheit nur eine Instanz geben kann. Habe ja oben gesagt, entweder hat eine Einheit einen Buff oder nicht, zweimal geht nicht.

    Eine weitere Möglichkeit wäre gewesen, dass ich noch einen Spezialeffekt dazu hätte machen wollen. Den hätte ich früher in der Structinstanz des Spells mitgespeichert und am Ende gelöscht. Auch das kann ein Buff nun automatisch machen, wenn mans nur im Init angibt.

    Und es stehen noch weitere Dinge offen. Zauberdiebstahl ist möglich oder ich lasse bei DWC Buffs einer Einheit in einem Multiboard anzeigen. Man kann random Buffs hinzufügen oder sonstwas. Nur würde ich bei den genannten Sachen verschiedene Klassen von Buffs einrichten, da nicht unbedingt alles bei allen Buffs gehen soll. Ich erweitere jetzt abschließend auch den Begriff Buff/komme nochmal zurück.

    Buffs (nicht Blizzard-Buffs sondern meine Definition jetzt) sind auf Objekten lagerbare Daten. Sie können einen Blizzard-Buff mit Icon haben, müssen aber nicht. Ich kann also auch versteckte Buffs machen, die einfach nur dazu dienen, die Struktur beizubehalten. Weiterhin habe ich jetzt die ganze Zeit gesagt, sie könnten an Units geheftet werden und helfen bei Spells. Auch das sind keine Notwendigkeiten. Man kann sie beispielsweise auch an Items attachen oder Custom Objekte. Ebenso sind sie nicht zu Fähigkeiten begrenzt. Fähigkeiten sind ja eh nur, was der Mapper daraus macht. Zumindest können Buffs helfen, ein schönes Muster hinzubekommen, Adapterfunktionen können wegfallen, Bufficons werden nicht so leicht vergessen und man kann noch weitere zentrale Steuerungen vornehmen.

    Ich hoffe, es war einigermaßen verständlich.
    Geändert von WaterKnight (19. März 2011 um 16:39 Uhr)
    Water's Footmen Wars
    Defend Wintercastle
    Mana
    God's Ascension (coming soon)
    Dark Colony (coming soon)

    Versunkene Zeiten - Vortex - Wild Scope - Hells Edge -
    Prison Break

  2. #2
    Benutzerbild von Kricz
    Registriert seit
    Apr 2008
    BNet Account
    Kricz
    Beiträge
    1.942
    http://www.wc3c.net/showthread.php?t=95521 ?

    Benutze das System und komme damit ohne Probleme zurecht...

    Zudem bräuchte ich dafür nicht dein mMn seltsames "Framework", mit den ganzen Textmacros usw, die ich eh nicht wirklich verstehe...
    Dota 2
    >> Besucht uns im neuen ingame Portal inDota2! <<

  3. #3
    Gewinner Spellcontest Benutzerbild von Quillraven
    Registriert seit
    Sep 2004
    Ort
    Österreich
    BNet Account
    Quillraven
    Beiträge
    4.446
    soweit ich es verstehe, hat water's system eben den vorteil, dass man nicht im OE herumhantieren muss, sondern dass es, dank der macht der textmakros( ), "automatisch" die abilities mit bildern usw. erstellt.

    man muss sich halt trotzdem die ganzen pfade und kürzel vom OE merken oder nachschauen, weshalb es für mich persönlich jetzt auch nicht wirklich rentabel wäre, aber es lasst halt wesentlich mehr freiheiten zu, als andere systeme.

    benutze btw intutive buff system und das reicht für mich eigentlich aus und ist recht simpel zum benutzen. dennoch solltest du nicht immer water's systeme "schlecht reden" oder anderen "unter stellen", wenn du, wie du selbst sagst, nicht einmal seinen ganzen code verstehst
    Besucht mich auf meinem YouTube Kanal

  4. #4
    Sektionsleiter Maps Benutzerbild von WaterKnight
    Registriert seit
    Aug 2003
    BNet Account
    WaterKnight
    Beiträge
    4.420
    Kricz Antwort war ja auch weitgehend daneben. Eure angesprochenen Systeme sind im ersten Link aufgelistet. Es ging mir auch nicht darum, die zu ersetzen, ich habe hier ja nur Pseudocode gepostet und die Funktionen, die aufgerufen werden, gar nicht deklariert. Ich wollte nur das Ganze mal ausführlicher in Text fassen, wofür das gut ist und außerdem die Idee erweitern, dass mans halt beispielsweise ohne Bufficon und auch auf andere Objekte als Units casten kann.

    Und die Textmacros sind hier überhaupt nicht wichtig, obwohl man damit zeigen kann, wie es im Endeffekt mit meinen anderen Systemen aussehen könnte. Diskussionen zu den Macros kommen hier bzw. da rein. Da kannst du mir dann auch sagen, was du an den Textmacros mit intuitiven Namen und einfacher funktionsweise so unverständlich findest im Gegensatz zu Systemen, die viele verschiedene Funktionen von vJass nutzen und mit mass Identifiern und Abkürzungen aufwarten. Textmacros sind dasselbe wie Module, nur mächtiger.

    Auch kann Dracu mir in den anderen Threads verraten, welche OE-Sachen man sich merken muss. Eigentlich nur, dass Objekte 4-Letter-Ids haben, die Order-Strings, wo ich mir mittlerweile aber schon lange eine Liste rauskopiert habe und man auch einige kennt und bei Targets ists genauso. Die schreibst einmal, dann weißt es (weil mans ja eigentlich auch schon oft gesehen hat) und man kann ja auch in bereits vorhandenen Spells nachschauen. Sollte zumindest schneller sein, als den langsamen Objekt-Editor zu bemühen.
    Geändert von WaterKnight (18. März 2011 um 12:27 Uhr)
    Water's Footmen Wars
    Defend Wintercastle
    Mana
    God's Ascension (coming soon)
    Dark Colony (coming soon)

    Versunkene Zeiten - Vortex - Wild Scope - Hells Edge -
    Prison Break

  5. #5
    Benutzerbild von Kricz
    Registriert seit
    Apr 2008
    BNet Account
    Kricz
    Beiträge
    1.942
    Ich will deine Systeme garnicht "schlecht reden", dass ist keinesfalls meine Absicht! Und ich weiß auch, wie textmacros funzen, bzw das sie mächtiger als Module (wenn auch von der Syntax hässliger mMn) sind, jedoch was ich damit meinte, dass ich Waters Systeme teilweise nicht verstehe sind der immense Gebrauch der Macros um Scopes und Structs zu erzeugen, anstatt einfach zu schreiben 'struct Name', anstelle eines Textmacro aufzurufen.

    Oder ich sehe einfach keinen Nutzen für mich selbst mit seinem System, auch wenn ich es persönlich besser finde, alle Objekte als Klassen zu benutzen.
    Aber sowas

    call caster.Facing.Set(value)
    //anstelle von
    set caster.facing = value


    ist halt mein Hauptproblem mit seinem System, das ist jedoch ein anderes Thema, hatte ich glaub ich schon mal in dem Thread oder woanders erwähnt.
    Dota 2
    >> Besucht uns im neuen ingame Portal inDota2! <<

Ähnliche Themen

  1. [Scripts] [Concepts] Selektive UnitStats-Anpassung
    Von WaterKnight im Forum Material
    Antworten: 0
    Letzter Beitrag: 14. August 2011, 02:38
  2. Buffs und Abilities
    Von ServusTV im Forum Triggerforum
    Antworten: 5
    Letzter Beitrag: 15. März 2011, 14:09
  3. Buffs kaufen
    Von Skasi im Forum Allgemeine Mappingfragen
    Antworten: 8
    Letzter Beitrag: 10. April 2006, 21:47
  4. Blm Buffs
    Von -)GSF(-Maggons im Forum Support-, Coding- & Webdesignforum
    Antworten: 85
    Letzter Beitrag: 23. Oktober 2004, 11:13
  5. Buffs per Trigger?
    Von Aludan im Forum Allgemeine Mappingfragen
    Antworten: 4
    Letzter Beitrag: 16. September 2004, 19:36

Forumregeln

  • Es ist dir nicht erlaubt, neue Themen zu verfassen.
  • Es ist dir nicht erlaubt, auf Beiträge zu antworten.
  • Es ist dir nicht erlaubt, Anhänge hochzuladen.
  • Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
  •