• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[vJASS] [System] Incinerate (Damage Stacking)

AGD

AGD

Level 16
Joined
Mar 29, 2016
Messages
688
Incinerate v1.0b


System Description:
This system allows you to add an Incinerate (the buggy Firelord ability made by Blizzard) ability to a unit. This system is a remake and a vJass version of my spell Triggered Incinerate v1.2. But unlike, the mentioned spell, this system does not oblige you give the unit an actual "ability" and therefore, is more flexible and gives the users more freedom.

System Information:
- Only damage coming from same incinerate instance can stack on each other
- An incinerate instance can have as many units registered into it
- A unit can be under the effect of any number of incinerate instances
- A unit can be registered into any number of incinerate instances
- When a unit dies, the system will iterate all incinerate instances affecting the unit then it will perform their effects for explosion/incineration

Bugs and Issues:
- When two or more incinerate (even from same incinerate instance) explosions affect the same unit at the same time, the damage dealt is somehow negated/nullified if the attacktype is set to ATTACK_TYPE_NORMAL (aka Spell damage). This is probably a problem regarding the damage system.

Read the documentation for more information and a demo map is also available below.


System Script:
JASS:
library Incinerate /* v1.0b


    */requires /*

    */DamageEvent                       /*  http://www.hiveworkshop.com/threads/system-physical-damage-detection.228456/
    */Table                             /*  http://www.hiveworkshop.com/threads/snippet-new-table.188084/
    */UnitDex                           /*  http://www.hiveworkshop.com/threads/system-unitdex-unit-indexer.248209/
    */TimerUtils                        /*  http://www.wc3c.net/showthread.php?t=101322
    */optional ResourcePreloader        /*  http://www.hiveworkshop.com/threads/snippet-resource-preloader.287358/
    */optional RegisterPlayerUnitEvent  /*  http://www.hiveworkshop.com/threads/snippet-registerevent-pack.250266/
    */optional GroupUtils               /*  http://www.wc3c.net/showthread.php?t=104464

    [Resource Link]  -  http://www.hiveworkshop.com/threads/system-incinerate-damage-stacking.290046/


    Description:

    This system is an attempt to remake the Firelord's Incinerate spell made by Blizzard.
    This was designed to solve the bugs in that spell namely, the object data of the
    original Incinerate overriding the data of any custom ability made from it, which as
    a result, you can't many Incinerate based abilities without having trouble configuring
    their data.

    With this system, you can create as many type of Incinerates, all with different stats
    and effects. This system does not also obligue to use an ability but instead, you
    can instantly allocate Incinerate for a certain unit (You will probably do it when a
    unit mets the condition you've specified such as having a certain item, reaching a
    certain level, etc.).

    *///! novjass

    |=========|
    | CREDITS |
    |=========|
    /*
        - AGD (Author)
        - Looking_For_Help, TriggerHappy, Vexorian, Bannar, Rising_Dusk (For the dependencies)
        - Aniki (For pointing out some flaws in the system)
    */
    |-----|
    | API |
    |-----|

        struct Incinerate

            boolean spellAsTrigger          /* Determines if spell damage can trigger incinerate */
            boolean incinerateAsTrigger     /* Determines if damage from an incinerate explosion can trigger incinerate */
            real stackingDamage             /* Damage increment per attack */
            real duration                   /* Duration of the incinerate */
            real damageCap                  /* Maximum value for damage stacking (Zero value means no limit) */
            real exMainAoe                  /* Full damage radius of explosion */
            real exSecondaryAoe             /* Small damage radius of explosion */
            real exSmallDamageFactor        /* Small damage factor of explosion */
            attacktype attackType           /* Attack-type of the Incinerate */
            damagetype damageType           /* Damage-type of the Incinerate */
            weapontype weaponType           /* Weapon-type of the Incinerate */
            string damageStackEffect        /* Special effect model attached to units that have been stacked upon with incinerate damage */
            string explosionEffect          /* Special effect model for the incinerate explosion */
            string effectAttachPoint        /* Special effect attachment point for <damageStackEffect> */
            boolean allyFilter              /* Determines if the Incinerate works on allies */
            boolean structureFilter         /* Determines if the Incinerate works on structures */
            boolean mechanicalFilter        /* Determines if the Incinerate works on mechanical */
            boolean magicImmuneFilter       /* Determines if the Incinerate works on magic-immunes */
            boolean illusionFilter          /* Determines if the Incinerate works on illusions */

            /* Event Responses */
            readonly static Incinerate exploded   /* The Incinerate instance that exploded */
            readonly static unit explodingUnit    /* The exploding unit */
            readonly static unit explosionSource  /* The unit who stacked the incinerate upon the explodedUnit */
            readonly static unit triggerUnit      /* The unit who landed the final blow upon the explodedUnit */

            static method create takes nothing returns Incinerate/*
                - Allocates a new Incinerate instance initialized with the default
                  values specified in the configuration

          */method destroy takes nothing returns nothing/*
                - Destroys an Incinerate instance

          */method register takes unit u returns Incinerate/*
                - Adds this Incinerate instance to the specified unit

          */method unregister takes unit u returns Incinerate/*
                - Removes this Incinerate instance from the specified unit

          */static method addExplosionHandler takes code c returns triggercondition/*
                - Registers a code to run upon an incinerate explosion event

          */static method removeExplosionHandler takes triggercondition tc returns nothing/*
                - Unregisters a triggercondition from the incinerate explosion event

    *///! endnovjass

    /*==============================================*/
    /*    Default Incinerate Stats Configuration    */
    /*----------------------------------------------*/
    /* A newly allocated Incinerate instance's data */
    /*     will be initialized to these values      */
    /*==============================================*/
    private module InitDefaultIncinerate
        set .spellAsTrigger = false
        set .incinerateAsTrigger = false
        set .stackingDamage = 10.00
        set .duration = 10.00
        set .damageCap = 500.00
        set .exMainAoe = 175.00
        set .exSecondaryAoe = 250.00
        set .exSmallDamageFactor = 0.60
        set .attackType = ATTACK_TYPE_HERO
        set .damageType = DAMAGE_TYPE_MAGIC
        set .weaponType = null
        set .damageStackEffect = "Abilities\\Spells\\Other\\Incinerate\\IncinerateBuff.mdl"
        set .explosionEffect = "Abilities\\Spells\\Other\\Incinerate\\FireLordDeathExplode.mdl"
        set .effectAttachPoint = "chest"
        set .allyFilter = true
        set .structureFilter = false
        set .mechanicalFilter = false
        set .magicImmuneFilter = false
        set .illusionFilter = true
    endmodule
    /*==============================================*/
    /*    End of Default Incinerate Configuration   */
    /*==============================================*/

    /*========================================================================*/
    native UnitAlive takes unit u returns boolean

    struct Incinerate

        static if not LIBRARY_GroupUtils then
            private static group ENUM_GROUP = CreateGroup()
        endif

        readonly static thistype exploded = 0
        readonly static unit explodingUnit = null
        readonly static unit explosionSource = null
        readonly static unit triggerUnit = null
        private static trigger trig = CreateTrigger()
        private static trigger eventHandler = CreateTrigger()
        private static unit tempUnit
        private static boolean explosion = false
        private static Table index
        private TableArray table
        private thistype prev
        private thistype next
        private group group
        private string sfxModel1
        private string sfxModel2
        boolean spellAsTrigger
        boolean incinerateAsTrigger
        real stackingDamage
        real duration
        real damageCap
        real exMainAoe
        real exSecondaryAoe
        real exSmallDamageFactor
        attacktype attackType
        damagetype damageType
        weapontype weaponType
        string effectAttachPoint
        boolean allyFilter
        boolean structureFilter
        boolean mechanicalFilter
        boolean magicImmuneFilter
        boolean illusionFilter

        method operator damageStackEffect= takes string model returns nothing
            set .sfxModel1 = model
            static if LIBRARY_ResourcePreloader then
                call PreloadEffect(model)
            endif
        endmethod

        method operator damageStackEffect takes nothing returns string
            return .sfxModel1
        endmethod

        method operator explosionEffect= takes string model returns nothing
            set .sfxModel2 = model
            static if LIBRARY_ResourcePreloader then
                call PreloadEffect(model)
            endif
        endmethod

        method operator explosionEffect takes nothing returns string
            return .sfxModel2
        endmethod

        static method create takes nothing returns thistype
            local thistype this = allocate()
            set .next = 0
            set .prev = thistype(0).prev
            set thistype(0).prev.next = this
            set thistype(0).prev = this
            set .table = TableArray[0x2000]
            set .group = CreateGroup()
            implement optional InitDefaultIncinerate
            return this
        endmethod

        method destroy takes nothing returns nothing
            call .deallocate()
            call .table.flush()
            call DestroyGroup(.group)
            set .next.prev = .prev
            set .prev.next = .next
            set .spellAsTrigger = false
            set .stackingDamage = 0
            set .duration = 0
            set .damageCap = 0
            set .exMainAoe = 0
            set .exSecondaryAoe = 0
            set .exSmallDamageFactor = 0
            set .attackType = null
            set .damageType = null
            set .weaponType = null
            set .sfxModel1 = null
            set .sfxModel2 = null
            set .effectAttachPoint = null
            set .allyFilter = false
            set .structureFilter = false
            set .mechanicalFilter = false
            set .magicImmuneFilter = false
            set .illusionFilter = false
        endmethod

        method register takes unit u returns thistype
            call GroupAddUnit(.group, u)
            return this
        endmethod

        method unregister takes unit u returns thistype
            call GroupRemoveUnit(.group, u)
            return this
        endmethod

        static method addExplosionHandler takes code c returns triggercondition
            return TriggerAddCondition(eventHandler, Filter(c))
            return null
        endmethod

        static method removeExplosionHandler takes triggercondition tc returns nothing
            call TriggerRemoveCondition(eventHandler, tc)
        endmethod

        private method filter takes unit target, unit source returns boolean
            return (UnitAlive(target)) and/*
                */ (target != source) and/*
                */ (IsUnitEnemy(target, GetOwningPlayer(source)) or .allyFilter) and/*
                */ (not IsUnitType(target, UNIT_TYPE_STRUCTURE) or .structureFilter) and/*
                */ (not IsUnitType(target, UNIT_TYPE_MECHANICAL) or .mechanicalFilter) and/*
                */ (not IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE) or .magicImmuneFilter) and/*
                */ (not IsUnitIllusion(target) or .illusionFilter)
        endmethod

        private static method debuff takes nothing returns nothing
            local timer t       = GetExpiredTimer()
            local integer id    = GetTimerData(t)
            local thistype this = index[GetHandleId(t)]
            local Table tb      = .table[id]
            call DestroyEffect(tb.effect[5])
            call ReleaseTimer(t)
            call tb.flush()
            set t = null
        endmethod

        private static method onDeath takes nothing returns nothing
            local unit killer    = GetKillingUnit()
            local unit dying     = GetTriggerUnit()
            local real x         = GetUnitX(dying)
            local real y         = GetUnitY(dying)
            local integer id     = GetUnitId(dying)
            local thistype this  = 0
            local boolean b
            local attacktype at
            local damagetype dt
            local weapontype wt
            local unit buffSource
            local unit target
            local real dx
            local real dy
            local real damage
            local real radius
            local real damageFactor
            local Table tb
            loop
                set this = .next
                exitwhen this == 0
                set tb = .table[id]
                if tb.boolean[7] then
                    set b = .incinerateAsTrigger
                    set at = .attackType
                    set dt = .damageType
                    set wt = .weaponType
                    set damage = tb.real[1]
                    set radius = tb.real[2]
                    set damageFactor = tb.real[4]
                    set buffSource = tb.unit[8]
                    call DestroyEffect(tb.effect[5])
                    call DestroyEffect(AddSpecialEffect(.explosionEffect, x, y))
                    call GroupEnumUnitsInRange(ENUM_GROUP, x, y, tb.real[3], null)
                    loop
                        set target = FirstOfGroup(ENUM_GROUP)
                        exitwhen target == null
                        call GroupRemoveUnit(ENUM_GROUP, target)
                        if .filter(target, buffSource) then
                            set dx = GetUnitX(target) - x
                            set dy = GetUnitY(target) - y
                            set explosion = b
                            if (dx*dx + dy*dy > radius*radius and UnitDamageTarget(buffSource, target, damage*damageFactor, true, false, at, dt, wt)) or UnitDamageTarget(buffSource, target, damage, true, false, at, dt, wt) then
                            endif
                            set explosion = false
                        endif
                    endloop
                    call ReleaseTimer(tb.timer[6])
                    call tb.flush()
                    /* Run inicneration handler */
                    set triggerUnit = buffSource
                    set explosionSource = killer
                    set explodingUnit = dying
                    set exploded = this
                    call TriggerEvaluate(eventHandler)
                    set triggerUnit = null
                    set explosionSource = null
                    set explodingUnit = null
                    set exploded = 0
                endif
            endloop
            set buffSource = null
            set killer = null
            set dying = null
        endmethod

        private static method onDamage takes nothing returns nothing
            local integer id     = GetUnitId(PDDS.target)
            local thistype this  = 0
            local timer t
            local real dcap
            local Table tb
            loop
                set this = .next
                exitwhen this == 0
                if (IsUnitInGroup(PDDS.source, .group)) and (not explosion) and (PDDS.damageType != CODE) and ((PDDS.damageType != SPELL) or .spellAsTrigger) then
                    set dcap = .damageCap
                    if .filter(PDDS.target, PDDS.source) then
                        set tb = .table[id]
                        set t = tb.timer[6]
                        if t == null then
                            set t = NewTimer()
                        endif
                        call SetTimerData(t, id)
                        set index.integer[GetHandleId(t)] = this
                        set tb.real[1] = tb.real[1] + .stackingDamage
                        set tb.real[2] = .exMainAoe
                        set tb.real[3] = .exSecondaryAoe
                        set tb.real[4] = .exSmallDamageFactor
                        set tb.timer[6] = t
                        set tb.boolean[7] = true
                        set tb.unit[8] = PDDS.source
                        if not tb.effect.has(5) then
                            set tb.effect[5] = AddSpecialEffectTarget(.damageStackEffect, PDDS.target, .effectAttachPoint)
                        endif
                        if dcap > 0.00 and tb.real[1] > dcap then
                            set tb.real[1] = dcap
                        endif
                        set PDDS.amount = 0.00
                        call UnitDamageTargetEx(PDDS.source, PDDS.target, PDDS.amount + tb.real[1], true, false, .attackType, .damageType, .weaponType)
                        call TimerStart(t, .duration, false, function thistype.debuff)
                    endif
                endif
            endloop
            set t = null
        endmethod

        private static method onInit takes nothing returns nothing
            static if RPUE_VERSION_NEW then
                call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function thistype.onDeath)
            elseif LIBRARY_RegisterPlayerUnitEvent then
                call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function thistype.onDeath)
            else
                local code c = function thistype.onDeath
                local trigger t = CreateTrigger()
                call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
                call TriggerAddCondition(t, Filter(c))
            endif
            call AddDamageHandler(function thistype.onDamage)
            set index = Table.create()
        endmethod

    endstruct


endlibrary



JASS:
library TestLibrary requires UnitDex, Incinerate


    private struct Init extends array

        private static constant real CREEP_RESPAWN_TIME = 30.00
        private static constant real HERO_RESPAWN_TIME = 2.00
        private static constant integer CAMP_COUNT = 15
        private static constant integer CREEP_COUNT = 20
        private static constant real CAMP_OFFSET = 1300.00

        private static real array originalX
        private static real array originalY
        private static real array originalFacing

        private static Incinerate furySwipe

        private static method respawn takes nothing returns nothing
            local unit u = GetTriggerUnit()
            local integer i = GetUnitId(u)
            local real x = originalX[i]
            local real y = originalY[i]
            call TriggerSleepAction(HERO_RESPAWN_TIME)
            if not ReviveHero(u, x, y, false) then
                call TriggerSleepAction(CREEP_RESPAWN_TIME - HERO_RESPAWN_TIME)
                call CreateUnit(GetTriggerPlayer(), GetUnitTypeId(u), x, y, originalFacing[i])
                call RemoveUnit(u)
            endif
            set u = null
        endmethod

        private static method levelUp takes nothing returns nothing
            local unit u = GetTriggerUnit()
            if IsUnitType(u, UNIT_TYPE_HERO) and IsUnitAlly( u, GetTriggerPlayer()) then
                call SetHeroLevel(u, (GetHeroLevel(u) + 1), true)
            endif
            set u = null
        endmethod

        private static method setup takes nothing returns nothing

            local player p = Player(1)
            local integer i = 360/CAMP_COUNT
            local real x
            local real y
            local integer a
            local real facing
            local integer index = 16

            local trigger t1 = CreateTrigger()
            local trigger t2 = CreateTrigger()

            call FogEnable(false)
            call FogMaskEnable(false)
            call PanCameraToTimed(0, 0, 0.00)
            call SetHeroLevel(CreateUnit(Player(0), 'H000', -200, 0, 270), 10, false)
            call SetHeroLevel(CreateUnit(Player(0), 'H001', 200, 0, 270), 10, false)
            call SetPlayerState(p, PLAYER_STATE_GIVES_BOUNTY, 1)

            loop

                exitwhen i > 360
                set i = i + (360/CAMP_COUNT)
                set x = CAMP_OFFSET*Cos(i*bj_DEGTORAD)
                set y = CAMP_OFFSET*Sin(i*bj_DEGTORAD)
                set facing = bj_RADTODEG*Atan2(-y, -x)

                set a = 0
                loop
                    set a = a + 1
                    call CreateUnit(p, 'hpea', x, y, facing)
                    exitwhen a == CREEP_COUNT
                endloop

            endloop

            loop
                set index = index - 1
                call TriggerRegisterPlayerUnitEvent(t1, Player(index), EVENT_PLAYER_UNIT_DEATH, null)
                call TriggerRegisterPlayerUnitEvent(t2, Player(index), EVENT_PLAYER_UNIT_SELECTED, null)
                exitwhen index == 0
            endloop

            call TriggerAddAction(t1, function thistype.respawn)
            call TriggerAddAction(t2, function thistype.levelUp)

        endmethod

        private static method register takes nothing returns nothing
            local unit u = GetIndexedUnit()
            local integer id = GetUnitTypeId(u)

            // If the entering unit is Firelord, give it the default Incinerate ability
            if id == 'H000' then
                call Incinerate.create().register(u)

            // If the entering unit is Ursa, give it a Fury Swipe-like ability similar to that in DotA
            elseif id == 'H001' then
                set furySwipe = Incinerate.create().register(u)
                set furySwipe.stackingDamage = 25.00
                set furySwipe.duration = 12.00
                set furySwipe.damageCap = 0.00
                set furySwipe.exMainAoe = 0.00
                set furySwipe.exSecondaryAoe = 0.00
                set furySwipe.exSmallDamageFactor = 0.00
                set furySwipe.attackType = ATTACK_TYPE_HERO
                set furySwipe.damageType = DAMAGE_TYPE_NORMAL
                set furySwipe.damageStackEffect = "Abilities\\Spells\\NightElf\\BattleRoar\\RoarTarget.mdl"
                set furySwipe.explosionEffect = "Objects\\Spawnmodels\\Undead\\UndeadBlood\\UndeadBloodNecromancer.mdl"
                set furySwipe.effectAttachPoint = "overhead"
            endif

            set originalX[GetIndexedUnitId()] = GetUnitX(u)
            set originalY[GetIndexedUnitId()] = GetUnitY(u)
            set originalFacing[GetIndexedUnitId()] = GetUnitFacing(u)
            set u = null
        endmethod

        private static method onDamage takes nothing returns nothing
            local string targetName
            if PDDS.amount != 0 then
                if IsUnitType(PDDS.target, UNIT_TYPE_HERO) then
                    set targetName = GetHeroProperName(PDDS.target)
                else
                    set targetName = GetUnitName(PDDS.target)
                endif
                call BJDebugMsg(GetHeroProperName(PDDS.source) + " dealt " + I2S(R2I(PDDS.amount)) + " damage to " + targetName + ".")
            endif
        endmethod

        // Play a undead dissipate special effect when a dying unit is under the effect of fury swipe
        private static method onExplode takes nothing returns nothing
            if Incinerate.exploded == furySwipe then
                call DestroyEffect(AddSpecialEffect("Objects\\Spawnmodels\\Undead\\UndeadDissipate\\UndeadDissipate.mdl", GetUnitX(Incinerate.explodingUnit), GetUnitY(Incinerate.explodingUnit)))
            endif
        endmethod

        private static method onInit takes nothing returns nothing
            call AddDamageHandler(function thistype.onDamage)
            call Incinerate.addExplosionHandler(function thistype.onExplode)
            call OnUnitIndex(function thistype.register)
            call thistype.setup()
        endmethod

    endstruct


endlibrary



v1.0b
- You can now add as many incinerates to a unit, unlike the previous version where the system allocates 1 incinerate per unit
- Added an incinerate explosion event handler and its event responses together with its api for the users
- On the onDamage method, instead of directly changing the PDDS.amount, it now uses UnitDamageTargetEx()
- The damage stacking special effect is now created once the effect is null instead of destroying and recreating per damage stacking
- Added a sample usage script
- Some code optimization and changes

v1.0
- First Release
 

Attachments

  • Incinerate v1.0b.w3x
    94.5 KB · Views: 125
Last edited:
Level 13
Joined
Nov 7, 2014
Messages
571
That's funny... I am afraid you made the ability too MUI =).

I think the Incinerate ability (ANia) works something like this:
Code:
When a unit gets hit by the ability (and passing the allowed targets check)
    - its "incinerate-hit-count" is incremented by 1
    - its "incinerate-ability-level" is set to max(old-value, level-of-incinerate-instance-that-hit-it)
    - bonus damage is applyed, where the bonus damage is calculated by:
        bonus-damage = incinerate-hit-count * multiplier-for(incinerate-ability-level);
        I haven't tested what kind of damage it is, could be spell (gets reduced by hero type armor, ignoring armor value, or some other kind)
    - a buf and a special effect is added to the unit
    - its "incinerate-timer" is restarted (when this timer expires the incinerate-hit-count is set to 0, the buf and effect are removed)

Example:
Code:
In a 4vs4 melee game, one of the teams decide to pick 4 firelords from the tavern and use incinerate.

All players go to the middle of the map and each firelord hero attacks "the big dragon" 10 times, for a total of 40 attacks;
the bonus damage from those attacks for level 1 incinerate turns out to be 820.

If the firelords were using your version of incinerate with (stackingDamage = 1),
the bonus damage would turn out to be 220 = 4 * 55, i.e
"the big dragon" will have 4 sets of:
    "incinerate-hit-count"
    "incinerate-ability-level"
    "incinerate-timer"

for each of the firelords that are attacking it.


You might want to consider using the keys feature of vJass for readability:
JASS:
...
if tb.boolean[7] then // whats bool[7]?, oh right its the "under the effect of incinerate" flag
...
call tb.real.remove(1) // whats real[1]?
...
set tb.timer[6] = t // the "incinerate-timer", sort of makes sense


It seems there's no need to null the primitive and enum types in the destroy method. They would be reset on the next call to the create method (which is also true for the handle types).

Its actually more lines to optionally include a library then not to, i.e you pretty much don't use the library:
JASS:
    optional GroupUtils               //  http://www.wc3c.net/showthread.php?t=104464
...
        static if not LIBRARY_GroupUtils then
            private static group ENUM_GROUP = CreateGroup()
        endif
...

PS: Blizzard's Incinerate ability (ANia) adds an icon in the units status bar, you can use the tornado aura ('Aasl') to optionally do the same (via UnitAddAbility).
 

AGD

AGD

Level 16
Joined
Mar 29, 2016
Messages
688
That's funny... I am afraid you made the ability too MUI =).
Nice catch =), thanks for pointing that out. Will fix it soon.

You might want to consider using the keys feature of vJass for readability:
Hmm, that would cost 8 additional lines.

It seems there's no need to null the primitive and enum types in the destroy method. They would be reset on the next call to the create method (which is also true for the handle types).
I need to do it because the module InitDefaultIncinerate is given for the users to configure, hence, they can remove it if they want to. If they did that, the destroyed instance's data won't all be reset after reallocation (unless if they would manually set all the data after allocation).

Its actually more lines to optionally include a library then not to, i.e you pretty much don't use the library:
3 more lines that will eventually be removed upon compiling is fine I think. In exchange for little efficiency in certain cases =).

PS: Blizzard's Incinerate ability (ANia) adds an icon in the units status bar, you can use the tornado aura ('Aasl') to optionally do the same (via UnitAddAbility).
Okay, I'll try to see what I can do with it.


EDIT:
I'll also add more description and details to the thread soon.
 

AGD

AGD

Level 16
Joined
Mar 29, 2016
Messages
688
Updated to v1.0b

- You can now add as many incinerates to a unit, unlike the previous version where the system allocates 1 incinerate per unit
- Added an incinerate explosion event handler and its event responses together with its api for the users
- On the onDamage method, instead of directly changing the PDDS.amount, it now uses UnitDamageTargetEx()
- The damage stacking special effect is now created once the effect is null instead of destroying and recreating per damage stacking
- Added a sample usage script
- Some code optimization and changes


PS: Blizzard's Incinerate ability (ANia) adds an icon in the units status bar, you can use the tornado aura ('Aasl') to optionally do the same (via UnitAddAbility).
Not implemented yet
 
Could you mybe enumerate bugs of Firelord's Incinerate?
I'm noob, and don't really know them myself, and it would help others probabaly, too. : )

Does main AoE of explosion have no damage binded to it?
Because I see there is a exclusive aoe for an other damage factor.

The current filter seems pretty handy, and maybe fits for most cases.
However if we need more power then maybe a general filter (that is customized) can be used + Incinerate-specific filter.
Could be maybe solved with binding to a trigger, and evaluating it. But not sure if it's very needed/good in the end, just thoughts.

Usage of DDS makes it very strong. (spell damage detection for example) It's pretty good.

group isn't nulled in destroy method.
+
GroupUtils could always be used if exists instead create/destroy

Not sure I would personaly init 0x2000 tables each time. Most of them is probably wasted resource.
Something like this would be a bit more neat mayb:
JASS:
function create
    set .table = Table.create()


function register
    set .table[GetUnitId(u)] = Table.create()


function onDamage
    local table t = .table[GetUnitId(u)]

edit:

Aniki's point is good, maybe optional buff was helpful!

And btw, couldn't your spell in Spells Section take usage of this system? It would maybe be a great example, too.
 
Last edited:

AGD

AGD

Level 16
Joined
Mar 29, 2016
Messages
688
Could you mybe enumerate bugs of Firelord's Incinerate?
I'm noob, and don't really know them myself, and it would help others probabaly, too. : )
From what I encountered, the only bug is that you can't properly configure the data of any copies you make out of the original ability specifically the amount of stacking damage. But there are other reports of even having the original ability bugged. I'll try to figure out more about it.

Does main AoE of explosion have no damage binded to it?
Because I see there is a exclusive aoe for an other damage factor.
It has, the explosion does full (100 %) damage to a small aoe and a partial damage to the bigger aoe.

Not sure I would personaly init 0x2000 tables each time.
Ah yes, that is indeed more efficient.

Aniki's point is good, maybe optional buff was helpful!
I thought of just adding another event instead which runs when a unit becomes under the effect of a certain incinerate instance, as well as when an incinerate expires on a unit. Then users can freely do the things they want such as putting a buff or anything.

It would maybe be a great example, too.
Seems like a nice idea =)


EDIT:

Something like this would be a bit more neat mayb:
JASS:
function create
    set .table = Table.create()


function register
    set .table[GetUnitId(u)] = Table.create()


function onDamage
    local table t = .table[GetUnitId(u)]
Oops, the unit registered in the register method is the attacker while the unit in the GetUnitId() under the onDamage method is the target unit so I guess I'll still be using array of TableArrays.
 
Last edited:
Top