Spell Blink Back

WolfieeifloW

WEHZ Helper
Reaction score
372
Blink Back
Created By: WolfieeifloW

Requires NewGen and TimerUtils
Optionally can use GTrigger
Version:
1.7


Credits:
Spell editing, idea, and triggers were created by WolfieeifloW.


If you take the time to download / look at these, please at least leave a comment.
Don't forget to rate also (using the stars
rating_5.gif
) !

blinkbackca7.jpg

Screenshots serve no justice, try the spell out ingame.


Features:
-Leakless
-Lagless
-Eye-candy
-MUI


Spell Description
Blinks onto a target enemy, dealing damage. After a period of time, your Hero blinks back to their original position, dealing damage in a 450 AoE around where he lands. Casting range improves per level.
Level 1 - 50 target damage, 40 AoE damage, 0.50 blink back delay.
Level 2 - 100 target damage, 80 AoE damage, 1.00 blink back delay.
Level 3 - 150 target damage, 120 AoE damage, 1.50 blink back delay.
Level 4 - 200 target damage, 160 AoE damage, 2.00 blink back delay.


Spell Code
JASS:
// +------------------------------------------------------------+
// |                                                            |
// |               -=-=- Blink Back [v1.7] -=-=-                |
// |                -=-=- By WolfieeifloW -=-=-                 |
// |             Requires JASS NewGen and TimerUtils            |
// |                 Optionally can use GTrigger                |
// |                                                            |
// +------------------------------------------------------------+
// |                                                            |
// |   Blinks onto a target enemy, dealing damage. After a      |
// |   period of time, your Hero blinks back to their           |
// |   original position, dealing damage in a XXX AoE around    |
// |   where he lands. Casting range improves per level.        |
// |                                                            |
// +------------------------------------------------------------+
// |                                                            |
// |   -=-=- How To Implement -=-=-                             |
// |      1. Copy TimerUtils into your map                      |
// |       b. Copy GTrigger into your map                       |
// |      2. Copy this trigger into your map                    |
// |      3. Copy the Blink Back ability into your map          |
// |      4. Make sure the 'Rawcodes' in the trigger match      |
// |          your Blink Back's rawcode in Object Editor        |
// |      5. Customize the spell                                |
// |      6. Enjoy!                                             |
// |                                                            |
// +------------------------------------------------------------+
// |                                                            |
// |   -=-=- Credits -=-=-                                      |
// |      Credits are not needed, but appreciated               |
// |       Just don't claim this as yours                       |
// |                                                            |
// +------------------------------------------------------------+
// |   -=-=- Version History -=-=-                              |
// |                                                            |
// |      Version 1.7                                           |
// |       - Added GTrigger as an optional library              |
// |       - Fixed grouping for blink back                      |
// |                                                            |
// |      Version 1.6b                                          |
// |       - Code revamp for .destroy()                         |
// |       - Changed FirstOfGroup() loop to ForGroup()          |
// |                                                            |
// |      Version 1.6                                           |
// |       - Updated to use new TimerUtils                      |
// |       - Added cooldown reset to test map                   |
// |                                                            |
// |      Older versions...                                     |
// |       Read changelog in thread                             |
// |                                                            |
// +------------------------------------------------------------+
scope BlinkBack initializer Init

    globals
//=========================================================================
//====================     Constants Configuration     ====================
//=========================================================================
        private constant integer ABILITY_ID = 'A000'
        //Rawcode of 'Blink Back' ability
    
        private constant string SFX_START = "Abilities\\Spells\\NightElf\\Blink\\BlinkCaster.mdl"
        //Path for the special effect when unit blinks to the target
    
        private constant string SFX_TARGET = "Abilities\\Spells\\Undead\\AnimateDead\\AnimateDeadTarget.mdl"
        //Path for the special effect when unit arrives at target
    
        private constant string SFX_BB = "Abilities\\Spells\\Orc\\AncestralSpirit\\AncestralSpiritCaster.mdl"
        //Path for the special effect when unit arrives back at original location
    
        private constant string SFX_AOE = "Abilities\\Spells\\Demon\\DarkPortal\\DarkPortalTarget.mdl"
        //Path for the special effect of units that get hit in the AoE
    
        private constant string SFX_ATTACH = "origin"
        //Attachment point for all above special effects
        
        private constant real SFX_DURATION = 1.233
        //Duration for the special effect
    
        private constant attacktype ATTACK_TYPE = ATTACK_TYPE_HERO
        //Attack type of Blink Back
    
        private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_FIRE
        //Damage type of Blink Back
    endglobals
    
//=========================================================================
//====================     Functions Configuration     ====================
//=========================================================================    
    private function AoEDamage takes integer level returns real
        return (level * 40.)
        //AoE damage upon blinking back
    endfunction
    
    private function TargetDamage takes integer level returns real
        return (level * 50.)
        //Target damage
    endfunction
    
    private function Delay takes integer level returns real
        return (level * 0.5)
        //Delay before the caster blinks back
    endfunction
    
    private function Radius takes integer level returns real
        return 450.
        //AoE that units get hit upon Blink Back
    endfunction
    
//========================================================================
//====================     DO NOT TOUCH PAST HERE     ====================
//====================     DO NOT TOUCH PAST HERE     ====================
//====================     DO NOT TOUCH PAST HERE     ====================
//========================================================================
    private struct data
        unit caster
        unit target
        real cx
        real cy
        real ccx
        real ccy
        real tx
        real ty
        integer level
        timer t
        effect sfx
        
        method destroy takes nothing returns nothing
            call ReleaseTimer(.t)
            call .deallocate()
        endmethod
    endstruct
    
    globals
        private group Group = CreateGroup()
        private player GPlayer
        private integer CurrentInstance
    endglobals
    
    
//============================================================
//====================     Conditions     ====================
//============================================================    
    private function Conditions takes nothing returns boolean
        local unit u = GetFilterUnit()
        local data d = CurrentInstance
        
        if (IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false and GetWidgetLife(GetFilterUnit()) >= 0.405 and IsUnitEnemy(GetFilterUnit(), GPlayer)) then
            call DestroyEffect(AddSpecialEffectTarget(SFX_AOE, u, SFX_ATTACH))
            call UnitDamageTarget(d.caster, u, AoEDamage(d.level), true, true, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE_WHOKNOWS)
            call GroupRemoveUnit(Group, u)
        endif
        set u = null
        return false
    endfunction
    
//=========================================================
//====================     Actions     ====================
//=========================================================
    private function SFXDestroy takes nothing returns nothing
        local data d = GetTimerData(GetExpiredTimer())
        
        call DestroyEffect(d.sfx)
        call d.destroy()
    endfunction
    
    private function BlinkBack takes nothing returns nothing
        local data d = GetTimerData(GetExpiredTimer())
        
        set d.ccx = GetUnitX(d.caster)
        set d.ccy = GetUnitY(d.caster)
        call DestroyEffect(AddSpecialEffect(SFX_START, d.ccx, d.ccy))
        call PauseUnit(d.caster, true)
        call SetUnitPosition(d.caster, d.cx, d.cy)
        call PauseUnit(d.caster, false)
        set GPlayer = GetOwningPlayer(d.caster)
        set CurrentInstance = d
        call GroupEnumUnitsInRange(Group, d.cx, d.cy, Radius(d.level), Condition(function Conditions))
        set d.sfx = AddSpecialEffectTarget(SFX_BB, d.caster, SFX_ATTACH)
        call ReleaseTimer(d.t)
        set d.t = NewTimer()
        call SetTimerData(d.t, d)
        call TimerStart(d.t, SFX_DURATION, false, function SFXDestroy)
    endfunction

    private function Actions takes nothing returns boolean
        local data d
        
        if GetSpellAbilityId() == ABILITY_ID then
            set d = data.create()
            set d.caster = GetTriggerUnit()
            set d.target = GetSpellTargetUnit()
            set d.cx = GetUnitX(d.caster)
            set d.cy = GetUnitY(d.caster)
            set d.tx = GetUnitX(d.target)
            set d.ty = GetUnitY(d.target)
            set d.level = GetUnitAbilityLevel(d.caster, ABILITY_ID)
            
            call DestroyEffect(AddSpecialEffect(SFX_START, d.cx, d.cy))
            call PauseUnit(d.caster, true)
            call SetUnitPosition(d.caster, d.tx, d.ty)
            call PauseUnit(d.caster, false)
            call DestroyEffect(AddSpecialEffectTarget(SFX_TARGET, d.caster, SFX_ATTACH))
            call UnitDamageTarget(d.caster, d.target, TargetDamage(d.level), true, true, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE_WHOKNOWS)
            set d.t = NewTimer()
            call SetTimerData(d.t, d)
            call TimerStart(d.t, Delay(d.level), false, function BlinkBack)
        endif
        return false
    endfunction
    
//=============================================================
//====================     Initializer     ====================
//=============================================================
    private function Init takes nothing returns nothing
        local trigger trig = CreateTrigger()
        
        call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_SPELL_EFFECT)
        static if(LIBRARY_GTrigger) then
            call TriggerAddCondition(GT_RegisterStartsEffectEvent(trig, ABILITY_ID), Condition(function Actions))
        else
            call TriggerAddCondition(trig, Condition(function Actions))
        endif
        set trig = null
    endfunction
    
endscope

Test map included.
Constructive criticism is welcomed, flaming is not.
This spell will only be submitted to TH.net.
Do not redistribute or modify without permission.
Credits are not needed but are appreciated.
Just don't claim the spell as yours.

Hope you enjoy it!​

Changelog
v1.7
- Added GTrigger as an optional library
- Fixed grouping for blink back


v1.6b
- Code revamp for .destroy()
- Changed FirstOfGroup() loop to ForGroup()

v1.6
-Updated to use new TimerUtils
- Added cooldown reset to test map

v1.5
- Major code revamp
- Now uses timers instead of TriggerSleepAction()

v1.4
- Fixed a resetting of X/Y's
- Changed from FirstOfGroup to ForGroup
Credits to Artificial
- Added a loop to trigger event
- Blink Back approved on Clan Mapz!

v1.3b
- Made AoE grouping more efficient
Credits to Bobo_The_Kodo

v1.3
- Code cleanup
- Fixed a BJ
- Made stuff formula configurable
- Removed loads of GetUnitAbilityLevel() calls

v1.2
- Code layout touchup

v1.1
- Blink Back approved on TH.net!
- Code fix (BJ)
Credits to Andrewgosu

v1.0d
- Code cleanup
- AoE can now be configured for per level
Thanks to AceHart and Flare

v1.0c
- Code cleanup
Thanks to AceHart
- Added condition to check if units alive
Prevents SFX from showing on dead units

v1.0b
- Code touchup
Thanks to kenny!
Thanks to saw792

v1.0
- Initial release
 

Attachments

  • opt-Blink_Back_v16.w3x
    25 KB · Views: 399
  • opt-Blink_Back_v16b.w3x
    25 KB · Views: 393
  • opt-Blink_Back_v17.w3x
    54 KB · Views: 459

Kenny

Back for now.
Reaction score
202
Since most units you blink to, and your hero itself while most likely always be inside map bounds or whatever, instead of:

JASS:
call SetUnitPosition(BBC, BBTX, BBTY)


Use SetUnitX/Y.

Again, instead of using TriggerSleepAction() maybe use a timer. Granted that means you may need an attachment system, however no one likes TSA's or PolledWaits.

JASS:
loop
        set pickedUnit = FirstOfGroup(BBAOE)
        exitwhen pickedUnit == null
            set pickedUnit = FirstOfGroup(BBAOE)
            call UnitDamageTarget(BBC, pickedUnit, (GetUnitAbilityLevel(BBC, ability_BBid) * BBAOEDmg), true, true, bbAttackType, bbDamageType, WEAPON_TYPE_WHOKNOWS)
            call DestroyEffect(AddSpecialEffectTarget(BBSFXAOE, pickedUnit, SFXAP))
            call GroupRemoveUnit(BBAOE, pickedUnit)
            set pickedUnit = null
    endloop


You dont need to null pickedUnit at the end there im pretty sure. Also, you set pickedUnit to FirstOfGroup() twice, once before the exitwhen condition and once after, this isnt needed.

You havent nulled BBC and BBT.

And,

Are you sure:

JASS:
private function BBConditions takes nothing returns boolean
    return IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetTriggerUnit()))
endfunction


GetTriggerUnit() works in that case, as i have tried many times and it seems to not work. It may be worth checking out.

JASS:


Why not just do: DestroyEffect(AddSpecialEffectTarget())? Im guessing because maybe the effect wont show properly? If thats the case, it would be better to set the effect to a variable then destoy the variable and null it :).

Other than that, its a pretty cool spell. I made something similar a long time ago, but it was just a blink-there blink-back type of thing, no extended wait or AoE dmg. Good work! :)
 

Kenny

Back for now.
Reaction score
202
SetUnitX,Y disables pathing i believe.

However this isnt really the type of spell that needs to check for any type of pathing. Plus he already pauses the unit before hand, which is one of the pros of using SetUnitPosition, so he may as well just use SetUnitX/Y and keep the PauseUnit().
 
Reaction score
86
Hmmm + rep for the spell but to me it seems rather useless/redundant... Blinking and then blinking back? Then what was the point... lol. Good spell none-the-less, albeit the idea, +rep.
 

WolfieeifloW

WEHZ Helper
Reaction score
372
Since most units you blink to, and your hero itself while most likely always be inside map bounds or whatever, instead of:
Use SetUnitX/Y.
SetUnitX,Y disables pathing i believe.
:) .
Also, "most likely".
I should show you a replay of a DotA game where we got outside of map bounds ;) !

Again, instead of using TriggerSleepAction() maybe use a timer. Granted that means you may need an attachment system, however no one likes TSA's or PolledWaits.
I haven't learned attachments yet :( .
TSA works for now, when I learn timers I'll convert.

You dont need to null pickedUnit at the end there im pretty sure.
I've been told to, so I did :) .

Also, you set pickedUnit to FirstOfGroup() twice, once before the exitwhen condition and once after, this isnt needed.
Removed.

You havent nulled BBC and BBT.
Fixed.

And,
Are you sure:
GetTriggerUnit() works in that case, as i have tried many times and it seems to not work. It may be worth checking out.
I found that odd to.
I've tried it before and it didn't work;
But it seemingly works for this spell so :) !

Why not just do: DestroyEffect(AddSpecialEffectTarget())? Im guessing because maybe the effect wont show properly? If thats the case, it would be better to set the effect to a variable then destoy the variable and null it :).
You guessed it.
The effect won't show properly.
And bj_lastCreatedEffect seems to work fine for me.

Other than that, its a pretty cool spell. I made something similar a long time ago, but it was just a blink-there blink-back type of thing, no extended wait or AoE dmg. Good work! :)
Cool!
I brought back something of yours I guess :p .
Thanks for the feedback!

Hmmm + rep for the spell but to me it seems rather useless/redundant... Blinking and then blinking back? Then what was the point... lol. Good spell none-the-less, albeit the idea, +rep.
This could be used for DPS heroes;
Blink in, do the damage, get outta there!
Can also be used for juking: Blink ahead, the enemy runs for you, and tada! You're back where you blinked from :p .



UPDATE
Changelog
v1.0b
- Code touchup
Thanks to kenny!
Thanks for all the comments guys, keep them coming!
Also don't forget to rate :) !
 

saw792

Is known to say things. That is all.
Reaction score
280
JASS:
.

We already told you in your help thread that that leaks. It doesn't destroy the effect at all because AddSpecialEffectTarget() does not save the effect to bj_lastCreatedEffect. Using DestroyEffect(AddSpecialEffectTarget(...)) there won't work either, as you found, so you have to do this:
JASS:
set sfx = call AddSpecialEffectTarget(BBSFXBV, BBC, SFXAP)
call TriggerSleepAction(1) //Will require some fiddling to get the right time
call DestroyEffect(sfx)


And move all that to just above where you null your locals so it doesn't interrupt other trigger actions. If you need more accuracy you need a timer and an attachment system.
 

WolfieeifloW

WEHZ Helper
Reaction score
372
We already told you in your help thread that that leaks. It doesn't destroy the effect at all because AddSpecialEffectTarget() does not save the effect to bj_lastCreatedEffect. Using DestroyEffect(AddSpecialEffectTarget(...)) there won't work either, as you found, so you have to do this:
[del]I can't do a wait in there, it delays the other SFX.[/del] (Didn't see that part of your post, sec)
And what's the point of bj_lastCreatedEffect if it's never even used?
Alright it worked, but I still don't see what's up with the bj.

UPDATE
Changelog
v1.0b
- Code touchup
Thanks to kenny!
Thanks to saw792
 

saw792

Is known to say things. That is all.
Reaction score
280
It is used... by BJs that set it for GUI use. And no, it doesn't delay the SFX, read my whole post please.
 

WolfieeifloW

WEHZ Helper
Reaction score
372
It is used... by BJs that set it for GUI use. And no, it doesn't delay the SFX, read my whole post please.
I see.
Read my edit please :p !
Thanks for help, credits to you for code touchup.

Keep the comments/suggestions/code revisions coming!
 

Azlier

Old World Ghost
Reaction score
461
Grasshoppah said:
I haven't learned attachments yet .
TSA works for now, when I learn timers I'll convert.

What, you still don't know how to attach a struct to a timer? A whole two minutes I lose explaining it to you, then! :p
 

AceHart

Your Friendly Neighborhood Admin
Reaction score
1,494
> Are you sure GetTriggerUnit() works in that case?

Yes.

> no one likes TriggerSleepAction

If it works, use it.


"Init" should be private too.

> set pickedUnit = null

Not needed.

> Casting range improves per level.

I'd suggest using a "range" function in that case.
Along with a "damage" function.

Something like
JASS:
private function Range takes integer level returns real
    return I2R(level) * 30.0 + 10.0
endfunction

to give people an easy way to customize it.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top