Spellpack Far Seer

Nyph

Occasional News Reader
Reaction score
87
Far Seer Spellpack
By Nyph

This spellpack contains two spells, Magnetic Attack and Electrocute.
Both are vJass
Both are MUI


Magnetic attack
(no screenshot)
Causes the attack of the far seer to drag the attacked unit towards him.
Deals 10% of the distance dragged in chaos damage.
Level 1 - Drags the target 75 units towards the far seer.
Level 2 - Drags the target 125 units towards the far seer.
Level 3 - Drags the target 175 units towards the far seer.

JASS:
////////////////////////////////////////////////////
//MAGNETIC ATTACK BY NYPH///////////////////////////
////////////////////////////////////////////////////
scope MagneticAttack initializer setUp
    private function SpecPullDist takes unit caster, unit target returns real // DO NOT CHANGE
        return 100.00 // If you want a custom distance pulled(eg. based on intelligence) then you can use this. If you don't know how to make it the way you want, ask me in my thread or anyone in the JASS forum about your problem.
    endfunction
    globals
        private constant boolean UseSpecPullDist = false
        private constant real L1Dist = 75 // Distance pulled at level 1
        private constant real DistInc = 50 // Distance added every level after level 1
        private constant integer MagBuff = 'B000' // Buff for pulling
        private constant integer MagAbi = 'A000' // Ability for pulling
        private constant real DamagePerDist = 0.1 // Multiple of distance pulled into damage
        private constant damagetype DType = DAMAGE_TYPE_FORCE // Damage type
        private constant attacktype AType = ATTACK_TYPE_CHAOS // Attack type
        private constant integer Steps = 10 // The amount of steps the effect is put over, each step takes 0.04 seconds
////////////////////////////////////////////////////
//DO NOT CHANGE ANYTHING PAST THIS POINT////////////
////////////////////////////////////////////////////
        private trigger DamageTrig = CreateTrigger()
        private trigger DetectTrig = CreateTrigger()
    endglobals
    private struct MagData
        unit caster
        unit target
        integer level
        integer times
    endstruct
////////////////////////////////////////////////////
    private function Pull takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local MagData data
        local real move
        set data = GetTimerStructA(t)
        if data.times > Steps then
            call ClearTimerStructA(t)
            set data.caster = null
            set data.target = null
            call data.destroy()
            call PauseTimer(t)
            call DestroyTimer(t)
            set t = null
        else
            if UseSpecPullDist == false then
                set move = (((data.level-1)*DistInc)+L1Dist)/Steps
            else
                set move = SpecPullDist(data.caster,data.target)/Steps
            endif
            if IsUnitInRange(data.target,data.caster,move) == false then
                call SetUnitX(data.target,PolarProjectionX(GetUnitX(data.target),move,AngleBetweenUnits(data.target,data.caster)))
                call SetUnitY(data.target,PolarProjectionY(GetUnitY(data.target),move,AngleBetweenUnits(data.target,data.caster)))
                call UnitDamageTarget(data.caster,data.target,move*DamagePerDist,false,false,AType,DType,null)
            endif
            set data.times = data.times + 1
        endif
    endfunction
    private function Damage takes nothing returns nothing
        local unit caster
        local unit target
        local integer level
        local timer t
        local MagData data
        if GetUnitAbilityLevel(GetTriggerUnit(),MagBuff) > 0 then
            set caster = GetEventDamageSource()
            set target = GetTriggerUnit()
            set level = GetUnitAbilityLevel(caster,MagAbi)
            call UnitRemoveAbility(target,MagBuff)
            set data = data.create()
            set data.caster = caster
            set data.target = target
            set data.level = level - 1
            set data.times = 1
            set t = CreateTimer()
            call SetTimerStructA(t,data)
            call TimerStart(t,0.04,true,function Pull)
            set caster = null
            set target = null
        endif
    endfunction
    private function Detect takes nothing returns nothing
        call TriggerRegisterUnitEvent(DamageTrig,GetEnteringUnit(),EVENT_UNIT_DAMAGED)
    endfunction
    
    private function setUp takes nothing returns nothing
        local region r = CreateRegion()
        local group g = CreateGroup()
        call RegionAddRect(r,GetWorldBounds())
        call TriggerRegisterEnterRegion(DetectTrig,r,null)
        call TriggerAddAction(DetectTrig,function Detect)
        call TriggerAddAction(DamageTrig,function Damage)
        call RemoveRegion(r)
        call GroupEnumUnitsInRect(g,GetWorldBounds(),null)
        loop
            exitwhen FirstOfGroup(g) == null
            call TriggerRegisterUnitEvent(DamageTrig,FirstOfGroup(g),EVENT_UNIT_DAMAGED)
            call GroupRemoveUnit(g,FirstOfGroup(g))
        endloop
        call DestroyGroup(g)
    endfunction
endscope

Electrocute
attachment.php

The Far Seer focuses his power and sends the target units up into the air, the Far Seer then sends an extremely powerful bolt of lightning to strike the unit, dealing massive damage.
Level 1 - Deals 175 damage.
Level 2 - Deals 275 damage.
Level 3 - Deals 375 damage.

JASS:
////////////////////////////////////////////////////
//ELECTROCUTE BY NYPH///////////////////////////////
////////////////////////////////////////////////////
scope Electrocute initializer StartUp
    private function SpecDamage takes unit caster, unit target returns real // DO NOT CHANGE
        return 100.00 // If you want a custom damage delt(say based on intelligence) then you can use this. If you don't know how to make it the way you want, ask me in my thread or anyone in the JASS forum about your problem.
    endfunction
    globals
        private constant integer ElectAbi = 'A001' // Ability that is used.
        private constant real L1Damage = 175.00 // Damage at level 1
        private constant real DamInc = 100.00 // Damage added per level
        private constant damagetype DType = DAMAGE_TYPE_LIGHTNING // Damage type
        private constant attacktype AType = ATTACK_TYPE_MAGIC // Attack type
        private constant boolean UseSpecDamage = false // Use custom damage from specdamage function above.
        private constant string WhichLightning = "CLPB" // String for lightning type used.
        private constant string SpecialEffect = "Abilities\\Weapons\\Bolt\\BoltImpact.mdl" // Special effect art
////////////////////////////////////////////////////
//DO NOT CHANGE ANYTHING PAST THIS POINT////////////
////////////////////////////////////////////////////
        private trigger castTrig = CreateTrigger()
    endglobals
    private struct ElecData
        unit target
        unit caster
        lightning zap
    endstruct
    private struct SpeedData
        unit u
        real removed
    endstruct
////////////////////////////////////////////////////
    private function RestoreSpeed takes nothing returns nothing
        local timer tt = GetExpiredTimer()
        local SpeedData data
        set data = GetTimerStructA(tt)
        call SetUnitMoveSpeed(data.u,GetUnitMoveSpeed(data.u)+data.removed)
        call ClearTimerStructA(tt)
        set data.u = null
        call data.destroy()
        call DestroyTimer(tt)
        set tt = null
    endfunction
    private function RemoveZap takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local timer tt = CreateTimer()
        local SpeedData sd = SpeedData.create()
        local ElecData data
        set data = GetTimerStructA(t)
        set sd.u = data.target
        call SetUnitFlyHeight(data.target,0,1600)
        call PauseUnit(data.target,false)
        call DestroyLightning(data.zap)
        set data.zap = null
        set data.caster = null
        set data.target = null
        call ClearTimerStructA(t)
        call data.destroy()
        call DestroyTimer(t)
        set t = null
        set sd.removed = GetUnitMoveSpeed(sd.u)/2
        call SetUnitMoveSpeed(sd.u,GetUnitMoveSpeed(sd.u)-sd.removed)
        call SetTimerStructA(tt,sd)
        call TimerStart(tt,5.00,false,function RestoreSpeed)
    endfunction
    private function ZapUnit takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local ElecData data
        local lightning zap
        local real damage
        set data = GetTimerStructA(t)
        call DestroyEffect(AddSpecialEffectTarget(SpecialEffect,data.target,"chest"))
        set zap = AddLightningEx(WhichLightning,true,GetUnitX(data.caster),GetUnitY(data.caster),GetUnitFlyHeight(data.caster),GetUnitX(data.target),GetUnitY(data.target),GetUnitFlyHeight(data.target)+120)
        set data.zap = zap
        if UseSpecDamage == false then
            set damage = L1Damage + DamInc*(GetUnitAbilityLevel(data.caster,ElectAbi)-1)
        else
            set damage = SpecDamage(data.caster,data.target)
        endif
        call PauseUnit(data.target,false)
        call UnitDamageTarget(data.caster,data.target,damage,false,false,AType,DType,null)
        call PauseUnit(data.target,true)
        call TimerStart(t,0.20,false,function RemoveZap)
        set zap = null
    endfunction
    private function MoveUnit takes nothing returns nothing
        local timer t
        local ElecData data
        if GetSpellAbilityId() == ElectAbi then
            set t = CreateTimer()
            set data = ElecData.create()
            call UnitAddAbility(GetSpellTargetUnit(),'Arav')
            call SetUnitFlyHeight(GetSpellTargetUnit(),300,400)
            call UnitRemoveAbility(GetSpellTargetUnit(),'Arav')
            call PauseUnit(GetSpellTargetUnit(),true)
            set data.target = GetSpellTargetUnit()
            set data.caster = GetTriggerUnit()
            call SetTimerStructA(t,data)
            call TimerStart(t,0.75,false,function ZapUnit)
        endif
    endfunction
    private function StartUp takes nothing returns nothing
        call TriggerRegisterAnyUnitEventBJ(castTrig,EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddAction(castTrig,function MoveUnit)
    endfunction
endscope
 

Attachments

  • Screenie.JPG
    Screenie.JPG
    53.3 KB · Views: 438
  • FarSeerPack.w3x
    41.3 KB · Views: 234

Flare

Stops copies me!
Reaction score
662
1)
JASS:
if GetUnitAbilityLevel(GetTriggerUnit(),'B000') > 0 then
set level = GetUnitAbilityLevel(caster,'A000')
call UnitRemoveAbility(target,'B000')


You set those rawcodes in Config header, so use them.

2) You should use a timer recycling system (such as CSSafety) instead of creating timers. Creating timers can cause bugs (I think)

3) Pause periodic timers before destroying them. If you destroy a timer, it will continue with it's present run, so the actions may run again (even though it shouldn't)

4) Where's this SpecPullDist function? Everything used by the spell (apart from systems used, like ABC) should be contained within the one trigger. Makes it easy to import :)

5) You aren't nulling your handles correctly. In the Damage function, you must null caster, target and t OUTSIDE the if. You are generating a new instance of each local whenever the function is called, but you are only nulling it when it's used.

6) Why aren't you using a conditionfunc for the Damage trigger? That way, you can check if the level of buff for triggering unit > 0, and you don't have to do with if within the actions function. That way, you can initialize your variables, and save some space
 

Nyph

Occasional News Reader
Reaction score
87
1)
JASS:
if GetUnitAbilityLevel(GetTriggerUnit(),'B000') > 0 then
set level = GetUnitAbilityLevel(caster,'A000')
call UnitRemoveAbility(target,'B000')


You set those rawcodes in Config header, so use them.

2) You should use a timer recycling system (such as CSSafety) instead of creating timers. Creating timers can cause bugs (I think)

3) Pause periodic timers before destroying them. If you destroy a timer, it will continue with it's present run, so the actions may run again (even though it shouldn't)

4) Where's this SpecPullDist function? Everything used by the spell (apart from systems used, like ABC) should be contained within the one trigger. Makes it easy to import

5) You aren't nulling your handles correctly. In the Damage function, you must null caster, target and t OUTSIDE the if. You are generating a new instance of each local whenever the function is called, but you are only nulling it when it's used.

6) Why aren't you using a conditionfunc for the Damage trigger? That way, you can check if the level of buff for triggering unit > 0, and you don't have to do with if within the actions function. That way, you can initialize your variables, and save some space

1 - Fixed.

2 - More information please.

3 - Done.

4 - At the top - its part of the config

5 - Don't have to null them, they are already nulled because they were never set.

6 - I personally don't like conditions and i prefer to keep the function count down as low as possible.
 

Flare

Stops copies me!
Reaction score
662
2) Get the CasterSystem and copy the CSSafety and CSData triggers into your map. Then, replace every instance of CreateTimer () with NewTimer (), and DestroyTimer with ReleaseTimer (). There is some bug associated with creating/destroying local timers, and recycling timers is, apparently, faster than creating/destroying.

4) Oh, lol. Never noticed that ^^

5) If you initialized the handles to null, it wouldn't be a problem (I think). AFAIK, local handles have to be nulled even if you didn't initialize them.

6) IMO, it looks much better if you have a conditionfunc, makes the code look more structured :)

And you should add all your constants to config header. You left out timer intervals, and fly height. Also, for Magnetic Attack, you should put the speed and damage on a per second basis in the config header, then move the unit (timer interval * speed/sec) distance whenever the timer expires, and do (timer interval * damage/sec) damage when the timer expires
 

cr4xzZz

Also known as azwraith_ftL.
Reaction score
51
> There is some bug associated with creating/destroying local timers
There's no bug with creating and destroying. Recycling is just faster and prevents some lag ^^

EDIT:
No Condition checking which ability is casted?! That's painful...
 

Flare

Stops copies me!
Reaction score
662
There's no bug with creating and destroying. Recycling is just faster and prevents some lag ^^

To quote CSSafety's documentation:
//* CSSafety was originally just a timer stack, take your map functions and replace calls
//* to CreateTimer with NewTimer and calls to DestroyTimer to ReleaseTimer and you can feel
//* at ease if your map's spells abuse dynamic triggers a lot since it prevents handle stack
//* corruptions caused by crazy reference counters, basically, wc3 will go crazy if you
//* detroy timers, so it is better to just recycle them
.

And if it wouldn't be called CSSafety if it wasn't safer than creating/destroying timers :p
 

cr4xzZz

Also known as azwraith_ftL.
Reaction score
51
I don't use recycling in my maps and I don't have any problems at all. I recently started using Recycler because everybody yells that it's a lot safer. :) But before that I never encountered this "crazy" moment.. ^^
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      • Ghan
        Administrator - Servers are fun

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top