Spell Aerial Strike

Joker(Div)

Always Here..
Reaction score
86
Aerial Strike:
Summons a great bird that fuses with your current energy (mana), which smashes itself into the target location.

The spell is very flexible, MUI, leakless (better be), and easily implemented. It is also pretty close to a JESP.

Credit to Tinki3 for the map. :)

How To Implement:
  • Create a Trigger
  • Name it: AerialStrike
  • Copy the script (Or just copy the entire trigger)
  • Make/Copy a spell based on channel
  • Make/Copy a flying dummy unit

Requires:
  • TT
  • Recycler
  • NewGen
  • Vex's Dummy Model

Screenies:
sc1uk9.jpg

sc2he5.jpg

sc3oj7.jpg

Code:
JASS:
//===========================================================================
//  Aerial Strike:  By Joker(Div)                     Credits: NewGen - PitzerMike/Vexorian
//                                                             TT - Cohadar
//                                                             Recycler - Cohadar, Vexorian (CSSafety)?     
// Requires: TT, Recycler, NewGen                              Dummy Model - Vexorian                                  
//===========================================================================
scope AerialStrike initializer Init

globals
    private constant integer ABILITY_ID = 'A000'        //ID of spell
    private constant integer BIRD_ID    = 'n000'        //ID of bird
    private constant integer DUMMY_ID   = 'n001'        //ID of Dummy (used to attach sfx)
    private constant real    DUMMY_SIZE = 1.0           //Size of sfx in case you increase base AoE
    
    private constant real BIRD_START     = 500.         //# of units behind the caster, where the bird spawns
    private constant real BIRD_SPEED     = 750.         //The bird's Units/Sec
    private constant real BIRD_HEIGHT    = 1500.         //The bird's starting height
    private constant real BIRD_DESCEND   = 1500.         //The bird's Units/Sec for descending
    private constant real BIRD_MINHEIGHT = 5.           //Minimun height of bird
    private constant real BIRD_SIZE_BASE = 3.5          //Make this w/e you have it as in Object Editor 
    private constant real BIRD_MANA2SIZE = 0.003        //The size increment per mana
    private constant real BIRD_ANIMATION = 4.0          //The rate the bird animates
    
    
    private constant real EXPLOSION_RADIUS  = 250.      //Self-Explanatory
    private constant real BASE_DAMAGE       = 50.       //This will be muliplied by the lvl (set it to 0 if you dont want any)
    private constant real MANA_IMPUT        = 0.5       //The % of mana put into dmg (in this case, 50%)
    
    private constant attacktype ATTACK_TYPE = ATTACK_TYPE_CHAOS  //Self-Explanatory
    private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_NORMAL //Self-Explanatory
    
    
    //The Explosion models (You can remove and add as you wish)
    private constant string IMPACT_EXPLOSION    = "Objects\\Spawnmodels\\NightElf\\NECancelDeath\\NECancelDeath.mdl"
    private constant string IMPACT_EXPLOSION2    = "Abilities\\Spells\\NightElf\\Taunt\\TauntCaster.mdl"
    private constant string IMPACT_EXPLOSION3   = "Units\\NightElf\\Wisp\\WispExplode.mdl"
   
    //The Teleport model
    private constant string TELEPORT = "Abilities\\Spells\\NightElf\\Blink\\BlinkTarget.mdl"
    
    //The crow ability, incase you have edited yours.
    private constant integer CROW_ABILITY = 'Arav'
    
    //This is here if you want the bird to explode once it collides with any unit.
    //Just set it you true if you want it.
    private boolean CONTACT_EXPLODE = true
endglobals


//========================================================================================
//                  You should not have to touch anything under here. 
//                                (Unless specified)
//========================================================================================
    private struct Aerial
        unit caster
        unit bird
        real dspeed
        real ddescend
        real dx
        real dy
        real x
        real y
        real angle
        real mana
        real endx
        real endy
        integer ticks
        integer lvl 
        boolean have
        group g
        
        static method start takes unit caster, unit bird, real x, real y, real angle, real range returns nothing
            local Aerial dat = Aerial.create()
            
              set dat.caster    = caster
              set dat.bird      = bird
              set dat.x         = x
              set dat.y         = y
              set dat.have      = false
              set dat.mana      = GetUnitState(caster, UNIT_STATE_MANA)
              set dat.lvl       = GetUnitAbilityLevel(caster, ABILITY_ID)
              set dat.g         = NewGroup() //Recycler
    
              set dat.dspeed      = BIRD_SPEED      * TT_PERIOD
              set dat.ddescend    = BIRD_DESCEND    * TT_PERIOD
              set dat.dx          = dat.dspeed      * Cos(angle) 
              set dat.dy          = dat.dspeed      * Sin(angle) 
              set dat.ticks       = R2I( ( (range+BIRD_START) / dat.dspeed ) + 0.5 )
            
            call SetUnitTimeScale( bird, BIRD_ANIMATION)
            call TT_Start(function Aerial.callback, dat ) //TT
        endmethod
        
        static method callback takes nothing returns boolean
            local Aerial dat    = TT_GetData() //TT
            local real birdX    = GetUnitX(dat.bird)
            local real birdY    = GetUnitY(dat.bird)
            local real f        = GetUnitFacing(dat.caster)
            local real x        = dat.x
            local real y        = dat.y
            local real fly      = GetUnitFlyHeight(dat.bird)
            local real scale    = BIRD_SIZE_BASE + dat.mana * BIRD_MANA2SIZE

            if dat.ticks > 0 then 
                call SetUnitPosition(dat.bird, birdX + dat.dx, birdY + dat.dy )
                
                set dat.ticks   = dat.ticks - 1
                
                if fly > BIRD_MINHEIGHT then
                    call SetUnitFlyHeight(dat.bird, fly - dat.ddescend, 0)
                endif
                
                if IsUnitInRange(dat.bird, dat.caster, 100.) and not dat.have then
                    call SetUnitScale( dat.bird, scale, scale, scale )
                    call DestroyEffect( AddSpecialEffect(TELEPORT, GetUnitX(dat.caster), GetUnitY(dat.caster)) )
                    call SetUnitState( dat.caster, UNIT_STATE_MANA, dat.mana * MANA_IMPUT )
                    call ShowUnit(dat.caster, false)
                    call PauseUnit(dat.caster, true)
                    set dat.have = true
                endif
                
                if CONTACT_EXPLODE then
                    if dat.have then
                        call GroupEnumUnitsInRange(dat.g, birdX, birdY, EXPLOSION_RADIUS, Condition(function Aerial.filter) )
                    
                        if FirstOfGroup(dat.g) != null and IsUnitInRange(FirstOfGroup(dat.g), dat.bird, 50.) then
                            set dat.endx    = birdX
                            set dat.endy    = birdY
                            call dat.destroy()
                            return true
                        endif
                    endif
                endif
            else
                set dat.endx    = birdX
                set dat.endy    = birdY
                call dat.destroy()
                return true
            endif
                
            return false
        endmethod
        
        //===============================================================================================================================
        //===============================================================================================================================
        private static method filter takes nothing returns boolean
            //Change the conditions to w/e you want here.
            return IsUnitEnemy( GetTriggerUnit(), GetOwningPlayer(GetFilterUnit())) and GetWidgetLife(GetFilterUnit()) > 0.405
        endmethod
        //===============================================================================================================================
        //===============================================================================================================================
        
        method onDestroy takes nothing returns nothing
            local unit first
            local unit dummy
            
            if .have then
                call GroupEnumUnitsInRange(.g, .endx, .endy, EXPLOSION_RADIUS, Condition(function Aerial.filter) )
                    
                call PauseUnit(.caster, false)
                call SetUnitPosition(.caster, .endx, .endy)
                    
                debug call ClearTextMessages()
                debug call BJDebugMsg("Aerial Strike: max damage: |cFFC0C000" + R2S(.lvl*BASE_DAMAGE + .mana*MANA_IMPUT) )
                    
                loop
                    set first = FirstOfGroup(.g)
                    exitwhen first == null
                    call UnitDamageTarget(.caster, first, .lvl*BASE_DAMAGE + .mana*MANA_IMPUT, false, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE_WHOKNOWS )
                    call GroupRemoveUnit(.g, first)
                endloop
                            
                if GetLocalPlayer() == GetOwningPlayer(.caster) then
                    call SelectUnit(.caster, true)
                endif
                
                set dummy = CreateUnit(GetOwningPlayer(.caster), DUMMY_ID, .endx, .endy, bj_UNIT_FACING)
                call SetUnitScale(dummy, DUMMY_SIZE, DUMMY_SIZE, DUMMY_SIZE)
                
                //=================================================================================
                //============= Incase you added or removed an effect(s) ==========================
                call DestroyEffect( AddSpecialEffectTarget(IMPACT_EXPLOSION, dummy, "origin" ) )
                call DestroyEffect( AddSpecialEffectTarget(IMPACT_EXPLOSION2, dummy, "origin" ) )
                call DestroyEffect( AddSpecialEffectTarget(IMPACT_EXPLOSION3, dummy, "origin" ) )
                //==================================================================================
                //==================================================================================
                
                call ShowUnit(.caster, true)
            endif
            
            call RemoveUnit(.bird)
            call KillUnit(dummy)
            call ReleaseGroup(.g)
            set first = null
            set dummy = null
        endmethod
    endstruct
  
//===========================================================================
private function Actions takes nothing returns nothing
    local unit caster   = GetTriggerUnit()
    local location loc  = GetSpellTargetLoc()
    local real casterX  = GetUnitX(caster)
    local real casterY  = GetUnitY(caster)
    local real x        = GetLocationX(loc)
    local real y        = GetLocationY(loc)
    local real rangex   = x - casterX
    local real rangey   = y - casterY
    local real range    = SquareRoot(rangex*rangex + rangey*rangey)
    local real angle    = Atan2(rangey, rangex)
    local real X        = casterX- BIRD_START * Cos(angle)
    local real Y        = casterY- BIRD_START * Sin(angle)
    local unit bird
    
    if not RectContainsCoords(bj_mapInitialPlayableArea, X, Y) then
        set bird = CreateUnit( GetOwningPlayer(caster), BIRD_ID, casterX, casterY, bj_RADTODEG*angle )
    else
        set bird = CreateUnit( GetOwningPlayer(caster), BIRD_ID, X, Y, bj_RADTODEG*angle )
    endif
    
    call UnitAddAbility(bird, CROW_ABILITY)
    call UnitRemoveAbility(bird, CROW_ABILITY)
    call SetUnitFlyHeight(bird, BIRD_HEIGHT, 0)
    call Aerial.start(caster, bird, x, y, angle, range)
    call RemoveLocation(loc)
    
    set loc     = null
    set caster  = null
    set bird    = null
endfunction

private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == ABILITY_ID
endfunction

//===========================================================================
private function Init takes nothing returns nothing
    local trigger t = CreateTrigger()
    local integer i = 0
    loop
        call TriggerRegisterPlayerUnitEvent( t, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, BOOLEXPR_TRUE ) //Recycler
        exitwhen i >= 15
        set i = i+1
    endloop
    call TriggerAddCondition( t, Condition( function Conditions ) )
    call TriggerAddAction( t, function Actions )
endfunction

endscope

Code:
//---11/8/08---\\
*Uses Vex's model so that the sfx size is alterable
*Small Clean up

//---10/26/08---\\
*Clean up coding (much easier to follow)

//---3/5/08----\\
* Fixed struct leak
* Fixed a little config error
* Made the "How to Implement" a bit more detailed.
** Got rid of Camera pan
** Added a error msg (Now needs SimError also)
** Does not use GetUnitFacing anymore

//---3/4/08----\\
* Took more of Cohadar's advise and changed more some coding
* Fix the target location, thx to Cohadar
* Little more optimization here and there
* Forgot that the bird takes half your mana, fixed that
* Added a "how to implement" in the map. (dunno how to get more detailed than that...)

//---3/3/08----\\
* Took some of Cohadar's advise and changed some coding
* Changed some other coding myself
* Made it easier for you to turn on Collision explosion
* Made nothing happen if bird does not pick you up.
* Made you level 1 on test map to show better the bird size.
* Test it in debug mode to see the damage dealt.
 

Attachments

  • Joker(Div) - Aerial Strike.w3x
    61.7 KB · Views: 474

Sim

Forum Administrator
Staff member
Reaction score
534
How To Implement:
  • Create a Trigger
  • Name it: AerialStrike
  • Make a spell based on channel
  • Make a flying dummy unit

You mean "Copy the trigger AerialStrike" I hope. :)
Actually, I hope you meant "Copy" on each line too.
 

Arcane

You can change this now in User CP.
Reaction score
87
So THAT'S what the KotG projectile looks like when it's enlarged. Interesting...
 

GoGo-Boy

You can change this now in User CP
Reaction score
40
Ohh my god!! So awesome innovative! ;D
I really love it. You definitely deserve a +Rep for this. It simply looks wonderful. Though one thing makes it look too hasty on the other side, the animation of the unit/projectile is too fast, which probably is a consequence of the fact that this model is used to be a projectile and no bigger model.
But else the model is perfect :) and it's no problem for people, since the model can be changed anyway hehe
 

darkRae

Ueki Fan (Ueki is watching you)
Reaction score
173
> So THAT'S what the KotG projectile looks like when it's enlarged. Interesting...

Actually, it's Human Priest's.
 

GoGo-Boy

You can change this now in User CP
Reaction score
40
As far as I know they are simply differently colored...

However to the spell, though awesome, I found something that has to be fixed. It's a channel ability and therefore should NOT mess up when canceled, but it does. The bird flies weird curves and you still get blinked and even (only when canceled) damaged.
And I'm not sure whether this problem rarely occurred as well when I didn't cancel the spell.

However: You should post this spell on the dota allstars forum, because spells that transport you to an other position in a unique way are beloved, and this one is so f##king nice :)
 

Cohadar

master of fugue
Reaction score
209
This is bad.
JASS:

    private constant real BIRD_SPEED = 25.       //X this by 32, or however fast you made TT to get Units/Sec
    private constant real BIRD_DESCEND = 15.     //X this by 32, or however fast you made TT to get Units/Sec


First of all those are not speeds but delta speeds.
Delta speed is a distance an object will move during one quantum of time (during one tick)

The proper way to do this is to use real speeds and TT_PERIOD constant.
JASS:

    // Those are the real game speeds, like the move speed of units
    // heroes usually move in range 300 - 350  << Movement - Speed Base >>
    // 522 is the maximum speed units can move (without triggers)
    // projectiles usually move in range 900 - 1600 << Combat - Attack 1 - Proojectile Speed >>
    // 
    private constant real BIRD_SPEED = 800.
    private constant real BIRD_DESCEND = 480.


Then you calculate the delta speeds in the trigger actions
JASS:

    set data.dSpeed = BIRD_SPEED * TT_PERIOD
    set data.dDescend = BIRD_DESCEND * TT_PERIOD


This way it is much easier to configure the speeds because you can directly compare then to standard game speeds.
It is also independent of what TT period you use.
Spell will behave the same for two people using same spell with differently set TT periods. (witch was the whole idea of making TT_PERIOD public)

I believe this was well demonstrated in TT demo map.

Also when you move unit in one direction it is pointless to calculate Cos and Sin every time. You can use deltaX and deltaY directly.
(again demonstrated in demo map)

I know it is easier to simply write 25. and 15. than to do extra brainwork but trust me - it is worth it.

For the end a couple of useful formulas:
JASS:

    ds == speed*TT_PERIOD
    dx == ds*Cos(angle)
    dy == ds*Sin(angle)
    ticks == R2I(distance/ds)
 
T

Tubba

Guest
It seemed to bug when close to boundaries, too. Otherwise, pretty nice.
 

Joker(Div)

Always Here..
Reaction score
86
I love you Cohadar <3

@Flare, That's why I got the 3rd screenshot, the effects are quick so its hard to capture it. You can change it anyway. :p

@Tubba, I can't control that, map boundaries are evil.

@GoGo-Boy, Sorry I missed your posts. Thx for the nice comments. :) Anyway, the spell is not really a channeling spell. I just put a casting time so you won't move from the point you casted (The bird would miss you). The wierd curves are proly caused by the map boundaries. I can't control that. Also, I am not gonna go bother the dota community. 80% of the people there have an IQ of 50. You are welcome to suggest the spell yourself, post the test map if you want to also.

NEW UPDATE 3/3/08
 

GoGo-Boy

You can change this now in User CP
Reaction score
40
Edit: Ohh... I see that you updated and removed that? I'll test it right now^^
Edit2: Now this way it's really nice, that the bird flies even when channeling is canceled and IF he comes close to you still moves you but else simple disappear... really, really nice way you erased the problems ;)
To the dota community, well I dunno, they always seemed fine to me (not the gamer for sure lol >_<) and the map is well made with nice coding, therefore I though it's nice to know a spell of oneself in such a nice map (please, nobody should start to talk about dota, I know there are different opinions about it :D)

PS: Can someone tell me how I can cross out text? So that I don't have to remove text I wrote because I noticed it's useless anymore but people might wonder if I simply remove it :d
 

Sim

Forum Administrator
Staff member
Reaction score
534
Implementation Instructions need to be inside the map.

Please make them more detailed too...

As for the spell: Great idea!

Love how it works out!

You got a few problems though...

  • I actually died at some point when casting this. Without any reason. If it can help you, I died when reaching the destination point.
  • Reselect the hero once the spell is over. It is annoying to select it again.
  • Your spell is acting weird, often. First of all, the blink should transport you to the destination point, not a set distance away, as blink does. Second, sometimes my hero wouldn't disappear "inside" the bird. I just got teleported a couple seconds later. Third, It doesn't always act the same way. Sometimes it teleports you to the target point, sometimes not, sometimes it lags a bit...

Nice spell overall, but it needs a bit of fixing!
 

Joker(Div)

Always Here..
Reaction score
86
@Daxtreme

"I actually died at some point when casting this. Without any reason. If it can help you, I died when reaching the destination point."
- Uh...your hero died while he was hidden?

"Reselect the hero once the spell is over. It is annoying to select it again."
- I'm pretty sure it does, unless you tested the older version.

"Your spell is acting weird, often. First of all, the blink should transport you to the destination point, not a set distance away, as blink does. Second, sometimes my hero wouldn't disappear "inside" the bird. I just got teleported a couple seconds later..."
- You must be testing the older version. I'll still try optimize this those, just to make sure.

"...Third, It doesn't always act the same way. Sometimes it teleports you to the target point, sometimes not, sometimes it lags a bit..."
- It lags?! :( Can you find any leaks?

Thx for those comments :D
 

Sim

Forum Administrator
Staff member
Reaction score
534
> - You must be testing the older version. I'll still try optimize this those, just to make sure.

Indeed.

Alright, new report. :D

It seems the bird is bugging hardcore when either his spawn point or his (not yours) destination point is outside the map's bounds. Simply check if the point's location is pathable, and if it isn't, find a pathable point nearby.

Because right now, if the bird's spawning and landing positions are unpathable, it just doesn't work at all.:rolleyes:
 

Joker(Div)

Always Here..
Reaction score
86
aw, you posted too early...Just got a new update. :(

Do I have to make a pathing checker? :( You can get rid of/lower the bird starting position to help with that. I just added it for the eyecandy. Most maps should be big enough, boundaries shouldn't be a prob.

NEW UPDATE 3/4/08
 

Sim

Forum Administrator
Staff member
Reaction score
534
Well, either cancel the spell or something. Warning message?

Oh and, please get rid of that camera lock. It's a spell, not a cinematic! :)
 

Joker(Div)

Always Here..
Reaction score
86
You could easily delete the camera lock yourself, had a text in there saying so, but w/e. I got rid of it anyway.

Added a error msg using SimError.

I sense an approval. :D
 

Sim

Forum Administrator
Staff member
Reaction score
534
> I sense an approval.
> I don't sense an approval?...

Ya gotta let me some time. :D

Approved. Great job!
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • Ghan Ghan:
    Still lurking
    +3
  • The Helper The Helper:
    I am great and it is fantastic to see you my friend!
    +1
  • The Helper The Helper:
    If you are new to the site please check out the Recipe and Food Forum https://www.thehelper.net/forums/recipes-and-food.220/
  • Monovertex Monovertex:
    How come you're so into recipes lately? Never saw this much interest in this topic in the old days of TH.net
  • Monovertex Monovertex:
    Hmm, how do I change my signature?
  • tom_mai78101 tom_mai78101:
    Signatures can be edit in your account profile. As for the old stuffs, I'm thinking it's because Blizzard is now under Microsoft, and because of Microsoft Xbox going the way it is, it's dreadful.
  • The Helper The Helper:
    I am not big on the recipes I am just promoting them - I use the site as a practice place promoting stuff
    +2
  • Monovertex Monovertex:
    @tom_mai78101 I must be blind. If I go on my profile I don't see any area to edit the signature; If I go to account details (settings) I don't see any signature area either.
  • The Helper The Helper:
    You can get there if you click the bell icon (alerts) and choose preferences from the bottom, signature will be in the menu on the left there https://www.thehelper.net/account/preferences
  • The Helper The Helper:
    I think I need to split the Sci/Tech news forum into 2 one for Science and one for Tech but I am hating all the moving of posts I would have to do
  • The Helper The Helper:
    What is up Old Mountain Shadow?
  • The Helper The Helper:
    Happy Thursday!
    +1
  • Varine Varine:
    Crazy how much 3d printing has come in the last few years. Sad that it's not as easily modifiable though
  • Varine Varine:
    I bought an Ender 3 during the pandemic and tinkered with it all the time. Just bought a Sovol, not as easy. I'm trying to make it use a different nozzle because I have a fuck ton of Volcanos, and they use what is basically a modified volcano that is just a smidge longer, and almost every part on this thing needs to be redone to make it work
  • Varine Varine:
    Luckily I have a 3d printer for that, I guess. But it's ridiculous. The regular volcanos are 21mm, these Sovol versions are about 23.5mm
  • Varine Varine:
    So, 2.5mm longer. But the thing that measures the bed is about 1.5mm above the nozzle, so if I swap it with a volcano then I'm 1mm behind it. So cool, new bracket to swap that, but THEN the fan shroud to direct air at the part is ALSO going to be .5mm to low, and so I need to redo that, but by doing that it is a little bit off where it should be blowing and it's throwing it at the heating block instead of the part, and fuck man
  • Varine Varine:
    I didn't realize they designed this entire thing to NOT be modded. I would have just got a fucking Bambu if I knew that, the whole point was I could fuck with this. And no one else makes shit for Sovol so I have to go through them, and they have... interesting pricing models. So I have a new extruder altogether that I'm taking apart and going to just design a whole new one to use my nozzles. Dumb design.
  • Varine Varine:
    Can't just buy a new heatblock, you need to get a whole hotend - so block, heater cartridge, thermistor, heatbreak, and nozzle. And they put this fucking paste in there so I can't take the thermistor or cartridge out with any ease, that's 30 dollars. Or you can get the whole extrudor with the direct driver AND that heatblock for like 50, but you still can't get any of it to come apart
  • Varine Varine:
    Partsbuilt has individual parts I found but they're expensive. I think I can get bits swapped around and make this work with generic shit though
  • Ghan Ghan:
    Heard Houston got hit pretty bad by storms last night. Hope all is well with TH.
  • The Helper The Helper:
    Power back on finally - all is good here no damage
    +2
  • V-SNES V-SNES:
    Happy Friday!
    +1
  • The Helper The Helper:
    New recipe is another summer dessert Berry and Peach Cheesecake - https://www.thehelper.net/threads/recipe-berry-and-peach-cheesecake.194169/

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top