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: 472
That's amazing, +rep.

One thing, when the bountyhunter get the glaive back on them, could the play spell animation?
 
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).
 
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
 
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
 
Your codes very messy.
Remove all the commented lines that aren't comments to the configurable's;
Then I'll read over it :) .
 
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)
 
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?
 
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" )
 
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 >.>
 
"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.

      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