1. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  2. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  3. Don’t forget to sign up for the Hive Cup. There’s a 555 EUR prize pool. Sign up now!
    Dismiss Notice
  4. The Hive Workshop Cup contest results have been announced! See the maps that'll be featured in the Hive Workshop Cup tournament!
    Dismiss Notice
  5. The results are out! Check them out.
    Dismiss Notice
  6. The poll for Hive's 12th Concept Art Contest is up! Go cast your vote for your favourite genie!
    Dismiss Notice
  7. The raddest synthwave tracks were chosen - Check out our Music Contest #12 - Results and congratulate the winners!
    Dismiss Notice
  8. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Zephyr Contest #11 - My aura, Your aura

Discussion in 'Contest Archive' started by Pharaoh_, Jul 1, 2014.

Thread Status:
Not open for further replies.
  1. Mythic

    Mythic

    Joined:
    Apr 24, 2012
    Messages:
    7,728
    Resources:
    102
    Models:
    87
    Icons:
    4
    Maps:
    3
    Spells:
    6
    Tutorials:
    2
    Resources:
    102
    Looking great ruler, however I think 2s is too short for ramping movement. Perhaps 3~4s?
     
  2. rulerofiron99

    rulerofiron99

    Joined:
    Jul 10, 2006
    Messages:
    3,129
    Resources:
    14
    Maps:
    4
    Spells:
    9
    Tutorials:
    1
    Resources:
    14
    Thanks.

    Levels 1 and 2 take 4 seconds, level 3 takes 2.5 seconds. These are just arbitrary numbers anyhow, I haven't given much thought to balancing it.

    After playing around with it a bit in a melee map, it seems to be really good for ranged armies (e.g. archers).

    So yeah I guess I'll drop the acceleration a bit.
     
  3. Mythic

    Mythic

    Joined:
    Apr 24, 2012
    Messages:
    7,728
    Resources:
    102
    Models:
    87
    Icons:
    4
    Maps:
    3
    Spells:
    6
    Tutorials:
    2
    Resources:
    102
    Hm, that's probably why Endurance Aura wasn't given to Night Elves because they would be overpowered as fuck. xD
     
  4. rulerofiron99

    rulerofiron99

    Joined:
    Jul 10, 2006
    Messages:
    3,129
    Resources:
    14
    Maps:
    4
    Spells:
    9
    Tutorials:
    1
    Resources:
    14
    Indeed! That is why Orcs + Night Elves make a good 2v2 team :)

    @ judge: I haven't seen any ruling explicitly allowing or disallowing the use of unit indexing systems. Are they allowed?
     
  5. Zeatherann

    Zeatherann

    Joined:
    Nov 25, 2008
    Messages:
    1,303
    Resources:
    6
    Skins:
    1
    Tools:
    1
    Maps:
    4
    Resources:
    6
    I see that someone else likes my empowering the aura theme hehe.
     
  6. Pharaoh_

    Pharaoh_

    Joined:
    Nov 6, 2008
    Messages:
    8,127
    Resources:
    11
    Icons:
    3
    Skins:
    1
    Spells:
    6
    Tutorials:
    1
    Resources:
    11
    Any system is allowed, as I said, as long as it doesn't make most of the job for you. If minimal effort is invested, it's downgrading.
     
  7. Zeatherann

    Zeatherann

    Joined:
    Nov 25, 2008
    Messages:
    1,303
    Resources:
    6
    Skins:
    1
    Tools:
    1
    Maps:
    4
    Resources:
    6
    New Ability Idea

    I'm thinking of changing my aura.
    New Tooltip (State 1)
    Aspect of Thunder

    Active: Purges all nearby enemy units, removing all buffs from them and immobilizing them for 3 seconds. Deals 300 damage to summoned units.


    Passive: Periodically hurls bolts of lightning at nearby enemy units dealing 25 damage.


    Rick-click to empower the aura.

    New Tooltip (State 2)
    Aspect of Thunder

    Active: Purges all nearby enemy units, removing all buffs from them and immobilizing them for 3 seconds. Deals 300 damage to summoned units.


    Passive: Periodically hurls bolts of lightning at nearby enemy units dealing 25 damage.


    Empowered: Bolts of lightning bounce to two additional targets, but drains 50 mana each time. Automatically unempowers when out of mana.


    Rick-click to unempower the aura.

     
  8. Mythic

    Mythic

    Joined:
    Apr 24, 2012
    Messages:
    7,728
    Resources:
    102
    Models:
    87
    Icons:
    4
    Maps:
    3
    Spells:
    6
    Tutorials:
    2
    Resources:
    102
    Tell me if anyone is missing on my first post; (C)lick
     
  9. BlueSaint

    BlueSaint

    Joined:
    Jun 18, 2012
    Messages:
    2,771
    Resources:
    3
    Tools:
    1
    Spells:
    2
    Resources:
    3
    Lol :p

    As I said, nothing special, it's something I can use myself for my future projects :) Frost Nova causes land to cover up in snow tiles for a while, then melting away. Haven't done that part yet, but beside that I'm doing fine.

    Once I post the code and stuff, does it mean it's final submission, or can I edit it afterwards?

    Edit: just realized 900 AoE damage is way too much, need a bit of rework on that ^^'
     
  10. Tank-Commander

    Tank-Commander

    Spell Reviewer

    Joined:
    May 26, 2009
    Messages:
    1,543
    Resources:
    44
    Packs:
    1
    Spells:
    41
    Tutorials:
    2
    Resources:
    44
    You're much more confident in me winning then I am, personally I think this contest is going to be a very evenly-matched one XD
     
  11. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    6,181
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    You have time until the contest ends. And it's also a rule to show a WIP. So feel free to post your unfinished result.

    In the end you should create a new post with your final entry.
     
  12. Empirean

    Empirean

    Joined:
    Jun 20, 2014
    Messages:
    390
    Resources:
    8
    Spells:
    8
    Resources:
    8
    hi, i chose a different model for my aura, have a look hehe.

    can i ask, is it allowed if i add something like if the bearer of the aura's life or mana reaches certain amount something will happen? or if the bearer of the aura dies something will happen?
     

    Attached Files:

  13. Tank-Commander

    Tank-Commander

    Spell Reviewer

    Joined:
    May 26, 2009
    Messages:
    1,543
    Resources:
    44
    Packs:
    1
    Spells:
    41
    Tutorials:
    2
    Resources:
    44
    I'm almost certain you can, otherwise I'd have to modify mine XD
     
  14. Empirean

    Empirean

    Joined:
    Jun 20, 2014
    Messages:
    390
    Resources:
    8
    Spells:
    8
    Resources:
    8
    thanks for the answer tank commander. hehe
     
  15. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    6,181
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    Yes, passives are also allowed.
     
  16. Zeatherann

    Zeatherann

    Joined:
    Nov 25, 2008
    Messages:
    1,303
    Resources:
    6
    Skins:
    1
    Tools:
    1
    Maps:
    4
    Resources:
    6
    Question About Art

    Will we be required to have a fitting icon/models for our auras? Required means not having it causes a loss of points.

     
  17. Pharaoh_

    Pharaoh_

    Joined:
    Nov 6, 2008
    Messages:
    8,127
    Resources:
    11
    Icons:
    3
    Skins:
    1
    Spells:
    6
    Tutorials:
    1
    Resources:
    11
    It's part of the visuals actually (I know, its not explicitly stated, I should have included it), but no, it's almost pointless to care. I'd do it for the sake of harmony (especially if the ability was part of a skillset of 4, it would be easier to remember the effect of the spell by its icon). Imagine having a holy effect and an icon of two eyes in pitch black - no relation.
     
  18. Zeatherann

    Zeatherann

    Joined:
    Nov 25, 2008
    Messages:
    1,303
    Resources:
    6
    Skins:
    1
    Tools:
    1
    Maps:
    4
    Resources:
    6
    Official Work in Progress for Aspect of Thunder

    So, at least try to get a good looking model/icon, but don't stress it? Got it.

    ~ Edit ~

    As lame of a work in progress post as it is, here is my work in progress post, map is attached.

    ~ Note ~

    I reference the aura's name as Aspect of Thunder or Aspect of Lightning as that was my original name for it. The final submission will all be using the same name.

     

    Attached Files:

    Last edited: Jul 7, 2014
  19. Mythic

    Mythic

    Joined:
    Apr 24, 2012
    Messages:
    7,728
    Resources:
    102
    Models:
    87
    Icons:
    4
    Maps:
    3
    Spells:
    6
    Tutorials:
    2
    Resources:
    102
    @Zeatherann, so you are officially replacing your old aura?
     
  20. BlueSaint

    BlueSaint

    Joined:
    Jun 18, 2012
    Messages:
    2,771
    Resources:
    3
    Tools:
    1
    Spells:
    2
    Resources:
    3
    Okay. Here's a WIP:
    ChillingAura
    This resource uses vJASS syntax:
    http://blizzardmodding.info/4263/the-jass-newgen-pack-jngp-2-0/

    This resource uses PUI:
    http://www.thehelper.net/threads/pui-perfect-unit-indexing.65470/

    This resource uses TimerUtils:
    http://www.wc3c.net/showthread.php?p=1020244

    This resource uses Table:
    http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/

    This resource uses StructuredDD:
    http://www.hiveworkshop.com/forums/...uctureddd-structured-damage-detection-216968/

    Ability Chilling Aura:
    Code (vJASS):
    scope ChillingAura // v1.0.0 // requires PUI, TimerUtils, Table, StructuredDD, StillDummy, UnitTextTag
    //===========================================================================

        // GLOBALS DECLARATION

    //===========================================================================
        globals
            private constant integer MAX_TILE = 3
            private constant boolean USE_TEXTTAG = true
                private constant string TT_COLOR = "|c0000ffff"
                private constant string TT_COLOR_RAGE = "|c00ff3300"
            private constant integer ABILITY_ID = 'AHab'
            private constant real INTERVAL = 0.05 // alt. 0.03125
            private constant real AURA_INTERVAL = 0.5
            private constant real TICK = 2.
            private constant real FULL_TICK = 6.
            private constant player EFFECT_OWNER = Player(PLAYER_NEUTRAL_PASSIVE)
            private constant string EFFECT_HIT = "Abilities\\Spells\\Undead\\CarrionSwarm\\CarrionSwarmDamage.mdl"
            private constant string EFFECT_BUFF = "Abilities\\Spells\\Other\\GeneralAuraTarget\\GeneralAuraTarget.mdl"
            private constant string EFFECT_READY_ORIGIN = "Abilities\\Spells\\Orc\\Purge\\PurgeBuffTarget.mdl"
            private constant string EFFECT_READY_OVERHEAD = "Abilities\\Spells\\Human\\ManaFlare\\ManaFlareTarget.mdl"
            private constant string EFFECT_MAX_1 = "Abilities\\Weapons\\Bolt\\BoltImpact.mdl"
            private constant string EFFECT_MAX_2 = "Abilities\\Spells\\Other\\Charm\\CharmTarget.mdl"
            private constant string EFFECT_MAX_3 = "Abilities\\Spells\\Human\\Feedback\\SpellBreakerAttack.mdl"
            private effect array EFFECT
            private group SWITCH_GROUP
            private group TEMP_GROUP = CreateGroup()
        endglobals
    //===========================================================================

        // USEFUL FUNCTIONS

    //===========================================================================
        private constant function GetSmaller takes real r1, real r2 returns real
            if r1 < r2 then
                return r1
            endif
            return r2
        endfunction
        private constant function GetBigger takes real r1, real r2 returns real
            if r1 > r2 then
                return r1
            endif
            return r2
        endfunction
    //===========================================================================

        // USEFUL STRUCTS

    //===========================================================================
        private struct UnitScale extends array
            private real goal
            private real current
            private real speed
            private unit u
            private boolean active
            boolean flushOnFinish
            method flush takes nothing returns nothing
                set active = false
                set current = 1
                set goal = 1
                set u = null
            endmethod
            private static method onLoop takes nothing returns nothing
                local timer t = GetExpiredTimer()
                local thistype s = GetTimerData(t)
                if s.current < s.goal then
                    set s.current = GetSmaller(s.current + s.speed, s.goal)
                    call SetUnitScale(s.u, s.current, s.current, s.current)
                elseif s.current > s.goal then
                    set s.current = GetBigger(s.current - s.speed, s.goal)
                    call SetUnitScale(s.u, s.current, s.current, s.current)
                endif
                if s.current == s.goal then
                    call ReleaseTimer(t)
                    set s.active = false
                    if s.flushOnFinish then
                        call s.flush()
                    endif
                endif
                set t = null
            endmethod
            method setScale takes real r, real rate returns nothing
                local timer t
                set goal = r
                set speed = rate
                set flushOnFinish = false
                if u != GetIndexUnit(this) then
                    set u = GetIndexUnit(this)
                    set current = 1
                endif
                if not active then
                    set active = true
                    set t = NewTimer()
                    call SetTimerData(t, this)
                    call TimerStart(t, INTERVAL, true, function thistype.onLoop)
                    set t = null
                endif
            endmethod
        endstruct
        private struct currentPool extends array
            readonly integer size
            readonly Table table
            method add takes integer which returns nothing
                if size == 0 then
                    set table = Table.create()
                    set size = 0
                endif
                set size = size + 1
                set table [size] = which
            endmethod
            method flush takes nothing returns nothing
                if size != 0 then
                    set size = 0
                    call table.destroy()
                endif
            endmethod
            private method flushIndex takes integer index returns nothing
                local integer i = size
                loop
                    set i = i - 1
                    set table [i] = table [i+1]
                    exitwhen i == 1 or i == index
                endloop
                set size = size - 1
            endmethod
            method remove takes integer which returns nothing
                local integer i = 0
                loop
                    set i = i + 1
                    if table [i] == which then
                        if size > 1 then
                            call flushIndex(i)
                        else
                            set size = size - 1
                        endif
                        exitwhen true
                    endif
                    exitwhen i >= size
                endloop
                if size == 0 then
                    call table.destroy()
                endif
            endmethod
        endstruct
    //===========================================================================

        // EFFECT STRUCT

    //===========================================================================
        private struct EffectReady
            private unit target
            private effect ef1
            private effect ef2
            boolean max
            method destroy takes nothing returns nothing
                call UnitScale[GetUnitIndex(target)].setScale(1,INTERVAL*2)
                set UnitScale[GetUnitIndex(target)].flushOnFinish = true
                call DestroyEffect(ef1)
                call DestroyEffect(ef2)
                if max then
                    call Tile_RemoveProducer(target)
                endif
                set max = false
                set ef1 = null
                set ef2 = null
                set target = null
            endmethod
            static method create takes unit u returns thistype
                local thistype s = thistype.allocate()
                set s.target = u
                set s.max = false
                set s.ef1 = AddSpecialEffectTarget(EFFECT_READY_ORIGIN, u, "origin")
                set s.ef2 = AddSpecialEffectTarget(EFFECT_READY_OVERHEAD, u, "overhead")
                call UnitScale[GetUnitIndex(u)].setScale(1.4,INTERVAL)
                return s
            endmethod
            method stateMax takes Table tiles returns nothing
                local unit u = StillDummy_Create(EFFECT_OWNER, GetUnitX(target), GetUnitY(target), GetUnitFlyHeight(target), .8)
                set max = true
                call BJDebugMsg("asd")
                call SetUnitScale(u, 1.7, 1.7, 1.7)
                call DestroyEffect(AddSpecialEffectTarget(EFFECT_MAX_1, u, "origin"))
                call DestroyEffect(AddSpecialEffectTarget(EFFECT_MAX_2, u, "origin"))
                call DestroyEffect(AddSpecialEffectTarget(EFFECT_MAX_3, u, "origin"))
                call Tile_Spawn(GetUnitX(target),GetUnitY(target),tiles,MAX_TILE,400,5)
                call Tile_AddProducer(target, tiles, MAX_TILE, 250)
                call UnitScale[GetUnitIndex(target)].setScale(1.7,INTERVAL)
                set u = null
            endmethod
        endstruct
    //===========================================================================

        // AURA STRUCT

    //===========================================================================
        private struct Struct
                // member declaration
            private static Table tTable // tiles table
            private static TableArray vTable // value table
            private static thistype s
            private static thistype array current
            private static trigger array deathTrigger
            private integer level
            private EffectReady efR
            private trigger t
            private timer tick
            private timer aura
            static if USE_TEXTTAG then
                private real textCd
            endif
            private real step
            private real outPut
            private real rage
            private real rageMultiplier
            private real rageCap
            private real damageMin
            private real damage
            private real damagePerSecond
            private real damageMax
            private real damageAoE
            private real auraAoE
            private unit caster
            private group g
            private static method ungroupUnit takes unit u, thistype from returns nothing
                local integer i = GetUnitIndex(u)
                call currentPool[i].remove(from)
                if currentPool[i].size == 0 then
                    call DestroyEffect(EFFECT[i])
                    set EFFECT[i] = null
                    call DestroyTrigger(deathTrigger[i])
                    set deathTrigger[i] = null
                endif
            endmethod
            private static method clearGroupEnum takes nothing returns nothing
                call ungroupUnit(GetEnumUnit(), s)
            endmethod
            private method destroy takes nothing returns nothing
                    // destroy method
                set current[GetUnitIndex(caster)] = 0
                set caster = null
                set s = this
                call ForGroup(g, function thistype.clearGroupEnum)
                call DestroyGroup(g)
                set g = null
                call ReleaseTimer(tick)
                set tick = null
                call ReleaseTimer(aura)
                set aura = null
                if efR != 0 then
                    call efR.destroy()
                    set efR = 0
                endif
                call DestroyTrigger(t)
                set t = null
            endmethod
            static if USE_TEXTTAG then
                private method displayRageText takes nothing returns nothing
                        // display text plus orange text
                    set textCd = 1.
                    call CreateTextTagUnit(caster, TT_COLOR+I2S(R2I(damage))+TT_COLOR_RAGE+" +"+I2S(R2I(rage)), TICK+0.5, 1.2, 0.8)
                endmethod
            endif
            private static method onAttack takes nothing returns nothing
                    // attack event
                local integer i = 0
                local unit u = GetTriggerUnit()
                local unit u2
                local currentPool cp = currentPool[GetUnitUserData(u)]
                if cp.size > 0 and IsUnitEnemy(GetEventDamageSource(),GetOwningPlayer(u)) then
                    loop
                        set i = i + 1
                        set s = cp.table [i]
                        set s.rage = GetSmaller(s.rage + GetEventDamage()*s.rageMultiplier, s.rageCap)
                        static if USE_TEXTTAG then
                            if s.textCd == 0 then
                                call s.displayRageText()
                            endif
                        endif
                        exitwhen i == cp.size
                    endloop
                    set u2 = StillDummy_Create(EFFECT_OWNER, GetUnitX(u), GetUnitY(u), GetUnitFlyHeight(u), .8)
                    call SetUnitScale(u2, 2, 2, 2)
                    call DestroyEffect(AddSpecialEffectTarget(EFFECT_HIT, u2, "origin"))
                    set u2 = null
                endif
                set u = null
            endmethod
            private static method auraFilter takes nothing returns boolean
                    // valid aura targets
                return UnitAlive(GetFilterUnit()) and IsUnitAlly(GetFilterUnit(), GetOwningPlayer(s.caster)) and not IsUnitType(GetFilterUnit(), UNIT_TYPE_MECHANICAL)
            endmethod
            private static method onDeath takes nothing returns boolean
                    // aura member death
                local unit u = GetTriggerUnit()
                call currentPool[GetUnitIndex(u)].flush()
                call DestroyEffect(EFFECT[GetUnitIndex(u)])
                set EFFECT[GetUnitIndex(u)] = null
                call DestroyTrigger(deathTrigger[GetUnitIndex(u)])
                set deathTrigger[GetUnitIndex(u)] = null
                set u = null
                return false
            endmethod
            private static method auraLoop takes nothing returns nothing
                    // register units
                local group g = CreateGroup()
                local unit FoG
                set s = GetTimerData(GetExpiredTimer())
                call GroupEnumUnitsInRange(g, GetUnitX(s.caster), GetUnitY(s.caster), s.auraAoE, Filter(function thistype.auraFilter))
                loop
                    set FoG = FirstOfGroup(s.g)
                    exitwhen FoG == null
                    if IsUnitInGroup(FoG, g) then
                        call GroupAddUnit(TEMP_GROUP, FoG)
                    elseif UnitAlive(FoG) then
                        call ungroupUnit(FoG,s)
                    endif
                    call GroupRemoveUnit(s.g, FoG)
                endloop
                set SWITCH_GROUP = s.g
                set s.g = TEMP_GROUP
                set TEMP_GROUP = SWITCH_GROUP
                loop
                    set FoG = FirstOfGroup(g)
                    exitwhen FoG == null
                    if not IsUnitInGroup(FoG, s.g) then
                        call GroupAddUnit(s.g, FoG)
                        call currentPool[GetUnitIndex(FoG)].add(s)
                        if EFFECT[GetUnitIndex(FoG)] == null and FoG != s.caster then
                            set EFFECT[GetUnitIndex(FoG)] = AddSpecialEffectTarget(EFFECT_BUFF, FoG, "origin")
                            set deathTrigger[GetUnitIndex(FoG)] = CreateTrigger()
                            call TriggerRegisterUnitEvent(deathTrigger[GetUnitIndex(FoG)], FoG, EVENT_UNIT_DEATH)
                            call TriggerRegisterUnitEvent(deathTrigger[GetUnitIndex(FoG)], FoG, EVENT_UNIT_DECAY)
                            call TriggerRegisterUnitEvent(deathTrigger[GetUnitIndex(FoG)], FoG, EVENT_UNIT_CHANGE_OWNER)
                            call TriggerAddCondition(deathTrigger[GetUnitIndex(FoG)], Condition(function thistype.onDeath))
                        endif
                    endif
                    call GroupRemoveUnit(g, FoG)
                endloop
                call DestroyGroup(g)
                set g = null
            endmethod
            private static method onLoop takes nothing returns nothing
                    // spell loop
                set s = GetTimerData(GetExpiredTimer())
                static if USE_TEXTTAG then
                    set s.textCd = GetBigger(s.textCd-INTERVAL, 0.)
                endif
                set s.step = s.step - INTERVAL
                if s.step <= 0. then
                    set s.step = TICK
                    if s.damage < s.damageMax then
                        set s.damage = GetSmaller(s.damage + s.damagePerSecond, s.damageMax)
                        if s.rage > 0 then
                            static if USE_TEXTTAG then
                                if s.textCd == 0 then
                                    call s.displayRageText()
                                endif
                            endif
                        else
                            static if USE_TEXTTAG then
                                if s.textCd == 0 then
                                    call CreateTextTagUnit(s.caster, TT_COLOR+I2S(R2I(s.damage)), TICK+0.5, 1.2, 0.8)
                                    set s.textCd = 1
                                endif
                            endif
                        endif
                    else
                        set s.step = FULL_TICK
                        static if USE_TEXTTAG then
                            if s.textCd == 0 then
                                call s.displayRageText()
                            endif
                        endif
                    endif
                    if Lich_EXTRA_DAMAGE[GetUnitIndex(s.caster)] != 0 then
                        // there is damage applied onto caster
                            // refresh the output value
                        set s.outPut = s.rage + s.damage
                        if s.outPut < s.damageMin then
                            set Lich_EXTRA_DAMAGE[GetUnitIndex(s.caster)] = 0
                            if s.efR != 0 then
                                call s.efR.destroy()
                                set s.efR = 0
                            endif
                        else
                            set Lich_EXTRA_DAMAGE[GetUnitIndex(s.caster)] = s.outPut
                            set Lich_EXTRA_DAMAGE_AOE[GetUnitIndex(s.caster)] = s.damageAoE
                            if s.damage == s.damageMax and not s.efR.max then
                                call s.efR.stateMax(tTable)
                            endif
                        endif
                    endif
                endif
                if Lich_EXTRA_DAMAGE[GetUnitIndex(s.caster)] == 0 then
                        // there's no damage applied onto caster
                        if s.outPut == 0 then
                            // if there hasn't been any damage
                            if s.rage + s.damage >= s.damageMin then
                                set s.outPut = s.rage + s.damage
                                set Lich_EXTRA_DAMAGE[GetUnitIndex(s.caster)] = s.outPut
                                set Lich_EXTRA_DAMAGE_AOE[GetUnitIndex(s.caster)] = s.damageAoE
                                if s.efR == 0 then
                                    set s.efR = EffectReady.create(s.caster)
                                endif
                            endif
                        else
                            // if there has been damage
                                // reduce the output amount from damage values
                            set s.rage = 0
                            set s.damage = 0
                            set s.outPut = 0
                                // remove possible effect applied
                            if s.efR != 0 then
                                call s.efR.destroy()
                                set s.efR = 0
                            endif
                        endif
                    endif
            endmethod
            private method updateStats takes nothing returns nothing
                    // update values
                set damagePerSecond   = vTable [1].real [level]
                set damageMax             = vTable [2].real [level]
                set auraAoE                    = vTable [3].real [level]
                set damageAoE              = vTable [4].real [level]
                set rageMultiplier          = vTable [5].real [level]
                set rageCap                    = vTable [6].real [level]
                set damageMin              = vTable [7].real [level]
            endmethod
            private static method casterDeath takes nothing returns boolean
                call current[GetUnitIndex(GetTriggerUnit())].destroy()
                return false
            endmethod
            private static method registerCaster takes unit u, integer i returns boolean
                if current[GetUnitIndex(u)] == 0 then
                    set s = thistype.create()
                    set Lich_EXTRA_DAMAGE[GetUnitIndex(u)] = 0
                    set s.caster = u
                    set s.level = i
                    set s.outPut = 0
                    set s.t = CreateTrigger()
                    call TriggerRegisterUnitEvent(s.t, u, EVENT_UNIT_DEATH)
                    call TriggerRegisterUnitEvent(s.t, u, EVENT_UNIT_CHANGE_OWNER)
                    call TriggerRegisterUnitEvent(s.t, u, EVENT_UNIT_DECAY)
                    call TriggerAddCondition(s.t, Condition(function thistype.casterDeath))
                    set s.efR = 0
                    set s.rage = 0
                    static if USE_TEXTTAG then
                        set s.textCd = 0
                    endif
                    set s.g = CreateGroup()
                    set current[GetUnitIndex(u)] = s
                    set s.damage = vTable [0].real [i]
                    call s.updateStats()
                    set s.step = TICK
                    set s.tick = NewTimer()
                    set s.aura = NewTimer()
                    call SetTimerData(s.tick, s)
                    call SetTimerData(s.aura, s)
                    call TimerStart(s.tick, INTERVAL, true, function thistype.onLoop)
                    call TimerStart(s.aura, AURA_INTERVAL, true, function thistype.auraLoop)
                    return true
                endif
                return false
            endmethod
            private static method onCast takes nothing returns boolean
                    // spell learned / unit entered field
                local unit u = GetTriggerUnit()
                local integer i = GetUnitAbilityLevel(u, ABILITY_ID)
                call BJDebugMsg("asd")
                if i > 0 then
                    if not registerCaster(u,i) and current[GetUnitIndex(u)].level != i then
                        set current[GetUnitIndex(u)].level = i
                        call current[GetUnitIndex(u)].updateStats()
                    endif
                elseif current[GetUnitIndex(u)] != 0 then
                    call current[GetUnitIndex(u)].destroy()
                endif
                set u = null
                return false
            endmethod
            private static method onInit takes nothing returns nothing
                    // spell initialization
                local trigger t = CreateTrigger()
                set tTable = Table.create()
                    // tiles
                set tTable [0] = 'Wsnw'
                set tTable [1] = 'Nsnw'
                set tTable [2] = 'Nsnr'
                set tTable [3] = 'Isnw'
                set vTable = TableArray [8]
                    // index 0 = starting damage
                set vTable [0].real[1] = 20.
                set vTable [0].real[2] = 30.
                set vTable [0].real[3] = 40.
                    // index 1 = damage per tick
                set vTable [1].real[1] = 4.
                set vTable [1].real[2] = 8.
                set vTable [1].real[3] = 12.
                    // index 2 = max damage
                set vTable [2].real[1] = 200.
                set vTable [2].real[2] = 250.
                set vTable [2].real[3] = 300.
                    // index 3 = aura AoE
                set vTable [3].real[1] = 800.
                set vTable [3].real[2] = 800.
                set vTable [3].real[3] = 800.
                    // index 4 = damage AoE
                set vTable [4].real[1] = 250.
                set vTable [4].real[2] = 250.
                set vTable [4].real[3] = 250.
                    // index 5 -rage mutliplier
                set vTable [5].real[1] = 0.2
                set vTable [5].real[2] = 0.4
                set vTable [5].real[3] = 0.6
                    // index 6 - rage cap
                set vTable [6].real[1] = 100
                set vTable [6].real[2] = 200
                set vTable [6].real[3] = 300
                    // index 7 - min damage
                set vTable [7].real[1] = 100
                set vTable [7].real[2] = 100
                set vTable [7].real[3] = 100
                call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_HERO_SKILL)
                call TriggerRegisterEnterRectSimple(t, bj_mapInitialPlayableArea)
                call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_HERO_REVIVE_FINISH)
                call TriggerAddCondition(t, Condition(function thistype.onCast))
                set t = null
                call StructuredDD.addHandler(function thistype.onAttack)
            endmethod
        endstruct
    endscope
    //===========================================================================

        // OUTPUT

    //===========================================================================
    library Lich
        globals
            public real array EXTRA_DAMAGE
            public real array EXTRA_DAMAGE_AOE
        endglobals
    endlibrary
    //===========================================================================

        // USED BY SUB-ABILITIES (such as Frost nova) AND AURA

    //===========================================================================
    library Tile initializer init requires Table, TimerUtils
        globals
            private constant real INTERVAL = .08334
            private constant real DISTANCE = 128.
            private group PRODUCERS = CreateGroup()
            private real CHECK_DIST = 0.
            private constant trigger TRIGGER = CreateTrigger()
            private Table array TILES
            private integer array TILE_MAX
            private real array RADIUS
            private group SWITCH_GROUP
            private group TEMP_GROUP = CreateGroup()
        endglobals
        private constant function GetBigger takes real r1, real r2 returns real
            if r1 > r2 then
                return r1
            endif
            return r2
        endfunction
        private function Pythagoras takes real x, real y returns real
            return SquareRoot(x*x + y*y)
        endfunction
        private function round takes real r1, real r2 returns real
                if r1 > 0 then
                    return I2R(R2I(r1/r2 + 0.5))*r2
                endif
                return I2R(R2I(r1/r2 - 0.5))*r2
        endfunction
        private function ProducerFilter takes nothing returns boolean
            return IsUnitInGroup(GetFilterUnit(), PRODUCERS)
        endfunction
        private struct Struct
            private integer original
            private integer tile
            private integer var
            private real time
            private real x
            private real y
            private static method onLoop takes nothing returns nothing
                local timer t = GetExpiredTimer()
                local thistype s = GetTimerData(t)
                local group g = CreateGroup()
                call GroupEnumUnitsInRange(g, s.x, s.y, CHECK_DIST, Filter(function ProducerFilter))
                if FirstOfGroup(g) == null then
                    set s.time = s.time - INTERVAL
                endif
                if s.time <= 0 then
                    if GetTerrainType(s.x, s.y) == s.tile and GetTerrainVariance(s.x, s.y) == s.var then
                        call SetTerrainType(s.x, s.y, s.original, -1, 1, 0)
                    endif
                    call ReleaseTimer(t)
                endif
                call DestroyGroup(g)
                set t = null
                set g = null
            endmethod
            static method create takes real x, real y, Table table, integer max, real duration returns thistype
                local thistype s
                local timer t
                local boolean b = true
                local integer i = GetTerrainType(x, y)
                local integer n = -1
                loop
                    set n = n + 1
                    if i == table[n] then
                        set b = false
                        exitwhen true
                    endif
                    exitwhen n == max
                endloop
                if b then
                    set s = thistype.allocate()
                    set t = NewTimer()
                    set s.original = i
                    set s.time = duration
                    call SetTerrainType(x, y, table[GetRandomInt(0, max)], -1, 1, 0)
                    set s.tile = GetTerrainType(x,y)
                    set s.var = GetTerrainVariance(x,y)
                    call SetTimerData(t, s)
                    set s.x = x
                    set s.y = y
                    call TimerStart(t, INTERVAL, true, function thistype.onLoop)
                    set t = null
                endif
                return s
            endmethod
        endstruct
        public function Spawn takes real x, real y, Table tiles,  integer maxTile, real radius, real time returns nothing
                // current coord
            local real cX = round(x - radius/2, DISTANCE)
            local real cY
            local real r
            loop
                set cX = cX + DISTANCE
                set cY = round(y - radius/2, DISTANCE)
                loop
                    set cY = cY + DISTANCE
                    set r = Pythagoras(x-cX,y-cY)
                    if r <= radius then
                        call Struct.create(cX, cY, tiles, maxTile, GetBigger(0.5,time - r/DISTANCE))
                    endif
                    exitwhen cY >= y + radius/2
                endloop
                exitwhen cX >= x + radius/2
            endloop
        endfunction
        public function AddProducer takes unit u, Table tiles, integer maxTile, real radius returns nothing
            if FirstOfGroup(PRODUCERS) == null then
                set CHECK_DIST = 0
                call EnableTrigger(TRIGGER)
            endif
            if not IsUnitInGroup(u, PRODUCERS) then
                set CHECK_DIST = GetBigger(radius, CHECK_DIST)
                call GroupAddUnit(PRODUCERS, u)
                set TILES[GetUnitIndex(u)] = tiles
                set TILE_MAX[GetUnitIndex(u)] = maxTile
                set RADIUS[GetUnitIndex(u)] = radius
            endif
        endfunction
        public function RemoveProducer takes unit u returns nothing
            if IsUnitInGroup(u, PRODUCERS) then
                call GroupRemoveUnit(PRODUCERS, u)
            endif
        endfunction
        private function Cond takes nothing returns boolean
            local unit FoG
            local integer i
            if FirstOfGroup(PRODUCERS) == null then
                call DisableTrigger(TRIGGER)
            else
                loop
                    set FoG = FirstOfGroup(PRODUCERS)
                    exitwhen FoG == null
                    set i = GetUnitIndex(FoG)
                    call Spawn(GetUnitX(FoG),GetUnitY(FoG),TILES[i],TILE_MAX[i],RADIUS[i],1)
                    call GroupRemoveUnit(PRODUCERS, FoG)
                    call GroupAddUnit(TEMP_GROUP, FoG)
                endloop
                set SWITCH_GROUP = PRODUCERS
                set PRODUCERS = TEMP_GROUP
                set TEMP_GROUP = SWITCH_GROUP
            endif
            return false
        endfunction
        private function init takes nothing returns nothing
            call TriggerRegisterTimerEvent(TRIGGER, INTERVAL, true)
            call TriggerAddCondition(TRIGGER, Condition(function Cond))
            call DisableTrigger(TRIGGER)
        endfunction
    endlibrary


    Changelog:
    Update 8.7.2014:
    -Added snow tiles beneath fully charged hero
    -Bug fixes
    -More comments
    -Added a couple of effects

    Posted 7.7.2014​


    I didn't include StillDummy and UnitTextTag yet. Also I haven't finished the Frost Nova effect and the aura itself lacks in effects.

    And I read something about adding comments to explain stuff in the code so that's in the works too, but this is a good start :)
     
    Last edited: Jul 8, 2014
Thread Status:
Not open for further replies.