• 🏆 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!

Sentry v1.3

  • Like
Reactions: OVOgenez
I made a spell pack for an assassin type Hero.

34pett1.png


Scythe hero spellpack made by msongyyy
Requires
All triggers in Systems used in this map, thanks to their rightful owners
All objects and imports used in this map
Thanks to Ecknovkol(Shade) and Maker (Lightning Speed Laceration) for their visions

Stuff in variables are ability id's and unit id's - make sure to set those up
Other configurable are in the spells' separate scopes

Changelog:
- 1.2 improved code again, now uses SharedList/TimerTools (lacerate and blur), UnitFadeSystem(no longer my crappy one), GetClosestWidget, TerrainPathability - recommended to use SharedList... cleaned up and improved lots of stuff
- 1.1 improved code slightly, added a grain of sands worth to the systems
- 1.0 release

Thanks to all these fellas who deserve much applause for their profound works.


JASS:
//===============================================
//
//          Amplify System
//  by msongyyy
//
//  Amplify system is a very lightweight system that lets you 
//  amplify damage dealt to an unit.
//  Not very customizable for the time being, don't recommend
//  using out of this spellpack unless you know what you're doing
//
//  Required Triggers:
//      xefx, xebasic
//      Functions
//  Required Imports:
//      dummy.mdx
//
//===============================================

library AmplifySystem

    globals
        private constant real FX_Z              = 150.00                    // How high above is the effect over the unit
        
        private constant real TAG_X             = 50.                       // How far on the x plane compared to the unit
        private constant real TAG_Y             = 100.                      // How far on the y plane compared to the unit 
        private constant real TAG_Z             = 150.                      // How high above is the text over the unit
        private constant real TAG_SIZE          = 13 * .0023                // Size of text
        
        private constant string TAG_COLOR       = "|cff99b4d1"              // Color of string
        
        private constant timer TMR              = CreateTimer()
        private constant real PERIOD            = 0.020000                  // How often text is updated
    endglobals
    
    struct Amplify extends array
        unit targ
        real mult
        xefx fx
        real time
        real size
        texttag t
        
        static integer array rn
        static integer array prev
        static integer array next
        static integer ic = 0
        
        method operator addSize= takes real value returns nothing
           set .size = .size + value
        endmethod
        
        method operator addMult= takes real value returns nothing
            set .mult = .mult + value
        endmethod
        
        method operator addTime= takes real value returns nothing
            set .time = .time + value 
        endmethod
        
        static method hasBuff takes unit u returns integer
            local thistype this = next[0]
            
            loop
                exitwhen this == 0
                if .targ == u then
                    return this
                endif
                set this = next[this]
            endloop
            
            return this
        endmethod
        
        static method looping takes nothing returns nothing
            local thistype this = next[0]
            
            loop
                exitwhen this == 0 
                
                if not UnitAlive(.targ) or .time <= 0.00 then
                    call DestroyTextTag(.t)
                    call .fx.destroy()
                    
                    set .t = null
                    set .targ = null
                    
                    set prev[next[this]] = prev[this]
                    set next[prev[this]] = next[this]
                    set rn[this] = rn[0]
                    set rn[0] = this
                else
                    set .fx.x = GetUnitX(.targ)
                    set .fx.scale = .size
                    set .fx.y = GetUnitY(.targ)
                    set .time = .time - PERIOD
                    call SetTextTagPos(.t, GetUnitX(.targ) + TAG_X, GetUnitY(.targ) + TAG_Y, TAG_Z)
                    call SetTextTagText(.t, TAG_COLOR + SubString(R2S(.mult), 0, 4), TAG_SIZE)
                endif
                
                set this = next[this]
                
                if next[0] == 0 then
                    call PauseTimer(TMR)
                endif
            endloop
        endmethod
        
        static method alloc takes unit target, real multiplier, string fxpath, real duration returns nothing
            local thistype this = rn[0]
            
            if this == 0 then
                set ic = ic + 1
                set this = ic
            else 
                set rn[0] = rn[this]
            endif
            
            set prev[this] = prev[0]
            set next[this] = 0
            set next[prev[0]] = this
            set prev[0] = this
        
            //
            
            set .targ = target
            set .mult = multiplier
            set .fx = xefx.create(GetUnitX(.targ), GetUnitY(.targ), 0.00)
            set .fx.fxpath = fxpath
            set .fx.z = FX_Z + GetUnitFlyHeight(.targ)
            set .size = 1.00
            set .time = duration
            
            set .t = CreateTextTag()
            call SetTextTagText(.t, TAG_COLOR + SubString(R2S(.mult), 0, 4), TAG_SIZE)
            call SetTextTagPos(.t, GetUnitX(.targ) + TAG_X, GetUnitY(.targ) + TAG_Y, TAG_Z)
            
            //
            
            if prev[this] == 0 then
                call TimerStart(TMR, PERIOD, true, function thistype.looping)
            endif
        endmethod
        
        static method amplifyDamage takes nothing returns boolean
            local thistype this = next[0]
            
            loop
                exitwhen this == 0 or .targ == udg_DamageEventTarget
                set this = next[this]
            endloop
            
            if .targ == udg_DamageEventTarget then
                set udg_DamageEventAmount = udg_DamageEventAmount * .mult
            endif
            
            return false 
        endmethod
        
        static method onInit takes nothing returns nothing
            local trigger t = CreateTrigger()
            
            call TriggerRegisterVariableEvent(t, "udg_DamageModifierEvent", EQUAL, 1.00)
            call TriggerAddCondition(t, function thistype.amplifyDamage)
        
            set t = null
        endmethod
            
    endstruct
    
endlibrary
JASS:
//===============================================
//
//          Lacerate
//  idea and original skill by Maker (Lighting Speed Laceration)
//  http://www.hiveworkshop.com/forums/spells-569/lightning-speed-laceration-1-09-a-178653/
// 
//  Triggers Required:
//      RegisterPlayerUnitEvent, SpellEffectEvent
//      UnitFadeSystem
//      SharedList
//      Functions
//  Imports Required:
//      Illusion Dummy
//      Lacerate Ability
//
//===============================================     

scope SentryLacerate

    globals
                                                                            // Effect to be made on each hit
        private constant string FX                  = "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl"
        private constant boolean MELEE              = false                 // Is it a melee attack?    
        private constant boolean RANGED             = true                  // Is it a ranged attack?
        
        private constant real SPACE_APART           = 95.00                 // Distance between created illusions and target unit
        
        private constant timer TMR                  = CreateTimer()
        private constant real PERIOD                = 0.2                   // Time between each hit
        
        private constant integer F_START            = 0xc864ffff
        private constant integer F_END              = 0x00000000
        private constant real    F_TIME             = 1.35                  // Time it takes to fade
    endglobals
        
    private function damage takes unit u returns real                       // Damage dealt per strike
        return ((GetUnitAbilityLevel(u, LAC_ID) * .10) + .55) * GetHeroAgi(u, true)
    endfunction
    
    private function hits takes unit u returns integer                      // Amount of hits
        return GetRandomInt(GetUnitAbilityLevel(u, LAC_ID), GetUnitAbilityLevel(u, LAC_ID) + 1)
    endfunction
    
//========================================================
//
    
    private struct Hit extends array
        implement SharedList
        unit cast
        unit targ
        player play
        integer id
        integer count
        
        static thistype l
        
        static method looping takes nothing returns nothing
            local thistype this = l.first
            local thistype nodeNext
            local real x
            local real y
            local real ang
            local unit d
            
            loop
                exitwhen this == l.sentinel
                set nodeNext = .next
                //
                
                if .count == 0 then
                    set .cast = null
                    set .targ = null
                    set .play = null
                    
                    call l.pop()
                else
                    // Deal with creation of illusion and fade stuff First
                    set ang = GetAtan(GetUnitX(.targ), GetUnitY(.targ), GetUnitX(.cast), GetUnitY(.cast))
                    set x = GetUnitX(.targ) + SPACE_APART * Cos(ang)
                    set y = GetUnitY(.targ) + SPACE_APART * Sin(ang)
                    set ang = ang * bj_RADTODEG - 180.
                    set d = CreateUnit(.play, .id, x, y, ang)
                    call FadeUnitStart(d, F_START, F_END, F_TIME, true)
                    call SetUnitAnimation(d, "attack")
                    call QueueUnitAnimation(d, "stand")
                    set d = null
                    
                    // Deal damage afterwards
                    call UnitDamageTarget(.cast, .targ, damage(.cast), MELEE, RANGED, ATK_TYPE, DMG_TYPE, WPN_TYPE)
                    call DestroyEffect(AddSpecialEffectTarget(FX, .targ, "origin"))
                    
                    set .count = .count - 1
                endif
                
                //
                
                set this = nodeNext
            endloop
            
            if l.first == sentinel then
                call PauseTimer(TMR)
            endif
        endmethod
        
        static method alloc takes nothing returns nothing
            local thistype this = l.enqueue()
            //
            
            set .cast = GetTriggerUnit()
            set .play = GetOwningPlayer(.cast)
            set .targ = GetSpellTargetUnit()
            set .id   = ILLU_ID
            set .count = hits(.cast)
            
            //
            
            if this == l.first then
                call TimerStart(TMR, PERIOD, true, function thistype.looping)
            endif
        endmethod
        
        static method onInit takes nothing returns nothing
            set l = thistype.create()
            call RegisterSpellEffectEvent(LAC_ID, function thistype.alloc)
        endmethod
        
    endstruct
    
endscope
JASS:
//===============================================
//
//          Lacerate
//  idea and original skill by Maker (Lighting Speed Laceration)
//  http://www.hiveworkshop.com/forums/spells-569/lightning-speed-laceration-1-09-a-178653/
// 
//  Triggers Required:
//      RegisterPlayerUnitEvent, SpellEffectEvent
//      UnitFadeSystem
//      TimerTools
//      Functions
//  Imports Required:
//      Illusion Dummy
//      Lacerate Ability
//
//===============================================     

scope SentryLacerate

    globals
                                                                            // Effect to be made on each hit
        private constant string FX                  = "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl"
        private constant boolean MELEE              = false                 // Is it a melee attack?    
        private constant boolean RANGED             = true                  // Is it a ranged attack?
        
        private constant real SPACE_APART           = 95.00                 // Distance between created illusions and target unit
        
        private constnat timer TMR                  = CreateTimer()
        private constant real PERIOD                = 0.2                   // Time between each hit
        
        private constant integer F_START            = 0xc864ffff
        private constant integer F_END              = 0x00000000
        private constant real    F_TIME             = 1.35                  // Time it takes to fade
    endglobals
        
    private function damage takes unit u returns real                       // Damage dealt per strike
        return ((GetUnitAbilityLevel(u, LAC_ID) * .10) + .55) * GetHeroAgi(u, true)
    endfunction
    
    private function hits takes unit u returns integer                      // Amount of hits
        return GetRandomInt(GetUnitAbilityLevel(u, LAC_ID), GetUnitAbilityLevel(u, LAC_ID) + 1)
    endfunction
    
//========================================================
//
    
    private struct Hit extends array
        implement SharedList
        unit cast
        unit targ
        player play
        integer id
        integer count
        
        static thistype l
        
        static method looping takes nothing returns nothing
            local thistype this = l.first
            local real x
            local real y
            local real ang
            local unit d
            
            loop
                exitwhen this == l.sentinel 
                
                //
                
                if .count == 0 then
                    set .cast = null
                    set .targ = null
                    set .play = null
                    
                    call l.dequeue()
                else
                    // Deal with creation of illusion and fade stuff First
                    set ang = GetAtan(GetUnitX(.targ), GetUnitY(.targ), GetUnitX(.cast), GetUnitY(.cast))
                    set x = GetUnitX(.targ) + SPACE_APART * Cos(ang)
                    set y = GetUnitY(.targ) + SPACE_APART * Sin(ang)
                    set ang = ang * bj_RADTODEG - 180.
                    set d = CreateUnit(.play, .id, x, y, ang)
                    call FadeUnitStart(d, F_START, F_END, F_TIME, true)
                    call SetUnitAnimation(d, "attack")
                    call QueueUnitAnimation(d, "stand")
                    set d = null
                    
                    // Deal damage afterwards
                    call UnitDamageTarget(.cast, .targ, damage(.cast), MELEE, RANGED, ATK_TYPE, DMG_TYPE, WPN_TYPE)
                    call DestroyEffect(AddSpecialEffectTarget(FX, .targ, "origin"))
                    
                    set .count = .count - 1
                endif
                
                //
                
                set this = l.next
            endloop
        endmethod
        
        static method alloc takes nothing returns nothing
            set this = l.enqueue
            //
            
            set .cast = GetTriggerUnit()
            set .play = GetOwningPlayer(.cast)
            set .targ = GetSpellTargetUnit()
            set .id   = ILLU_ID
            set .count = hits(.cast)
            
            //
            
            call TimerStart(TMR, PERIOD, true, function thistype.looping)
        endmethod
        
        static method onInit takes nothing returns nothing
            local l = thistype.create()
            call RegisterSpellEffectEvent(LAC_ID, function thistype.alloc)
        endmethod
        
    endstruct
    
endscope
JASS:
//===============================================
//
//          Default Lacerate
//
//  Attack just orders units to "attack" any enemy units
//  that have been right clicked by a hero unit.
//  Mainly for Scythe, since he doesn't have an auto attack.
//
//      Required Triggers:
//          RegisterPlayerUnitEvents
//
//===============================================

library DefaultLac initializer init requires RegisterPlayerUnitEvent
//===============================================
//

    private function convertOrder takes nothing returns boolean
        local unit hero = GetTriggerUnit()
        local unit target = GetOrderTargetUnit()
        local player pl = GetOwningPlayer(hero)
        
        if OrderId2String(GetIssuedOrderId()) == SMART_S and IsUnitEnemy(target, pl) then
            call IssueTargetOrder(hero, LAC_ORDER_S, target)
        endif
        
        set hero = null
        set target = null
        set pl = null
        
        return false 
    endfunction
    
    private function init takes nothing returns nothing
        call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, function convertOrder)
    endfunction

endlibrary
JASS:
//===============================================
//
//          Shade
//  Original skill and idea by ecknovkol in AoS (SOTIS) sc2
//  
//  Required Triggers:
//      RegisterPlayerUnitEvent, SpellEffectEvent
//      UnitFadeSystem
//      GetClosestWidget
//      BoundSentinel
//      TerrainPathability
//      Functions
//  Required Objects:
//      Shade Ability
//      Illusion Dummy
//
//===============================================

scope SentryShade initializer init

    globals
                                                                        // Effect to be made in initial caster's location
        private constant string FX          = "Abilities\\Spells\\NightElf\\Blink\\BlinkCaster.mdl"
        private constant string DFX         = "Abilities\\Spells\\Orc\\Disenchant\\DisenchantSpecialArt.mdl"
                                                                        // Effect displayed on damaged units
        
        private constant boolean ALLOW_CLIFFBLINK       = false         // Allows unit to blink to different cliff levels
        private constant boolean ALLOW_TREEBLINK        = false         // Prevents unit from blinking to area with lots of trees and getting stuck
        
        private constant integer F_START    = 0xc864ffff
        private constant integer F_END      = 0x0064ffff
        private constant real F_TIME        = 1.35                      // Time it takes to fade
        private constant real SCALE         = 3.                        // Size of illusion 
        
        private group g     = CreateGroup()                             
        private unit fog    = null
    endglobals
    
    private function damage takes unit u returns real                   // Damage dealt
        return (GetUnitAbilityLevel(u, SHADE_ID) * 1. + 1.0) * GetHeroAgi(u, true)
    endfunction
    
    private function aoe takes unit u returns real                      // Aoe damage is dealt to
        return 200.
    endfunction
    
    private function damagePoint takes unit u returns real              // How far is the center of damage from caster
        return 175.
    endfunction     
    
    private function blinkPoint takes unit u returns real               // How far is the unit going to blink foward
        return 350.
    endfunction
    
//===========================================================
//
    
    private function cond takes nothing returns nothing
        local unit cast         = GetTriggerUnit()
        local player play       = GetOwningPlayer(cast)
        local real ang          = GetUnitFacing(cast) * bj_DEGTORAD
        local real x            = GetUnitX(cast) + damagePoint(cast) * Cos(ang)
        local real y            = GetUnitY(cast) + damagePoint(cast) * Sin(ang)
        local unit illu         = CreateUnit(play, ILLU_ID, x, y, ang * bj_RADTODEG)
        
        call FadeUnitStart(illu, F_START, F_END, F_TIME, true)
        call SetUnitScale(illu, SCALE, SCALE, SCALE)
        call SetUnitAnimation(illu, "attack")
        call QueueUnitAnimation(illu, "stand")
        
        call GroupEnumUnitsInRange(g, x, y, aoe(cast), null)
        loop
            set fog = FirstOfGroup(g)
            exitwhen fog == null
            if IsUnitEnemy(fog, play) and UnitAlive(fog) then
                call UnitDamageTarget(cast, fog, damage(cast), false, false, ATK_TYPE, DMG_TYPE, WPN_TYPE)
                call AddEffectTarget(DFX, fog, "origin", 1.0)
            endif
            call GroupRemoveUnit(g, fog)
        endloop
        
        call DestroyEffect(AddSpecialEffect(FX, GetUnitX(cast), GetUnitY(cast)))
        set x    = GetUnitX(cast) + blinkPoint(cast) * Cos(ang)
        set y    = GetUnitY(cast) + blinkPoint(cast) * Sin(ang)
        
        if IsTerrainWalkable(x, y) then
            if not ALLOW_TREEBLINK then
                if GetClosestDestructableInRange(x, y, 150., true, null) == null then
                    if not ALLOW_CLIFFBLINK then 
                        if GetTerrainCliffLevel(x, y) == GetTerrainCliffLevel(GetUnitX(cast), GetUnitY(cast)) then
                            call SetUnitX(cast, x)
                            call SetUnitY(cast, y)
                        endif
                    else
                        call SetUnitX(cast, x)
                        call SetUnitY(cast, y)
                    endif
                endif
            endif
        endif
        
        set cast = null
        set illu = null
        set play = null
    endfunction
    
    private function init takes nothing returns nothing
        call RegisterSpellEffectEvent(SHADE_ID, function cond)
    endfunction

endscope
JASS:
//===============================================
//
//          Blur
//  Original idea from God knows where....
//
//  Required Triggers:
//      RegisterPlayerUnitEvent
//      UnitFadeSystem
//      SharedList
//      Unit Indexer, Is Unit Moving
//  Required Objects
//      Blur Ability
//      Illusion Dummy
//
//===============================================

scope SentryBlur

    globals
        private constant integer F_START    = 0xa564ffff
        private constant integer F_END      = 0x0064ffff
        private constant real    F_TIME     = .800              // Time it takes to fade
        
        private constant timer TMR          = CreateTimer()
        private constant real PERIOD        = 0.1625000         // Time in between illusions created
    endglobals
    
//===============================================================
//

    private struct Trail extends array
        implement SharedList
        unit u
        
        static thistype l
        
        static method looping takes nothing returns nothing
            local thistype this = l.first
            local thistype nodeNext
            local unit d = null
            
            loop    
                exitwhen this == l.sentinel
                set nodeNext = .next
                
                //
                
                if UnitAlive(.u) and udg_UnitMoving[GetUnitUserData(u)] then
                    set d = CreateUnit(GetOwningPlayer(u), ILLU_ID, GetUnitX(.u), GetUnitY(.u), GetUnitFacing(.u))
                    
                    call SetUnitAnimationByIndex(d, 6)
                    call FadeUnitStart(d, F_START, F_END, F_TIME, true)
                    
                    set d = null
                elseif not UnitAlive(.u) then
                    set u = null
                    
                    call l.pop()
                endif
                
                //
                
                set this = nodeNext
            endloop
            
            if l.first == l.sentinel then
                call PauseTimer(TMR)
            endif
        endmethod
        
        static method alloc takes nothing returns nothing
            local thistype this = l.enqueue()
        
            set .u = GetTriggerUnit()
            
            if l.first == this then
                call TimerStart(TMR, PERIOD, true, function thistype.looping)
            endif
        endmethod
        
        static method cond takes nothing returns boolean
            local unit u
            
            if GetLearnedSkill() == BLUR_ID then
                set u = GetTriggerUnit()
                if GetUnitAbilityLevel(u, BLUR_ID) == 1 then
                    call thistype.alloc()
                endif
                
                set u = null
            endif
            
            return false 
        endmethod
        
        private static method onInit takes nothing returns nothing
            call RegisterPlayerUnitEvent(EVENT_PLAYER_HERO_SKILL, function thistype.cond)
            set l = thistype.create()
        endmethod
    endstruct
    
endscope
JASS:
//===============================================
//
//          Blur
//  Original idea from God knows where....
//
//  Required Triggers:
//      RegisterPlayerUnitEvent
//      UnitFadeSystem
//      TimerTools
//      Unit Indexer, Is Unit Moving
//  Required Objects
//      Blur Ability
//      Illusion Dummy
//
//===============================================

scope SentryBlur

    globals
        private constant integer F_START    = 0xa564ffff
        private constant integer F_END      = 0x0064ffff
        private constant real    F_TIME     = .800              // Time it takes to fade
        
        private constant real PERIOD        = 0.1625000         // Time in between illusions created
    endglobals
    
//===============================================================
//

    private struct Trail extends array
        implement TimerHead
        unit u
        
        static Timer timer
        static boolexpr oeC
        static integer oeI
        
        static method looping takes nothing returns boolean
            local thistype this = thistype(Timer.expired).first
            local unit d = null
            
            loop    
                exitwhen this == 0 
                
                //
                
                if UnitAlive(.u) and udg_UnitMoving[GetUnitUserData(u)] then
                    set d = CreateUnit(GetOwningPlayer(u), ILLU_ID, GetUnitX(.u), GetUnitY(.u), GetUnitFacing(.u))
                    
                    call SetUnitAnimationByIndex(d, 6)
                    call FadeUnitStart(d, F_START, F_END, F_TIME, true)
                    
                    set d = null
                elseif not UnitAlive(.u) then
                    set u = null
                    
                    set timer = this
                    call timer.destroy()
                    call remove(this)
                endif
                
                //
                
                set this = Timer(this).next
            endloop
            
            return false
        endmethod
        
        static method alloc takes nothing returns nothing
            local thistype this = Timer.create(PERIOD, oeC, oeI)
        
            set .u = GetTriggerUnit()
            
            call add(this)
        endmethod
        
        static method cond takes nothing returns boolean
            local unit u
            
            if GetLearnedSkill() == BLUR_ID then
                set u = GetTriggerUnit()
                if GetUnitAbilityLevel(u, BLUR_ID) == 1 then
                    call thistype.alloc()
                endif
                
                set u = null
            endif
            
            return false 
        endmethod
        
        private static method onInit takes nothing returns nothing
            call RegisterPlayerUnitEvent(EVENT_PLAYER_HERO_SKILL, function thistype.cond)
            
            set oeC = Condition(function thistype.looping)
            set oeI = thistype.looping
        endmethod
    endstruct
    
endscope
JASS:
//===============================================
//
//          Track
//  Original skill by msongyyy
//      
//  Required Triggers:
//      RegisterPlayerUnitEvent, SpellEffectEvent
//      Amplify System
//      Unit Indexer, Damage Engine
//      xefx, xebasic
//  Required Objects:
//      Track Ability
//
//===============================================

scope SentryTrack initializer init

    globals
        private constant string FX              = "Abilities\\Spells\\NightElf\\FaerieFire\\FaerieFireTarget.mdl"
    endglobals                                                      // Effect to be attached to Target

    private function amountBase takes unit u returns real           // Damage multiplier
        return GetUnitAbilityLevel(u, TRACK_ID) * .15 + 1.
    endfunction
    
    private function amountInc takes unit u returns real            // Increase in multiplier per stacking cast
        return GetUnitAbilityLevel(u, TRACK_ID) * .05
    endfunction
    
    private function timeBase takes unit u returns real             // Initial duration
        return 10.00
    endfunction
    
    private function timeInc takes unit u returns real              // Duration increased per stacking cast
        return 7.
    endfunction
    
    private function scaleInc takes unit u returns real             // Increase of effect size per stacking cast
        return .25
    endfunction
    
//==========================================================
//
    
    private function cond takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local unit t = GetSpellTargetUnit()
        local Amplify a = Amplify.hasBuff(t)
        
        if a != 0 then
            set a.addMult = amountInc(u)
            set a.addTime = timeInc(u)
            set a.addSize = scaleInc(u)
        else
            call Amplify.alloc(t, amountBase(u), FX, timeBase(u))
        endif
        
        set u = null
        set t = null
    endfunction
    
    private function init takes nothing returns nothing
        call RegisterSpellEffectEvent(TRACK_ID, function cond)
    endfunction
endscope
JASS:
//===============================================
//          Trance
//  Original skill by msongyyy
//  
//  Required Triggers:
//      RegisterPlayerUnitEvent
//  Required Objects:
//      Lacerate Ability
//      Trance Ability
//  
//===============================================

scope SentryTrance initializer init 

    globals
        private constant real SPEED_INC         = 25.00
        
        private constant integer LAC_LEVEL_INC  = 1
    endglobals
    
//=============================================================
//

    private function cond takes nothing returns nothing
        local unit u
        
        if GetLearnedSkill() == TRANCE_ID then
            set u = GetTriggerUnit()
            
            call SetUnitMoveSpeed(u, GetUnitMoveSpeed(u) + SPEED_INC)
            call SetUnitAbilityLevel(u, LAC_ID, GetUnitAbilityLevel(u, LAC_ID)+ LAC_LEVEL_INC)
            
            set u = null
        endif
    endfunction
    
    private function init takes nothing returns nothing
        call RegisterPlayerUnitEvent(EVENT_PLAYER_HERO_SKILL, function cond)
    endfunction
    
endscope

I know there are lots of ways to improve this guy, so I will take lots of time working off feedbacks.


I've uploaded a new, revamped version of Scythe coded in Wurst.
The additional wurst files required are added on a post below. All spells are MUI of course.
Thanks to:
Frotty, Peq, Muzzel, Crigges(Helpd me quite a bit) for Wurst
Looking_For_Help for DamageEvent
Maker for Original Lacerate Spell
Ecknovkol for Original Shade Spell
JetFangInferno for SpiralAura.mdx


JASS:
package Lacerate

	import DamageEvent
	import Colors
	import PeriodicModule
	import FadeUnit
	
	// Scythe is able to attack her enemies 4 times in a single strike. 
	// Each strike deals 35% of her normal damage.
	
	// Requirements
	// General: Wurst installed correctly and wurst editor
	// WurstCodes: DamageEvent, PeriodicModule, FadeUnit, Colors and Wurst packages
	// ObjectEditor: Scythe Illu(unit), Lacerate(ability)
	
	// Instructions
	//		- Give your hero Lacerate(ability)
	//		- Set required configs correctly
	
	// Required configs
	// ===============================================================
	// abilId		= Lacerate ability
	// illuId		= Scythe Illu unit
	
	constant int abilID = 'A000'
	constant int illuID = 'e001'
	
	//
	// End of required configs
	
	// Start of spell configurables
	// ============================================================================
	// cStart		= Starting color of fade
	// cEnd			= Ending color of fade
	// cTime		= Fade time
	
	// fxPath		= Effect displayed on target unit
	
	// dtype		= Damage type
	// atype		= Attack type
	//		** NOTE: the damage and attack type combination must produce a non physical damageType 
	//				 in DamageEvent. Otherwise, Lacerate will run itself forever and crash the game.
	
	// counts		= Amount of hits
	// damage		= Damage to deal (mine does in comparison to amount from DamageEvent)
	
	constant colorA cStart = colorA(150, 235, 235, 255)
	constant colorA cEnd = colorA(0, 0, 0, 0)
	constant real cTime = 1.0
	
	constant string fxPath = "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl"
	
	constant damagetype dtype = DAMAGE_TYPE_UNKNOWN
	constant attacktype atype = ATTACK_TYPE_NORMAL
	
	function counts() returns int
		return 4
		
	function damage(real amt) returns real
		return amt * .35
		
	//
	// End of spell configurables
	
	class Lacerate
		use PeriodicModule
		unit cast
		unit targ
		int count
		real dmg
		
		protected static constant real ANIMATION_PERIOD = 0.1500
		
		override function onTimedLoop()
			unit d
			real x
			real y
			angle ang
		
				
			if this.count == 0 or not this.targ.isAlive()
				this.cast = null
				this.targ = null
				this.stopPeriodicAndDestroy()
			else
				ang = angleBetweenCoords(this.cast.getX(), this.cast.getY(), this.targ.getX(), this.targ.getY())
				x = polarProjectionX(this.targ.getX(), -95., ang)
				y = polarProjectionY(this.targ.getY(), -95., ang)
				d = CreateUnit(GetOwningPlayer(this.cast), illuID, x, y, ang.degrees())
				d.setAnimation("attack")
				// this.cast.damageTarget(this.targ, this.dmg) deals physical damage -_-;;
				UnitDamageTarget(this.cast, this.targ, this.dmg, false, false, atype, dtype, WEAPON_TYPE_WHOKNOWS)
				AddSpecialEffectTarget(fxPath, this.targ, "origin").destr()
				d.queueAnimation("stand")
				new FadeUnit(d, cStart, cEnd, cTime, true)
				this.count = this.count - 1
			
		construct (unit u, unit t, real amt)
			this.dmg = damage(amt)
			this.cast = u
			this.targ = t
			this.count = counts()
		
			this.startPeriodic()
			
	function onAttack()
		if source.getAbilityLevel(abilID) > 0 and damageType == DamageType.PHYSICAL
			new Lacerate(source, target, amount)
			amount = 0.
			
	init
		addDamageHandler(function onAttack)
		Lacerate.setPeriod(Lacerate.ANIMATION_PERIOD)
JASS:
package Shade

	import SpellEffectEvents
	import PeriodicModule
	import FadeUnit
	
	player referencePlayer = null
	
	// Scythe makes her way ellusively through wild hostiles on the fields - slashing all those who come inbetween. 
	// Deals damage in a 205 aoe 205 distance in front of her and blinks 410 distance forward.
	   
	// Requirements
	// General: Wurst installed correctly and wurst editor
	// WurstCodes: PeriodicModule, FadeUnit, SpellEffectEvents and Wurst packages
	// ObjectEditor: Scythe Illu(unit), Shade(ability), Shade Disabled(ability), Shade Learn(ability), Show Shade Charges(ability)
	// 			     Show Shade Charges(buff)
	
	// Instructions
	// 		- Give your hero only the Shade Learn(ability)
	//		- Make sure Show Shade Charges(ability) buff data is set to Show Shade Charges(buff)
	//		- Set required configurables correctly
	
	// Required configs
	// ===========================================================
	// abilId 		= Castable ability
	// disAbilId 	= Ability icon that shows up when disabled
	// illuId  		= Scythe illusion ID
	// showId		= Show Charges ability
	// buffId		= Show Charges buff
	// learnId		= Dummy learn ability
	
	constant int abilId 		= 'A005'	
	constant int disAbilId 		= 'A006'
	constant int illuId 		= 'e001'
	constant int showId 		= 'A00A'
	constant int buffId 		= 'B000'
	constant int learnId 		= 'A00B'
	
	//
	// End of required configs
	
	
	// Start of spell configurables
	//========================================================================
	// fxPath		= Effect displayed when units are damaged 
	// blinkPath	= Effect displayed where the caster used to be
	
	// cStart		= Starting fade color of Giant Scythe
	// cEnd			= Ending fade color of Giant Scythe
	// cTime		= How long it takes to fade
	
	// textColor 	= Color of Shade Charges Text
	// textSize		= Size of Shade Charges Text
	
	// dtype		= Damage type
	// atype		= Attack type
	
	// damage		= How much damage does it deal
	// blinkDist	= How far does the caster blink
	// damagePoint	= How far from the caster to deal damage
	// damageAoe	= Area of damage dealt
	
	constant string fxPath 		= "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl"
	constant string blinkPath 	= "Abilities\\Spells\\NightElf\\Blink\\BlinkCaster.mdl"
	
	constant colorA cStart = colorA(150, 235, 235, 255)
	constant colorA cEnd = colorA(150, 235, 235, 0)
	constant real cTime = 1.0
	
	constant colorA textColor = colorA(150, 200, 150, 200)
	constant real textSize = 12.
	
	constant damagetype dtype = DAMAGE_TYPE_UNKNOWN
	constant attacktype atype = ATTACK_TYPE_NORMAL
	
	function damage(unit u) returns real
		return 5. * u.getAbilityLevel(abilId) + ((.1 + .1 * u.getAbilityLevel(abilId)) * GetHeroAgi(u, true))
		
	function blinkDist() returns real
		return 410.
		
	function damagePoint() returns real
		return 205.
		
	function damageAoe() returns real
		return 205.
	
	//
	// End of spell configurables
	
	class Charges
		use PeriodicModule
		unit u
		int cc
		int mc
		int abil
		int disAbil
		real time
		real reTime
		texttag tag
		
		protected constant static real ANIMATION_PERIOD = .02

		override function onTimedLoop()
			string s = ""
			
			if cc < mc
				if time <= 0.
					cc++
					if cc < mc
						time = reTime
						if cc == 1
							u.removeAbility(disAbilId)
							u.addAbility(abilId)
							u.setAbilityLevel(abilId, u.getAbilityLevel(learnId))
							UnitMakeAbilityPermanent(u, true, abilId)
				else
					time -= ANIMATION_PERIOD
					
			if time <= 0.
				time = 0.
				
			if GetLocalPlayer() == u.getOwner() and u.hasAbility(buffId)
				s = I2S(cc) + "(" + R2SW(time, 1,1) + ")"
			tag.setText(s, textSize)
			tag.setPos(vec3(u.getX()+25., u.getY(), 25))
				
				
		private static function get(unit u) returns thistype
			thistype n = first
			
			while n != null
				if n.u == u
					return n
				n = n.getNext()
				
			return n
			
		static function check(unit u)
			thistype n = get(u)
			
			n.cc = n.cc - 1
			
			if n.cc == 0
				UnitMakeAbilityPermanent(u, false, abilId)
				u.removeAbility(abilId)
				u.addAbility(disAbilId)
			else if n.cc == n.mc - 1
				n.time = n.reTime
			
		construct(unit u, int mc, real reTime, int sC, int abil, int disAbil)
			this.u = u
			this.cc = sC
			this.mc = mc
			this.reTime = reTime
			this.time = 0.
			this.abil = abil
			this.disAbil = disAbil
			this.tag = CreateTextTag()
			
			tag.setColor(textColor)
			
			
			this.startPeriodic()
		
	function filter() returns boolean
		return IsUnitEnemy(GetFilterUnit(), referencePlayer) and GetFilterUnit().isAlive()
		
	function onCast(unit u, int lvl)
		angle ang = u.getFacing().asAngleDegrees()
		real nx = polarProjectionX(u.getX(), damagePoint(), ang)
		real ny = polarProjectionY(u.getY(), damagePoint(), ang)
		
		unit d = CreateUnit(u.getOwner(), illuId, nx, ny, ang.degrees())
		new FadeUnit(d, cStart, cEnd, cTime, true)
		d.setAnimation("attack")
		d.queueAnimation("stand")
		d.setTimeScale(.65)
		d.setScale(3.5)
		
		AddSpecialEffect(blinkPath, u.getX(), u.getY()).destr()
		
		group g = CreateGroup()
		referencePlayer = u.getOwner()
		g.enumUnitsInRange(vec2(nx, ny), 205., Filter(function filter))
		real dmg = damage(u)
		while g.hasNext()
			unit fg = g.next()
			UnitDamageTarget(u, fg, dmg, false, false, atype, dtype, WEAPON_TYPE_WHOKNOWS)
			AddSpecialEffectTarget(fxPath, fg, "origin").destr()
		g.destr()
		
		nx = polarProjectionX(u.getX(), blinkDist(), ang)
		ny = polarProjectionY(u.getY(), blinkDist(), ang)
		u.setX(nx)
		u.setY(ny)
		Charges.check(u)
		
	function onLearn() returns boolean
		unit u = GetTriggerUnit()
		
		if GetLearnedSkill() == learnId
			if u.getAbilityLevel(learnId) == 1
				u.addAbility(showId)
				u.addAbility(abilId)
				new Charges(u, 3, 6., 1, abilId, disAbilId)
			else
				u.setAbilityLevel(abilId, u.getAbilityLevel(learnId))
			
		return false
		
	init
		CreateTrigger()
			..registerAnyUnitEvent(EVENT_PLAYER_HERO_SKILL)
			..addCondition(Condition(function onLearn))
		Charges.setPeriod(Charges.ANIMATION_PERIOD)
		onSpellEffect(abilId, (unit caster, int lvl) ->
			onCast(caster, lvl))
JASS:
package Blur

	import Colors
	import PeriodicModule
	import FadeUnit
	import FearSystem
	import DamageEvent
	import SpellEffectEvents
	import HashMap
	
	// Scythe moves with so much alacrity, that she leaves trails of images behind her. 
	// On cast, Scythe turns temporarily invisible and faster while creating illusions of herself 
	// that walk in various directions causing confusion in her surroundings.
	
	// Requirements
	// General: Wurst installed correctly, Wurst Editor
	// WurstCodes: Colors, PeriodicModule, FadeUnit, FearSystem, SpellEffectEvents, DamageEvent and Wurst packages
	// ObjectEditor: Scythe Illu(unit), Blur(ability), Blur(buff)
	
	// Instructions
	// 		- Give your hero Blur(ability)
	//		- Make sure Blur(ability) has buff data set to Blur(buff)
	//		- Set required configs correctly
	
	// Required configs
	// ============================================================
	// abilId = Blur ability
	// illuId = Scythe Illu unit
	
	constant integer abilId = 'A004'
	constant integer illuId = 'e001'
	
	//
	// End of configs
	
	// Start of spell configurables
	// ============================================================================
	// cStart		= Starting color of fade
	// cEnd			= Ending color of fade
	// cTime		= Fade time
	
	// evasion		= Evasion chance per levl
	
	constant colorA cStart = colorA(150, 235, 235, 255)
	constant colorA cEnd = colorA(150, 235, 235, 0)
	constant real cTime = .7
	
	function evasion(int i) returns int
		return i * 7
	//
	// End of spell configurables
	
	class Blur
		use PeriodicModule
		protected constant static real ANIMATION_PERIOD = 0.15
		protected static HashMap<int, thistype> hash = new HashMap<int, thistype>()
		unit u
		real x
		real y
		real ang
		int ev
		boolean removeOnDeath
		
			
		override function onTimedLoop()
			if this.u.isAlive()
				if this.u.getX() != this.x or this.u.getY() != this.y
					unit d = CreateUnit(GetOwningPlayer(this.u), illuId, u.getX(), u.getY(), this.ang)
					new FadeUnit(d, cStart, cEnd, cTime, true)
					SetUnitAnimationByIndex(d, 6)
				this.x = this.u.getX()
				this.y = this.u.getY()
				this.ang = this.u.getFacing()
			else if this.removeOnDeath
				stopPeriodicAndDestroy()
				
		construct(unit u, boolean rod)
			this.u = u
			this.x = u.getX()
			this.y = u.getY()
			this.ang = u.getFacing()
			this.removeOnDeath = rod
			hash.put(u.getHandleId(), this)
			
			this.startPeriodic()
			
	function onLearn() returns boolean
		unit u = GetTriggerUnit()
		
		if GetLearnedSkill() == abilId
			if u.getAbilityLevel(abilId) == 1
				new Blur(u, false)
				
			Blur b = Blur.hash.get(u.getHandleId())
			b.ev = evasion(u.getAbilityLevel(abilId))
		return false
		
	function onCast(unit u, int lvl)
		int i = lvl * 3 + 1
		unit dd
		while i != 0
			dd = CreateUnit(GetOwningPlayer(u), illuId, u.getX(), u.getY(), GetRandomReal(0, 360))
			new Blur(dd, true)
			new FadeUnit(dd, cStart, cEnd, lvl * 2.5 + 5, true)
			new Fear(dd, lvl * 2.5 + 5.)
			i--
		
	function onDamaged()
		Blur b = Blur.hash.get(target.getHandleId())
		
		if b != null and GetRandomInt(1, 100) <= b.ev
			amount = 0.
			texttag t = CreateTextTag()
			t.setText("miss", 10)
			t.setColor(colorA(255, 20, 20, 0))
			t.setVelocity(0, 0.05)
			t.setAge(0.)
			t.setPermanent(false)
			t.setLifespan(2.5)
			t.setFadepoint(0.)
			t.setPos(target.getX()+ 25., target.getY(), target.getFlyHeight() + 50.)
	init
		addDamageHandler(function onDamaged)
		CreateTrigger()
			..registerAnyUnitEvent(EVENT_PLAYER_HERO_SKILL)
			..addCondition(Condition(function onLearn))
		Blur.setPeriod(Blur.ANIMATION_PERIOD)
		onSpellEffect(abilId, (unit caster, int lvl) ->
			onCast(caster, lvl))
JASS:
package Trance

	import HashMap
	import DamageEvent
	import Colors
	
	// Scythe's concentration on the fields are unmatched. 
	// Her enemies stand in awe and terror, watching the grace of Scythe's coordination in full movement. 
	// Her battle trance unraveling upon each individual, as they renounce their unfateful encounter.
	
	// Requirements
	// General: Wurst installed correctly, WurstEditor
	// WurstCodes: HashMap, DamageEvent, Colors and Wurst packages
	// ObjectEditor: Trance(ability), Trance Passive(ability), Trance(buff)
	// ImportManager: SpiralAura.mdx(model)
	
	// Instructions
	//		- Trance Passive ability has Trance buff
	//		- Trance ability is given to your hero
	//		- Trance Passive ability aura model set to SpiralAura.mdx
	//		- Set up configs
	
	// Required configs
	// ==================================================================
	// abilId 	= Trance ability
	// passId 	= Trance passive ability
	
	constant int abilId = 'A007'
	constant int passId = 'A003'
	//
	// End of required configs
	
	// Start of spell configurables
	// =======================================================================
	// chance 		= Chance to crit, 1 out of 100
	// critDamage   = Crit multiplier, should be over 1.00
	
	function chance(int i) returns int
		return i * 10 + 15
		
	function critDamage(int i) returns real
		return i * .2 + 1.
		
	//
	// End of spell configurables
	
	public class Trance
		protected static HashMap<int, thistype> hash = new HashMap<int, thistype>()
		unit u
		int cc
		real cd
		
		construct(unit u, int cc, real cd)
			this.u = u
			this.cc = cc
			this.cd = cd
			
			hash.put(u.getHandleId(), this)
			
	function onLearn() returns boolean
		unit u = GetTriggerUnit()
		
		if GetLearnedSkill() == abilId
			if u.getAbilityLevel(abilId) == 1
				u.addAbility(passId)
				new Trance(u, 0, 0)
			else
				u.setAbilityLevel(passId, abilId)
				
			Trance n = Trance.hash.get(u.getHandleId())
			n.cc = chance(u.getAbilityLevel(abilId))
			n.cd = critDamage(u.getAbilityLevel(abilId))
		return false
		
	function onDamaged()
		Trance n = Trance.hash.get(source.getHandleId())
		
		if n != null and amount >= .1
			if GetRandomInt(1, 100) <= n.cc
				amount = amount * n.cd
				texttag t = CreateTextTag()
				t.setText("Crit: " + R2SW(amount, 1, 1) + "1", 10)
				t.setColor(fromPlayer(source.getOwner()).withAlpha(255))
				t.setVelocity(0, 0.05)
				t.setPos(vec3(target.getX() + 25., target.getY(), target.getFlyHeight()))
				t.setAge(0.)
				t.setFadepoint(0.)
				t.setLifespan(2.0)
				t.setPermanent(false)
			
	init
		CreateTrigger()
			..registerAnyUnitEvent(EVENT_PLAYER_HERO_SKILL)
			..addCondition(Condition(function onLearn))
		addDamageHandler(function onDamaged)


JASS:
package ShadowLock

	import PeriodicModule
	import FadeUnit
	import SpellEffectEvents
	import StunSystem
	
	
	// Scythe channels her dark energies to lock down a single unit within a prison of shadows - rendering all control useless. 
	// Target unit is stunned and dealt damage over time for a short duration.
	   
	// Requirements
	// General: Wurst installed correctly and wurst editor
	// WurstCodes: PeriodicModule, FadeUnit, SpellEffectEvents, StunSystem and Wurst packages
	// ObjectEditor: Scythe Illu(unit), ShadowLock(ability)
	
	// Instructions
	// 		- Give your hero ShadowLock(ability)
	//		- Set required configurables correctly
	
	// Required configs
	// =================================================================
	// abilId = ShadowLock ability
	// illuId = Scythe Illu unit
	
	constant int abilId = 'A008'
	constant int illuId = 'e001'
	
	//
	// End of required configs
	
	
	// Start of spell configurables
	// =================================================================
	// cS	 	= Starting color of fade
	// cE 		= Ending color of fade
	// cT		= Fade time
	
	// fxPath	= Effect displayed on target
	// maxCount	= Amount of illusions to show up
	
	constant colorA cS = colorA(25, 50, 50, 200)
	constant colorA cE   = colorA(0, 0, 0, 0)
	constant real cT = .7
	
	constant string fxPath = "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl"
	constant int maxCount = 5
	
	//
	// End of spell configurables
	
	class ShadowLock
		use PeriodicModule
		unit cast
		unit targ
		unit array[maxCount] illusions
		real dmg
		real endTime
		real curTime
		protected constant static real ANIMATION_PERIOD = 0.1
		
		override function onTimedLoop()
			if this.curTime >= this.endTime or not this.targ.isAlive()
				int i = 0
				while i != maxCount
					this.illusions[i].setTimeScale(1.)
					new FadeUnit(this.illusions[i], cS, cE, cT, true)
					i++
					
					this.stopPeriodicAndDestroy()
			else if this.curTime == .2
				int i = 0
				while i != maxCount
					this.illusions[i].setTimeScale(.02)
					i++
					
			if this.targ.isAlive()
				AddSpecialEffectTarget(fxPath, this.targ, "origin").destr()
				
			this.curTime = this.curTime + ANIMATION_PERIOD
			this.cast.damageTarget(this.targ, this.dmg)
				
		construct(unit cast, unit targ, int lvl)
			this.cast = cast
			this.targ = targ
			this.endTime = lvl * 1. + 1.5
			this.curTime = 0.
			this.dmg = ((150 + 50. * cast.getAbilityLevel(abilId)) *ANIMATION_PERIOD)/endTime
			
			new Stun(targ, this.endTime, false)
			
			int i = 0
			real x
			real y
			real r = 360./maxCount
			angle ang
			while i != maxCount
				ang = (r*i).asAngleDegrees()
				x = polarProjectionX(targ.getX(), 95., ang)
				y = polarProjectionY(targ.getY(), 95., ang)
				ang = angleBetweenCoords(x, y, targ.getX(), targ.getY())
				this.illusions[i] = CreateUnit(GetOwningPlayer(cast), illuId, x, y, ang.degrees())
				this.illusions[i].setVertexColor(cS)
				this.illusions[i].setAnimation("attack")
				i++
				
			this.startPeriodic()
	init
		ShadowLock.setPeriod(ShadowLock.ANIMATION_PERIOD)
		onSpellUnitEffect(abilId, (unit caster, int lvl, unit target) ->
			new ShadowLock(caster, target, lvl))
Wurst Post



Keywords:
Sentry Scythe slash lacerate maker cool blood wtf msongyyy ownage wurst
Contents

Scythe (Wurst) (Map)

Reviews
17:16, 23rd Oct 2013 PurgeandFire: Changes made. Approved. (Old) Review: http://www.hiveworkshop.com/forums/2435676-post26.html

Moderator

M

Moderator

17:16, 23rd Oct 2013
PurgeandFire: Changes made. Approved.

(Old) Review:
http://www.hiveworkshop.com/forums/2435676-post26.html
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
I've skimmed through the scripts, and I was awed. The scripts are well indented and easy to read.

I've also noticed this:
JASS:
        set ang  = GetUnitFacing(cast)
        set x    = GetUnitX(cast) + damagePoint(cast) * Cos(ang * bj_DEGTORAD)
        set y    = GetUnitY(cast) + damagePoint(cast) * Sin(ang * bj_DEGTORAD)
        ...
        set x    = GetUnitX(cast) + blinkPoint(cast) * Cos(ang * bj_DEGTORAD)
        set y    = GetUnitY(cast) + blinkPoint(cast) * Sin(ang * bj_DEGTORAD)

        // could be written as this:
        set ang  = GetUnitFacing(cast)*bj_DEGTORAD
        set x    = GetUnitX(cast) + damagePoint(cast) * Cos(ang)
        set y    = GetUnitY(cast) + damagePoint(cast) * Sin(ang)
        ...
        set x    = GetUnitX(cast) + blinkPoint(cast) * Cos(ang)
        set y    = GetUnitY(cast) + blinkPoint(cast) * Sin(ang)
 
i don't know much about jass but i know my english ^^.
Track is not the name of an ability that amplifies damage :)
The name would be more of:
• Marked for Death
• Target for Death
• Inspect Victum (as in knowing week points (might be more of a crit-strike))

track is more of being able to find or follow your target, more than dealing more damage to them.
 
Level 9
Joined
Dec 3, 2010
Messages
162
i don't know much about jass but i know my english ^^.
Track is not the name of an ability that amplifies damage :)
The name would be more of:
• Marked for Death
• Target for Death
• Inspect Victum (as in knowing week points (might be more of a crit-strike))

track is more of being able to find or follow your target, more than dealing more damage to them.

Honestly, it doesn't really matter. It's just the name of a spell, the users can change it as they deem fit.
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
I think what nhocklanhox6 is trying to say is that accessing a global variable will be slower than reading a constant expression.
 
Level 9
Joined
Dec 3, 2010
Messages
162
I think what nhocklanhox6 is trying to say is that accessing a global variable will be slower than reading a constant expression.

I don't think it's worth sacrificing the readability for that small of a thing though.

well, when you use
JASS:
bj_DEGTORAD
, your map will do some logical.
bj_DEGTORAD=3.14159/180=0.0174532, that why don't let it run too much times, just use 0.0174532 instead.

And I'm pretty sure bj_DEGTORAD is already a constant; so no calculations would be involved during run-time.
 
I hate you, huhu why you don't understand me iAyan... whatever :((.

bj_DEGTORAD
Here inside constant bj_DEGTORAD:
constant real bj_DEGTORAD = bj_PI/180.0
Here inside constant bj_PI:
constant real bj_PI = 3.14159

You can see.
bj_DEGTORAD return bj_PI/180.0 and bj_PI return 3.14159 and then
3.14159/180.0 = 0.0174532......

If you test it as text:
call DisplayTextToPlayer(Player(0),0,0,R2S(bj_DEGTORAD))
Here the results: 0.01

Did you see that ?, some logical here.
 
Level 9
Joined
Dec 3, 2010
Messages
162
I hate you, huhu why you don't understand me iAyan... whatever :((.

bj_DEGTORAD
Here inside constant bj_DEGTORAD:
constant real bj_DEGTORAD = bj_PI/180.0
Here inside constant bj_PI:
constant real bj_PI = 3.14159

You can see.
bj_DEGTORAD return bj_PI/180.0 and bj_PI return 3.14159 and then
3.14159/180.0 = 0.0174532......

If you test it as text:
call DisplayTextToPlayer(Player(0),0,0,R2S(bj_DEGTORAD))
Here the results: 0.01

Did you see that ?, some logical here.

Soo, what's wrong with bj_PI/180.0? That's like a one-time calculation; totally worth using it.

The value is 0.01 because R2S rounds at the 3rd decimal point. Try call BJDebugMsg(R2S(bj_DEGTORAD * 10000)). So nope, I don't really see the logic here :/

Edit:
And your test value is 0.017 btw, not 0.01 :p
 
Soo, what's wrong with bj_PI/180.0? That's like a one-time calculation; totally worth using it.

The value is 0.01 because R2S rounds at the 3rd decimal point. Try call BJDebugMsg(R2S(bj_DEGTORAD * 10000)). So nope, I don't really see the logic here :/

Edit:
And your test value is 0.017 btw, not 0.01 :p

No, it's not, one-time call bj_DEGTORAD = one-time calculation
iAya...whatever said:
The value is 0.01 because R2S rounds at the 3rd decimal point. Try call BJDebugMsg(R2S(bj_DEGTORAD * 10000)). So nope, I don't really see the logic here :/

The results is: 174.533, logical logical and logical, did you see that ?, hmm i think you must going to sleep now, you very very tired, i know :D..
 
Level 9
Joined
Dec 3, 2010
Messages
162
No, it's not, one-time call bj_DEGTORAD = one-time calculation

Errr, what? PI is divided by 180 once, then stored in bj_DEGTORAD. Unless you're arguing the speed of reading from a global vs using the numbers directly.

The results is: 174.533, logical logical and logical, did you see that ?, hmm i think you must going to sleep now, you very very tired, i know :D..

Lol, what? I've just told you R2S rounds at 3rd decimal point. Just try multiply by 1000 or 100000. Values will always vary at the 3rd decimal point.
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
Errr, what? PI is divided by 180 once, then stored in bj_DEGTORAD...
How can you confirm this ?

If it's stored once, why do you think the Blizzard put the arithmetic operator (division) there ?

It's like, every time you call the bj_DEGTORAD function, the operation (calculation) will perform, each time.

If you are saying it only perform one-time calculation, the function should look like this;
constant real bj_DEGTORAD = anotherVariableName

That anotherVariableName should handle the bj_PI / 180.0 once.
 
Level 9
Joined
Dec 3, 2010
Messages
162
How can you confirm this ?

If it's stored once, why do you think the Blizzard put the arithmetic operator (division) there ?

It's like, every time you call the bj_DEGTORAD function, the operation (calculation) will perform, each time.

If you are saying it only perform one-time calculation, the function should look like this;
constant real bj_DEGTORAD = anotherVariableName

That anotherVariableName should handle the bj_PI / 180.0 once.

Well, I am doing some assumption here, but I'm pretty sure bj_DEGTORAD is a constant. Constants can only have a single init value and can't be changed. The arithmetic operator was likely there to improve the precision (like how 22/7 is more accurate than 3.14 for PI). Okay maybe 22/7 was a bad example as 22/7 actually does exceed PI, but you get the point, right?

JASS:
// how is the different from...
globals
    private constant real constantA = bj_PI / 180.
endglobals

// this?
globals
    private constant real temp = bj_PI / 180.
    private constant real constantB = temp
endglobals

Both constantA and constantB holds the value of bj_PI / 180.. Why do you say that constantA performs the division every time the variable is used? Unless of course, JASS works that way.
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
How can you confirm this ?
The mathematical operation is evaluated only once when being set to the global variable. The bj global variable (of type integer) holds data, not a mathematical operation of N operands.

If it's stored once, why do you think the Blizzard put the arithmetic operator (division) there ?
- Since bj_PI is defined (with a global variable), why not use it?
- It's easier (more intuitive?) to understand, in the context of identifying the formula being used, instead of using the evaluated value of bj_PI/180.

It's like, every time you call the bj_DEGTORAD function, the operation (calculation) will perform, each time.
No. Boolexpr and code, yes.

If you are saying it only perform one-time calculation, the function should look like this constant real bj_DEGTORAD=anotherVariableName
No.

If you guys want to argue with iAyanami further, pm him/her, or at least put comments and suggestions for the spell in review.
 
Review:
  • In "FadeSystem", move this part:
    JASS:
    if next[0] == 0 then
        call PauseTimer(tmr)
    endif
    Out of the loop. When next[0] == 0 the list is empty. The check only needs to be performed once per timer tick, not once per iteration. If the list is empty, then the loop will end immediately afterward so there is no need to put the check within the loop.
  • In "AmplifySystem", there are a few times where you use GetUnitX/Y(.targ). Since you store them in .fx.x and .fx.y, you can just refer to that instead (unless xe doesn't allow that, I never used xe before).
  • In "Lacerate" in the looping method, you should save the x's and y's into locals so that you don't have to constantly retrieve them.
  • In "Lacerate", you have two angles where you calculate the angle between the two units. If i'm not mistaken, then the second angle can just be:
    set ang = -ang * bj_RADTODEG
    Rather than calculating the arctangent all over again.
  • In "Lacerate", same thing as fade system. You can move the check out of the loop.
  • In "Attack", you should use a general event EVENT_PLAYER_UNIT_ISSUED_ORDER rather than a specific unit event.
    Otherwise you'll leak 1 event per registry (and you'll end up adding the same condition several times).
  • Name "Attack" something more specific. e.g. "SentryAttack". "Attack" is too broad of a name and might confuse the user or interfere with a different system.
  • In "Shade" you can initialize the locals on declaration e.g.:
    local unit cast = GetTriggerUnit()
  • In "Blur", you need to null "u" in "cond". Or you can get rid of u and just input GetTriggerUnit() directly since you only use it once.
  • For "Track", you might want to rename the scope. One of my libraries uses that name (for something completely unrelated to yours). How about "SentryTrack"?

There might be an issue with "Trance" in that the unit might have the ability removed, but I suppose something like that should be left up to the user (I don't think there is much you can do about it). Otherwise, it looks good. I mentioned most of the issues, other things were kind of minor (e.g. iterating through a list vs. using a hashtable to find a unit corresponding to an instance). Good luck with the update.

About the constants thing vs. direct value, I say leave it as a multiplication/division/whatever. It is a lot more intuitive--especially if it is meant to be changed by the user. It is much easier to change a texttag's font size with 13 * 0.023 to the desired font value compared to 0.299.

And GetWidgetX/Y() vs. GetUnitX/Y() is negligible.
 
Top