• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Spin Bash

this is my spell Spin Bash requested by Aelita.

Spin Bash
The Blademaster spins the target around, damaging all enemies in range. After some time he releases his target, throwing it far away.
The spell is in vJass, is MUI and easy configurable...

A How To Import is included!

Needs JNGP to work well!!!

JASS:
scope SpinBash initializer Init

// Spin Bash by The_Witcher

// The Blademaster spins the target around, 
// damaging all enemies in range.
// After some time he releases his target, throwing it away.

globals
    // the rawcode of your ability(press CTRL + D in object editor)
    private constant integer SpellID = 'A000'
    
    // the interval of the timer (increase if laggy)
    private constant real interval = 0.01
    
    // the distance between the target and the caster when
    // spinnig around
    private constant real SpinDistance = 150
    
    // the curve is a constant used by the parabola forumla
    private constant real Curve = 1.5
    
    // this is the range in where units have to be around the target
    // to get damaged
    private constant real DamageRange = 80
endglobals

private function GetRotateTime takes integer lvl returns real
    local real lowest  = IMaxBJ(4-lvl,0)
    local real highest = lowest + 2
    return GetRandomReal(lowest,highest)  // on lvl 1 between 4 and 6 seconds
endfunction

private function GetThrowDistance takes integer lvl returns real
    return 200.*lvl  //100 on lvl 1, 200 on lvl 2,...
endfunction

private function GetRotateSpeed takes integer lvl returns real
    return 4.*lvl    // +4 degree every interval
endfunction

private function GetSpinDamage takes  integer lvl  returns real
    return 30.*lvl   // every unit hit by the spinning/thrown unit takes this damage (here 30/60/90)
endfunction

private function GetTargetDamage takes  integer lvl  returns real
    return 40.*lvl  // the damage the target takes (here 40/80/120)
endfunction

//-----------Don't modify anything below this line---------

private struct data
    unit u
    unit v
    real a
    real d
    real s
    real maxd
    integer lvl
    integer mode = 1
    real dmg1
    real dmg2
    group DamageOnceGroup
endstruct

globals
    private data array DATAS
    private integer total = 0
    private timer tim = CreateTimer()
    private group g = CreateGroup()
    private item ite
    private player TempPlayer
    private data TempDat
endglobals

private function IsCoordPathable takes real x, real y returns boolean
    local real xx
    local real yy
    call SetItemVisible(ite,true)
    call SetItemPosition(ite,x,y)
    set xx = GetItemX( ite ) - x
    set yy = GetItemY( ite ) - y
    call SetItemVisible(ite,false)
    if xx < 1 and xx > -1 and  yy < 1 and yy > -1 then
        return true
    endif
    return false
endfunction

private function JumpParabola takes real dist, real maxdist, real curve returns real
    local real t = (dist * 2) / maxdist - 1
    return (- t * t + 1) * (maxdist / curve)
endfunction

private function EnemiesOnly takes nothing returns boolean
    return IsUnitEnemy(GetFilterUnit(),TempPlayer) and not (IsUnitType(GetFilterUnit(),UNIT_TYPE_DEAD) or GetUnitTypeId(GetFilterUnit()) == 0 )
endfunction

private function Damage takes nothing returns nothing
    if not IsUnitInGroup(GetEnumUnit(),TempDat.DamageOnceGroup) then
        call UnitDamageTarget(TempDat.u,GetEnumUnit(),TempDat.dmg1,true,false,ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
        call GroupAddUnit(TempDat.DamageOnceGroup,GetEnumUnit())
    endif
endfunction

private function execute takes nothing returns nothing
    local data dat
    local integer i = 0
    local real x
    local real y
    local unit u
    loop
        exitwhen i >= total
        set dat = DATAS[i]
        if dat.mode == 1 then
        // Spinning around
            set x = GetUnitX(dat.u) + SpinDistance * Cos(dat.a*bj_DEGTORAD)
            set y = GetUnitY(dat.u) + SpinDistance * Sin(dat.a*bj_DEGTORAD)
            call SetUnitX(dat.v,x)
            call SetUnitY(dat.v,y)
            call SetUnitFacing(dat.v,dat.a-180)
            set dat.a = dat.a + dat.s
            set dat.d = dat.d - interval
            set TempPlayer = GetOwningPlayer(dat.u)
            call GroupEnumUnitsInRange(g,GetUnitX(dat.v),GetUnitY(dat.v), DamageRange,Condition(function EnemiesOnly))
            call GroupRemoveUnit(g,dat.v)
            set TempDat = dat
            call ForGroup(g, function Damage)
            call GroupClear(g)
            if dat.a > 360 then
                set dat.a = dat.a - 360
                call GroupClear(dat.DamageOnceGroup)
            endif
            if dat.d <= 0 then
                set dat.d = 0 
                set dat.maxd = GetThrowDistance(dat.lvl)
                set dat.mode = 2
                call PauseUnit(dat.u,false)
                call SetUnitAnimation(dat.u,"stand")
                call GroupClear(dat.DamageOnceGroup)
            endif
        else
        // throw
            set x = GetUnitX(dat.v) + dat.s * Cos(dat.a*bj_DEGTORAD)
            set y = GetUnitY(dat.v) + dat.s * Sin(dat.a*bj_DEGTORAD)
            if IsCoordPathable(x,y) then
                call SetUnitX(dat.v,x)
                call SetUnitY(dat.v,y)
                call GroupEnumUnitsInRange(g,GetUnitX(dat.v),GetUnitY(dat.v), DamageRange,Condition(function EnemiesOnly))
                call GroupRemoveUnit(g,dat.v)
                set TempDat = dat
                call ForGroup(g, function Damage)
                call GroupClear(g)
            endif
            set dat.d = dat.d + dat.s
            if dat.mode == 3 then
                call SetUnitFlyHeight(dat.v,JumpParabola(dat.d,dat.maxd,Curve),0)
            else
                call SetUnitFlyHeight(dat.v,JumpParabola(dat.d,dat.maxd,Curve*3),0)
            endif
            if dat.d >= dat.maxd and dat.mode == 2 then
                set dat.d = 0 
                set dat.maxd = GetThrowDistance(dat.lvl) / 3
                set dat.mode = 3
                call GroupClear(dat.DamageOnceGroup)
                call UnitDamageTarget(dat.u,dat.v,dat.dmg2,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
            elseif dat.d >= dat.maxd and dat.mode == 3 then
                call SetUnitFlyHeight(dat.v,0,0)
                call PauseUnit(dat.v,false)
                call SetUnitTimeScale(dat.v,1)
                call DestroyGroup(dat.DamageOnceGroup)
                set total = total - 1
                set DATAS[i] = DATAS[total]
                call dat.destroy()
                set i = i - 1
            endif
        endif
        set i = i + 1
    endloop
    if total == 0 then
        call PauseTimer(tim)
    endif
endfunction

private function start takes nothing returns boolean
    local data dat
    if GetSpellAbilityId() == SpellID then
        set dat = data.create()
        set dat.u = GetTriggerUnit()
        set dat.v = GetSpellTargetUnit()
        set dat.a = bj_RADTODEG * Atan2(GetUnitY(dat.v) - GetUnitY(dat.u), GetUnitX(dat.v) - GetUnitX(dat.u))
        set dat.lvl = GetUnitAbilityLevel(dat.u,SpellID)
        set dat.d = GetRotateTime(dat.lvl)
        set dat.s = GetRotateSpeed(dat.lvl)
        set dat.dmg1 = GetSpinDamage(dat.lvl)
        set dat.dmg2 = GetTargetDamage(dat.lvl)
        set dat.DamageOnceGroup = CreateGroup()
        call IssueImmediateOrder(dat.u,"stop")
        call PauseUnit(dat.u,true)
        call PauseUnit(dat.v,true)
        call SetUnitTimeScale(dat.v,0)
        call SetUnitAnimation(dat.u,"spin")
        call UnitAddAbility(dat.v,'Amrf')
        call UnitRemoveAbility(dat.v,'Amrf')
        set DATAS[total] = dat
        set total = total + 1
        if total == 1 then
            call TimerStart(tim,interval,true, function execute)
        endif
    endif
    return false
endfunction

private function Init takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerAddCondition(t,Condition(function start))
    call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    set ite = CreateItem('wolg',0,0)
    call SetItemVisible(ite,false)
    call SetItemInvulnerable( ite, true)
endfunction

endscope

Keywords:
spin, throw, away, damage, group, AOE, MUI, vJass, jass, blademaster
Contents

Noch eine WARCRAFT-III-Karte (Map)

Reviews
12:37, 20th Dec 2009 TriggerHappy: Review for Spin Bash Please use a scope, not a library. You should probably use Dusk's pathablity script instead of your own function. I'm pretty sure there is an inlinable jump parabola somewhere. A...

Moderator

M

Moderator

12:37, 20th Dec 2009
TriggerHappy:

Review for Spin Bash

  • Please use a scope, not a library.
  • You should probably use Dusk's pathablity script instead of your own function.
  • I'm pretty sure there is an inlinable jump parabola somewhere.
  • A Timer attachment system would most likely be better than an
    O(n) search.
  • FirstOfGroup loops are the slowest AFAIK.

Status

Feel free to message me here if you have any issues with
my review or if you have updated your resource and want it reviewed again.

Approved
 
Top