Spell Glaive Bounce

BlackRose

Forum User
Reaction score
239
No... not some weird attack modifying spell.

Glaive Bounce by BlackRose v1.02b

glaivebounce.jpg


Creates 2 transparent like guards, they then throw a glaive that bounces off them, dishing out damage between enemy units hit by the glaive.

  • It is MUI.
  • No it will not lag, even on lots of instances.
  • Quite amusing.

Requirements:
- JassNewGenPack
- SimError - Vexorian
- KeyTimers2 - Jesus4Lyf

JASS:
Glaive Bounce by BlackRose
---------------------------

Version: 1.02b
Date released: 27th June 2009
Date updated: 4th July 2009

Makes a glaive that bounces between 2 spirits, it keeps deflecting, 
damage enemy units in the way.

How to import:
--------------

 - Make sure you have JassNewGenPack.

1. Copy GlaiveBounce, SimError, and KT trigger into your map.
2. Copy all objects needed.
3. Make sure to update rawcode.
4. Done!

Version history:
----------------
v1.00: 27th June 2009
 - Initial release.
 
v1.01: 27th June 2009
 - Made transparency customizable.
 - Guards now play Spell Animation (7) when they delflect Glaive.

v1.01b: 27th June 2009
 - Small code update.
 
v1.01c: 27th June 2009
 - Another small update.
 
v1.02: 28th June 2009
 - Code updates.
 - Made it so you can see how many bounces there are, <-- Configurable as well.
 - Made text appear on enemy units to show how much damage done.
 - Fixed something to do with map boundary.
 
 v1.02b: 4th July 2009
  - Code update.
  - Extra configurables.

Credits:
--------

- Blitz for suggestion playing animation when Glaive reflects.
- emjlr3 for AnimIndexs finding out, though it is not even hard to make.
- Jesus4Lyf for KeyTimers2.
- Vexorian for SimError.

- JassNewGenPack team.

- Made for TheHelper.net AND ClanMapz.com Resources forum, DO NOT REDISTRUBUTE at all. 
  Contact can be made by PMing me at TheHelper forums, Username: BlackRose

JASS:
scope GlaiveBounce initializer Init

    globals
        // OBJECT CONFIGURABLES
        // ----------------------------------------------------------------------------
        private constant integer SPELL_ID = 'A000'  // Glaive Bounce rawcode.
        private constant integer DUMMY_ID = 'h005'  // Glaive rawcode.
        private constant integer GUARD_ID = 'e001'  // Reflector rawcode.
    
        // You could kill a group of units easy by placing right next to you.
        // Allow this?
        private constant string MIN_RANGE_MSG = "Target is inside minimum range."
        private constant boolean ALLOW_MIN_RANGE = true

        private constant boolean RECLICK = true     // If point is in min-range, re click?
        private constant string SPELL_HOTKEY = "B"  // Hotkey.
        
        // OTHER CONFIGURABLES
        //----------------------------------------------------------------------------
        private constant real TIMER_INTERVAL = 0.03 // Every 0.03 do action.
        private constant integer END_TYPE = 1 //<- Set to 0 or 1.
        // END_TYPES - How the spell ends, after certain time or after bounces/
        // 0 = Time limit.
        // 1 = Bounces limit.
    
        // DAMAGE CONFIGURABLES
        // ----------------------------------------------------------------------------
        
        private constant attacktype ATK_TYPE = ATTACK_TYPE_NORMAL   // Attack type
        private constant damagetype DMG_TYPE = DAMAGE_TYPE_MAGIC    // Damage type
        private constant weapontype WPN_TYPE = null                 // Weapon type
        
        // COSMETIC CONFIGURABLES
        // ----------------------------------------------------------------------------
        private constant boolean SHOW_DMG_TT = true // Show damage text above target? True or false.
        private constant string DMG_TT_COLOR = "|cffff0000" // Damage text color, right now is RED.
        private constant real DMG_TT_SIZE    = 10.5 // Text size.
        
        private constant boolean SHOW_BOUNCE_TT = true         // Show bounces on Guard?
        private constant string BOUNCE_TT_COLOR = "|cff87ceeb" // Color of above? Right now is LIGHT BLUE
        private constant real BOUNCE_TT_SIZE    = 12 // Text size.
        
        private constant integer ANIMATION = 7  // Animation index of Guard, type -anim in this testmap to find out indexes. 
                                                // Credit to emjlr3.
                                                
        // Colors of Guard, can be edited here OR Object Editor. In Percentage here.
        private constant real RED          = 100.
        private constant real BLUE         = 100.
        private constant real GREEN        = 100.
        private constant real TRANSPARENCY = 50. // How much transparency Guard has. Max of 100.
        
        // Effects
        private constant string ATH_POINT = "chest"         // Where on targets place SFX?
        private constant string REFLECT_POINT = "origin"    // Where on Guard reflect?
        private constant string REFLECT_SFX = "Abilities\\Spells\\Human\\Defend\\DefendCaster.mdx"          // Reflect SFX.
        private constant string DAMAGE_SFX = "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdx" // Damage targets SFX.
    endglobals
    
    // AoE of Glaive Damage, right now is 140. But you can set it up whatever.
    private function GetAoE takes integer Level returns real
        return 140 + ( Level * 0. )
    endfunction
    // Minimum range you can cast. 400/450/500/550.
    private function GetMinRange takes integer Level returns real
        return 350 + ( Level * 50. )
    endfunction
    // Damage. It is level * 20 right now, so its 20/40/60/80
    private function GetDamage takes integer Level returns real
        return Level * 20.
    endfunction
    // Speed of the missile moving.
    private function GetSpeed takes integer Level returns real
        return Level * 30.
    endfunction
    // How many bounces there are.
    private function GetBounces takes integer Level returns real
        return Level * 5.
    endfunction
    // Or how long will the spell last.
    private function GetTime takes integer Level returns real
        return Level * 2.5
    endfunction
    
    //===========================================================================
    // Only modify below if you know how to.
    //===========================================================================
    
function QTT takes string Message, real x, real y, real angle, real dur, real size returns nothing
    local texttag tt = CreateTextTag()
    local real vel = 90 * 0.071 / 128
    local real xvel = vel * Cos( angle )
    local real yvel = vel * Sin( angle )
    
    call SetTextTagText( tt, Message, size * 0.0023 )
    call SetTextTagPos( tt, x, y, 0 )
    call SetTextTagPermanent( tt, false )
    call SetTextTagVelocity( tt, xvel, yvel )
    call SetTextTagFadepoint( tt, dur - 0.50 )
    call SetTextTagLifespan( tt, dur )

    set tt = null
endfunction

    globals
        private player TempPlayer
        private group TempGroup
        private group G = CreateGroup()
        private boolexpr UFilter 
        
    endglobals
    
// Conditions.
private function UFilt takes nothing returns boolean
    return IsUnitType( GetFilterUnit(), UNIT_TYPE_DEAD ) == false and IsUnitEnemy( GetFilterUnit(), TempPlayer ) and IsUnitInGroup( GetFilterUnit(), TempGroup ) == false
endfunction

private struct xxData
    boolean BounceBack = false

    unit Caster
    unit Missile
    unit Guard1
    unit Guard2
    player Owner
    
    group DamageGroup
    
    real tx
    real ty
    real MaxTime
    real MaxBounces
    real Damage
    real Speed
    real AoE
    
    real Time = 0.00
    integer Bounces = 0
    method onDestroy takes nothing returns nothing
        call KillUnit( .Missile )
        call RemoveUnit( .Guard1 )
        call RemoveUnit( .Guard2 )
        call DestroyGroup( .DamageGroup )
    endmethod
    
    static method create takes nothing returns xxData
        local xxData d = xxData.allocate()
        local integer level
        local integer i = 0
        local real array x
        local real array y
        local real cx
        local real cy
        local location l = GetSpellTargetLoc()
        local real Angle
        
        local integer r = R2I(RED * 2.55 )
        local integer b = R2I(BLUE * 2.55 )
        local integer g = R2I(GREEN * 2.55 )
        local integer t = R2I(TRANSPARENCY * 2.55 )

        set d.DamageGroup = CreateGroup()

        set d.Caster = GetTriggerUnit()
        set d.Owner = GetOwningPlayer( d.Caster )
        set level = GetUnitAbilityLevel( d.Caster, SPELL_ID )
        
        // Saving func calls.
        set d.MaxBounces = GetBounces( level )
        set d.MaxTime = GetTime( level )
        set d.Damage = GetDamage( level )
        set d.Speed = GetSpeed( level )
        set d.AoE = GetAoE( level )
        
        set cx = GetUnitX( d.Caster )
        set cy = GetUnitY( d.Caster )
        
        set d.tx = GetLocationX( l )
        set d.ty = GetLocationY( l )
        
        set Angle = bj_RADTODEG * Atan2( d.ty - cy, d.tx - cx )
        set d.Missile = CreateUnit( d.Owner, DUMMY_ID, cx, cy, Angle )
        set d.Guard1 = CreateUnit( d.Owner, GUARD_ID, cx, cy, Angle )
        set Angle = bj_RADTODEG * Atan2( cy - d.ty, cx - d.tx )
        set d.Guard2 = CreateUnit( d.Owner, GUARD_ID, d.tx, d.ty, Angle )
        
        set d.tx = GetUnitX( d.Guard2 )
        set d.ty = GetUnitY( d.Guard2 )

        call SetUnitVertexColor( d.Guard1, r, b, g, t )
        call SetUnitVertexColor( d.Guard2, r, b, g, t )
        
        call RemoveLocation( l )
        set l = null
        
        return d
    endmethod
endstruct

private function Callback takes nothing returns boolean
    local xxData d = KT_GetData()

    local real x
    local real y
    local real nx
    local real ny
    local real angle
    
    local real dx
    local real dy

    local unit u
    set d.Time = d.Time + TIMER_INTERVAL
    
    debug call BJDebugMsg(R2S( d.Time ) )

    set x = GetUnitX( d.Missile )
    set y = GetUnitY( d.Missile )
    set angle = Atan2( d.ty - y, d.tx - x )
    set nx = x + d.Speed * Cos( angle )
    set ny = y + d.Speed * Sin( angle )
    
    set dx = d.tx - nx
    set dy = d.ty - ny
        
    call SetUnitX( d.Missile, nx )
    call SetUnitY( d.Missile, ny )
    
    set TempPlayer = d.Owner
    set TempGroup = d.DamageGroup
    call GroupEnumUnitsInRange( G, nx, ny, d.AoE, UFilter )
    loop
        set u = FirstOfGroup( G )
        exitwhen u == null
        call GroupRemoveUnit( G, u )
        call GroupAddUnit( d.DamageGroup, u )
        
        if SHOW_DMG_TT then
            call QTT( DMG_TT_COLOR + I2S( R2I( d.Damage ) ) + "|r", GetUnitX( u ), GetUnitY( u ), 90, 1, DMG_TT_SIZE )
        endif
        
        call UnitDamageTarget( d.Caster, u, d.Damage, true, false, ATK_TYPE, DMG_TYPE, WPN_TYPE )
        call DestroyEffect( AddSpecialEffectTarget( DAMAGE_SFX, u, ATH_POINT ) )
    endloop
        // GLAIVE BOUNCES BACK
        // -------------------------
        if ( dx * dx + dy * dy ) < 8100 then
            set d.Bounces = d.Bounces + 1
            call GroupClear( d.DamageGroup )
            
            if SHOW_BOUNCE_TT and END_TYPE == 1 then
                // QuickTaxTag by ME
                call QTT( BOUNCE_TT_COLOR + I2S( d.Bounces ) + "|r", d.tx, d.ty, angle, 2, BOUNCE_TT_SIZE )
            endif
            if d.BounceBack then
                call SetUnitAnimationByIndex( d.Guard1, ANIMATION )
                call DestroyEffect( AddSpecialEffectTarget( REFLECT_SFX, d.Guard1, REFLECT_POINT ) )
                set d.BounceBack = false
                set d.tx = GetUnitX( d.Guard2 )
                set d.ty = GetUnitY( d.Guard2 )
            else
                call SetUnitAnimationByIndex( d.Guard2, ANIMATION )
                call DestroyEffect( AddSpecialEffectTarget( REFLECT_SFX, d.Guard2, REFLECT_POINT ) )
                set d.tx = GetUnitX( d.Guard1 )
                set d.ty = GetUnitY( d.Guard1 )
                set d.BounceBack = true
            endif
        endif
        
        if (d.Time >= d.MaxTime and END_TYPE == 0) or (d.Bounces >= d.MaxBounces and END_TYPE == 1) then
            if END_TYPE == 0 then
                debug call BJDebugMsg( "END_TYPE = 0, timer" )
            else
                debug call BJDebugMsg("END_TYPE = 1, bounces" )
            endif
            call d.destroy()
            return true
        endif
        
    return false
endfunction

private function Cond takes nothing returns boolean
    if GetSpellAbilityId() == SPELL_ID then
        call KT_Add( function Callback, xxData.create(), TIMER_INTERVAL )
    endif
    return false
endfunction
//===========================================================================
private function MinCond takes nothing returns boolean
    return GetSpellAbilityId() == SPELL_ID
endfunction

private function StopAction takes nothing returns nothing
    local location l = GetSpellTargetLoc()
    local unit u = GetTriggerUnit()
    local real dx = GetLocationX( l ) - GetUnitX( u )
    local real dy = GetLocationY( l ) - GetUnitY( u )
    if SquareRoot( dx * dx + dy * dy ) < GetMinRange( GetUnitAbilityLevel( u, SPELL_ID ) ) and ALLOW_MIN_RANGE then
        call IssueImmediateOrder( u, "stop" )
        call SimError( GetOwningPlayer( u ), MIN_RANGE_MSG )
        if GetLocalPlayer() == GetOwningPlayer( u ) then
            call ForceUIKey( SPELL_HOTKEY )
        endif
    endif
    call RemoveLocation( l )
    set l = null
    set u = null
endfunction
//==========================================================================
private function Init takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( t, Condition( function Cond ) )
    
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_CHANNEL )
    call TriggerAddCondition( t, Condition( function MinCond ) )
    call TriggerAddAction( t, function StopAction )

    set UFilter = Condition( function UFilt )
endfunction
endscope
 

Attachments

  • Glaive Bounce 1.02b.w3x
    33.9 KB · Views: 457

GetTriggerUnit-

DogEntrepreneur
Reaction score
129
That's amazing, +rep.

One thing, when the bountyhunter get the glaive back on them, could the play spell animation?
 

BlackRose

Forum User
Reaction score
239
One thing, when the Guard reflects the glaive, could they play the spell animation?
Proper English please :D

Ok, thanks for +REP.

I'll see to it, I actually thought of that to begin with... but didn't feel like finding Animation Indexes.

Well, I've updated:
- Transparency is now customizable.
- Guard's now play Spell Animation (7).
 

RaiJin

New Member
Reaction score
40
JASS:
        if d.Time >= d.MaxTime and END_TYPE == 0 then
            call d.destroy()
            return true
        endif
        
        if d.Bounces >= d.MaxBounces and END_TYPE == 1 then
            call d.destroy()
            return true
        endif


can be

JASS:
        if d.Time >= d.MaxTime and END_TYPE == 0 or d.Bounces >= d.MaxBounces and END_TYPE == 1 then
            call d.destroy()
            return true
        endif


i think that would work
 

BlackRose

Forum User
Reaction score
239
Nope, it does not work. I just tested it. Oops, fixed a small error:
JASS:
set d.Time = d.Time + 0.03 --- set d.time = d.Time + TIMER_INTERVAL
 

WolfieeifloW

WEHZ Helper
Reaction score
372
Your codes very messy.
Remove all the commented lines that aren't comments to the configurable's;
Then I'll read over it :) .
 
Reaction score
341
C/P'd from Clan Mapz.

  • JASS:
    // Hates working with maths. Using BJ.
    Then let me do it for you :p
    JASS:
    local integer v = R2I(100 * I2R(255) * 0.01 // Declare this at the top.
    call SetUnitVertexColor(d.Garud1, v, v, v, TRANSPARENCY)
    call SetUnitVertexColor(d.Garud2, v, v, v, TRANSPARENCY)
  • JASS:
    private function Action takes nothing returns nothing
        local xxData d = xxData.create()
        
        call KT_Add( function Callback, d, TIMER_INTERVAL )
    endfunction


    Can be inlined to;
    JASS:
    private function Action takes nothing returns nothing
        call KT_Add( function Callback, xxData.create(), TIMER_INTERVAL )
    endfunction
  • Using only a condition thread is supposedly faster; for example instead of adding an action and a condition you could do this;

    JASS:
    function actions takes nothing returns boolean
        if YOUR_CONDITION then
            // do your actions
            return false
        endif
        return false
    endfunction
    
    function init takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterSomeEvent(t)
        call TriggerAddCondition(t, Condition(function actions)
    endfunction
  • JASS:

    In your StopAction function you never null or destroy this.
    JASS:
    local unit u = GetTriggerUnit()

    Or that.
  • You may want to make int configurable whether or not to ignore pathing. (SetUnitX/Y or SetUnitPosition)
 

BlackRose

Forum User
Reaction score
239
Your codes very messy.
Remove all the commented lines that aren't comments to the configurable's;
Then I'll read over it .
Um.. what? I only got a few comments on the non-config lines...

@ Simonake
16 seconds must be a long time then.

@ TriggerHappy

- Your transparency thing with non-BJ doesn't work, TRANSPARARENCY is a real, non-bj takes integer lol.

-Done the inlining thingy.
-Removed and nulled l and u.

You may want to make int configurable whether or not to ignore pathing. (SetUnitX/Y or SetUnitPosition)
What? What do you mean by that... why would anyone want to make SetUnitPosition with a dummy?
 

WolfieeifloW

WEHZ Helper
Reaction score
372
I mean all this:
JASS:
//
        //private constant real TIME_LIMIT = 12   // Duration of spell if END_TYPE = 0.
        //private constant real BOUNCE_LIMIT = 10 // How many bounces before it can end.
        //private constant real SPEED = 50// How fast it will move.
            // Use only local code (no net traffic) within this block to avoid desyncs.

And why does it still have BJDebugMsg's?
JASS:
//
    debug call BJDebugMsg(R2S( d.Time ) )
            debug call BJDebugMsg( "END_TYPE = 0, timer" )
            debug call BJDebugMsg( "END_TYPE = 1, bounces" )
 

BlackRose

Forum User
Reaction score
239
private function UFilt takes nothing returns boolean
return IsUnitType( GetFilterUnit(), UNIT_TYPE_DEAD ) == false and IsUnitEnemy( GetFilterUnit(), TempPlayer ) and IsUnitInGroup( GetFilterUnit(), TempGroup ) == false
endfunction
Totally >.>
 

Andrewgosu

The Silent Pandaren Helper
Reaction score
716
"private constant real MIN_RANGE = 500"
"private constant real AOE = 140"

You should make these globals into constant functions, as well.


In the "create" method:

"local integer r = R2I( RED * I2R(255) * 0.01 )"

It can be just "R2I(RED * 2.55)", saves you a call.


I think you can omit the square root call in the "Callback" function if you're doing just a distance check:

"SquareRoot( dx * dx + dy * dy ) < 90" can just be "dx * dx + dy * dy < 8100"


Anyway, spell approved.
 
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