Frost Arrows v.1.01

CODE:
JASS:
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*   F R O S T   A R R O W S   V 1.01
*
* Written by DualShock (IBornForThis100)
*   [17.02.2012]
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Spell Description:
*   Fires a frost arrow into the sky which explodes and scatters
*   at the center of the point target, showering the target area.
*   Deals amount of damage each.
*
* CREDITS:
* -------
*
*   Vexorian XE libraries:
*       [URL]http://www.wc3c.net/showthread.php?t=101150[URL]
*   
*   - xebasic
*   - xemissile
*   - xecast
*   - xefx
*   - xedamage
*
*   RegisterPlayerUnitEvent by Magtheridon96
*       [URL]http://www.hiveworkshop.com/forums/jass-resources-412/snippet-registerplayerunitevent-203338/[URL]
*   TimerUtils              by Vexorian
*       [URL]http://www.wc3c.net/showthread.php?t=101322[URL]
*   BoundSentinel           by Vexorian
*       [URL]http://www.wc3c.net/showthread.php?t=102576[URL]
*
* HOW TO IMPORT:
* -------------
*
*   - copy spells (Object Editor)
*   - copy dummy unit (Object Editor)
*   - copy dummy.mdx model
*   - copy libraries and spell trigger
*   - edit raw-codes in spell settings, xebasic
*
* UPDATE HISTORY:
* --------------
*   ~ v1.00 First Release.
*   ~ v1.01 optimized code, added comments and import documentation, removed xepreload
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

library FrostArrows uses RegisterPlayerUnitEvent, TimerUtils, SimError, xemissile, xecast, xedamage optional BoundSentinel
    
//*================================================================================
//* C O N F I G U R A T I O N     M E N U
//*================================================================================

    globals
        private constant integer SPELL_ID       = 'A000' //spell raw code 
        private constant integer FROST_NOVA_ID  = 'A001' //dummy spell id
        private constant string  DUMMY_ORDER    = "frostnova" //dummy order
        private constant boolean PRELOAD        = true // preload dummy ability?
        private constant string  ARROW_MODEL    = "Abilities\\Spells\\Other\\FrostArrows\\NagaColdArrowMissile.mdl" //missile fx path
        private constant string  EFFECT         = "Abilities\\Spells\\Undead\\FrostNova\\FrostNovaTarget.mdl" //explode sfx
        private constant real    ARROW_SCALE    = 1. //arrow scale
        private constant real    MAX_HEIGHT     = 500. // explode height 
        private constant real    SPEED          = 800.
        private constant real    ARC            = 0.15 
        private constant real    MIN_DIST       = 300. // min cast range 
        private constant string  ERROR_MSG      = "Inside Minimum Range."  
    endglobals

    private function GetAoE takes integer lvl returns real
        return 400. // spell aoe, must match the object editor field
    endfunction

    private function GetDamage takes integer lvl returns real
        return 25. * lvl // deals damage each arrow
    endfunction

    private function GetArrowCount takes integer lvl returns integer 
        return 12 //how many arrows
    endfunction
        
    private function GetArrowAoE takes integer lvl returns real
        return 125. // collision size each arrow
    endfunction
        
    //xedamage options:
    private function DamageOptions takes xedamage spellDamage returns nothing
        set spellDamage.dtype           = DAMAGE_TYPE_MAGIC
        set spellDamage.atype           = ATTACK_TYPE_NORMAL
        set spellDamage.exception       = UNIT_TYPE_STRUCTURE //don't damage building
        set spellDamage.visibleOnly     = false //only damage visible unit
        set spellDamage.damageAllies    = false //damage allies if true
        set spellDamage.damageTrees     = true //damage destructables?
    endfunction
        
//*================================================================================
//* E N D     O F     C O N F I G U R A T I O N     M E N U
//*================================================================================
        
    globals
        xedamage xed
        xecast   xec
    endglobals
        
    struct Arrow extends xemissile
        
        unit    caster 
        real    tx 
        real    ty 
        integer lvl
            
        private method onHit takes nothing returns nothing
            
            call xed.damageAOE(.caster,.tx, .ty, GetArrowAoE(.lvl), GetDamage(.lvl))
                
            set  xec.owningplayer = GetOwningPlayer(.caster)
            call xec.castOnAOE(.tx,.ty, GetArrowAoE(.lvl))
                
        endmethod
            
        static method start takes unit c, real x, real y, real tx, real ty, integer lvl returns nothing
            local thistype this = thistype.allocate(x,y,MAX_HEIGHT,tx,ty,45.)
            local real dist = SquareRoot((x - tx) * (x - tx) + (y - ty) * (y - ty))
            local real speed = dist * (SPEED / GetAoE(.lvl))
                
            set .fxpath = ARROW_MODEL
            set .scale  = ARROW_SCALE
                
            set .lvl = lvl
            set .caster = c
            set .tx = tx
            set .ty = ty
               
            call .launch(speed,ARC)
        endmethod
            
    endstruct
        
    private struct MainArrow extends xemissile
        
        unit    caster
        integer lvl
        real    sx
        real    sy
        real    tx
        real    ty
        xefx    sfx
            
        private method onHit takes nothing returns nothing
            local integer i
            local real angle
            local real dis
            local real tx
            local real ty
                
            //sfx:
            set .sfx = xefx.create(.sx, .sy, 0.)
            set .sfx.z = MAX_HEIGHT
            set .sfx.fxpath = EFFECT
            set .sfx.alpha = 0
            call .sfx.destroy()

            set i = GetArrowCount(.lvl)
                
            loop
                    
                exitwhen i == 0
                set angle = GetRandomReal(0., 2. * bj_PI)
                set dis = GetRandomReal(1., GetAoE(.lvl))
                set tx = .tx + dis * Cos (angle)
                set ty = .ty + dis * Sin (angle)
                call Arrow.start(.caster, .sx, .sy, tx, ty, .lvl)
                    
                set i = i - 1
            endloop
                
        endmethod
            
        private static method start takes unit u, real x, real y, integer lvl returns nothing
            local real unitX = GetUnitX(u)
            local real unitY = GetUnitY(u)
            local real dx    = x - unitX
            local real dy    = y - unitY
            local real a     = Atan2(dy, dx)
            local real dist  = SquareRoot(dx*dx + dy*dy)/2
            local real tx    = unitX + dist * Cos(a)
            local real ty    = unitY + dist * Sin(a)

            local thistype this = thistype.allocate(unitX, unitY, 45, tx, ty, MAX_HEIGHT)

            set this.fxpath = ARROW_MODEL
            set this.scale  = ARROW_SCALE

            set this.lvl = lvl
            set this.caster = u
            set this.sx = tx
            set this.sy = ty
            set this.tx = x
            set this.ty = y

            call this.launch(SPEED, ARC)
        endmethod
            
        private static method SpellEffect takes nothing returns nothing
            
            if GetSpellAbilityId() == SPELL_ID then
                call thistype.start(GetTriggerUnit(),GetSpellTargetX(), GetSpellTargetY(), GetUnitAbilityLevel(GetTriggerUnit(),SPELL_ID))
            endif
                
        endmethod
            
            
        private static method Check takes nothing returns nothing
            
            local unit u = GetTriggerUnit()
                
            local real dx = GetUnitX(u) - GetSpellTargetX()
            local real dy = GetUnitY(u) - GetSpellTargetY()
            
            if GetSpellAbilityId() == SPELL_ID and dx * dx + dy * dy < MIN_DIST * MIN_DIST then
                
                call SimError(GetOwningPlayer(u), ERROR_MSG)
                call PauseUnit(u, true)
                call IssueImmediateOrder(u, "stop")
                call PauseUnit(u, false)
                    
            endif
            
            set u = null
        endmethod
            
        private static method onInit takes nothing returns nothing
        
            call RegisterPlayerUnitEvent( EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.SpellEffect )
            call RegisterPlayerUnitEvent( EVENT_PLAYER_UNIT_SPELL_CHANNEL, function thistype.Check )
            
            //xecast options:
            set xec             = xecast.create()
            set xec.abilityid   = FROST_NOVA_ID
            set xec.orderstring = DUMMY_ORDER
            //xe damage init:    
            set xed = xedamage.create()
            call DamageOptions(xed)
            //preload sfx and dummy ability:
            static if PRELOAD then //preload enabled?
                set bj_lastCreatedUnit = CreateUnit(Player(15), XE_DUMMY_UNITID, 0, 0, 0)

                call UnitAddAbility(bj_lastCreatedUnit, FROST_NOVA_ID)
                call RemoveUnit(bj_lastCreatedUnit)
                
                call Preload(ARROW_MODEL)
                call Preload(EFFECT)
            endif
            
        endmethod
            
    endstruct
        
endlibrary

Keywords:
Frost Arrows, frost, slow, arrows, nova, rain of arrows, arrow, MUI, AOE
Contents

Frost Arrows v1.01 (Map)

Reviews
19:18, 18th Feb 2013 Magtheridon96: Approved. This is well-written and the documentation is sufficient. It's also easily configurable and clean!

Moderator

M

Moderator

19:18, 18th Feb 2013
Magtheridon96: Approved.
This is well-written and the documentation is sufficient.
It's also easily configurable and clean!
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
why do you even have GetArrowCount, GetArrowAoE, GetAoE, those are values that are not changing so they could be globals and that would speed the spell a little bit

It seems to me that Arrow and MainArrow are never destroyed
 
Dummy by Nestharus is better than xe.
Also,i think that error ms shouldnt be in the configuration
Cache GetUnitX/Y inside a variable,so you could add some speed
SquareRoot dx + dx * dy + dy MIN DIST
-
dx + dx * dy + dy MIN DIST * MIN DIST
Your code lacks documentation
And add those sytems on a uses or requires code syntax
Like:
Library a uses b,c
 
I'm okay with the use of xe, because it's a widely used library and most things that are approved on wc3c.net and thehelper.net are totally okay here.

edit
Almia's right about documentation though :v

Documentation should include at the very least, the resource name, the author name and links to required resources.
For systems, you would include an API listing as well.
A changelog is 100% optional.
 
Level 5
Joined
Aug 16, 2010
Messages
97
There's a thing with spells and systems (and unfortunately Moderators) of Hive: that they pay too much attention to efficiency while most computer systems now are updated enough to not care about the mentioned 30% or so of performance gain. We make spells complicated and not-user-friendly only to gain a marginal performance increase.
( But it can also be a good practice for programmers ;) )
 
We don't pay too much attention to efficiency, but when something can be 400% faster, we're definitely going to ask you to update it to be faster :V

Even the fastest of computers can succumb to the slowness that is Warcraft III's Engine.

edit
Okay fine, maybe we do :C
It's just that if something can be better, I believe it should be better, because the work to make it better is only done once, but the resource lasts till the end of time (Or till Wc3 modding is over).
 
Top