Snippet Spinning Attachment Tool

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
JASS:
Spinning Attachment Tool v1.3.0
                                present by kingking

What is the function of this tool?
    >>It enable users to put some spining attachment around units in an easy way.

Functions provided :
    >>SAT_Add takes unit u, integer id, string path, integer count, real range, real speed, real height, real size, integer facingstyle, boolean endeffect, code callback, integer data returns integer
    >>SAT_GetData -> integer
    >>SAT_Stop(integer)
    
For Advanced Jassers, you can use struct syntax :
    >> Struct Name : SAT
    >> static method create takes real x, real y
    >> method SetAttachTarget takes unit u
    >> method SetRange takes real range
    >> method SetSpeed takes real speed
    >> method SetEndEffect takes boolean WantEndEffect
    >> method SetFacingStyle takes integer Style
    >> method CreateEffects takes integer Count, integer id, string ModelPath
    >> method SetHeight takes real height
    >> method SetSize takes real size
    >> method AddCallback takes code callback, integer callback_data
    >> method SetXY takes real x, real y//Use this when no unit is attached on the instance.
    >> method Start()
    
    >> Change these variables can make it more freedom to spin at multiple style
    
    What is needed?
    >>Dummy model by Vexorian.
    >>JassHelper 0.9.G.2 or newer. (Lower version may support, but it is untested.) 
    
Provided Facing Style:
1) All effects follow target's facing + 90.
2) All effects face outward.
3) All effects have same angle which the angle will change over time.
4) All effects follow target's facing.
5) All effects face inward.

**If you put 5 or above value in the Facing Style argument, it will automatically revert it to 1 to prevent bug.

Tricky Info :
1) Put negative in rotate speed value to make effects spin clockwise.
2) Put 0 in rotate speed value to make effects follow the caster without spinning.
3) The callback will stop when returned value is true
4) SetHeight and SetSize will not apply settings if it is called before CreateEffect.
5) ID argument in CreateEffect : Put 0 to use default dummy or put the rawcode of your dummy if the effect of the result is not satisfied.



JASS:
library SAT
/////////////////////////////User defined constant//////////////////////////////////////////
globals
    private constant integer DUMMY_ID = 'h000'//Dummy's id
    private constant integer FLY_HACK = 'Arav'//Fly Trick
    private constant real HANDLER_SPEED = .03125//Timer's callback speed
    private constant integer MAX_ATTACHMENT = 36//Max number of effect on per instance.
endglobals

//////////////////////////////DO NOT TOUCH BELOW THIS LINE//////////////////////////////////
globals
    private constant timer t = CreateTimer()
    private integer array Data
    private integer Counter = 0
    private integer bj_lastCallbackData = 0
endglobals


public function GetData takes nothing returns integer
    return bj_lastCallbackData
endfunction

public function Add takes unit u, integer id, string path, integer count, real range, real speed, real height, real size, integer facingstyle, boolean endeffect, code c, integer data returns integer
    local SAT d = SAT.create(GetUnitX(u),GetUnitY(u))
    call d.SetAttachTarget(u)
    call d.SetRange(range)
    call d.SetSpeed(speed)
    call d.SetEndEffect(endeffect)
    call d.SetFacingStyle(facingstyle)
    call d.CreateEffect(count,id,path)
    call d.SetHeight(height)
    call d.SetSize(size)
    call d.AddCallback(c,data)
    //Hook new instance to rotating instances
    call d.Start()
    return d
endfunction

private function Handler takes nothing returns nothing
    local integer i = Counter
    loop
    //Rotate
    exitwhen i == 0
        if not SAT(Data<i>).stop then
            //Rotate
            call SAT(Data<i>).rotate()
        else
            //If the instance is demanded to destroy...
            call SAT(Data<i>).destroy()
            set Data<i> = Data[Counter]
            //Defragment instance
            set Counter = Counter - 1
        endif
        set i = i - 1
    endloop
    if Counter == 0 then
        call PauseTimer(t)
    endif
endfunction


struct SAT
    private unit cs
    private integer style
    private boolean endeffect
    private real range
    private real rotatespeed
    private real size
    private unit array dummies[MAX_ATTACHMENT]
    private effect array eff[MAX_ATTACHMENT]
    private integer count
    private real angle
    private real currentangle
    private integer callbackData
    private trigger callback = CreateTrigger()
    private triggercondition ta
    boolean stop
    
    static method create takes real x, real y returns SAT
        local SAT d = SAT.allocate()
        set d.endeffect = false
        set d.style = 1
        set d.currentangle = 0.
        set d.stop = false
        set d.cs = CreateUnit(Player(15),DUMMY_ID,x,y,0.)
        return d
    endmethod
    
    method AddCallback takes code c, integer Data returns nothing
        if not (c == null) then
            set .ta = TriggerAddCondition(.callback,Condition(c))
            set .callbackData = Data
        endif
    endmethod
    
    method SetRange takes real range returns nothing
        set .range = range
    endmethod
    
    method CreateEffect takes integer count, integer id, string path returns nothing
        local integer i = 1
        local integer idz
        if count &gt; MAX_ATTACHMENT then
            set count = MAX_ATTACHMENT//Locks the max effect count to prevent bug occurs
        endif
        set .count = count
        set .angle = 360. / .count
        if id == 0 then
            set id = DUMMY_ID
        endif
        loop
        exitwhen i &gt; count
            set .dummies<i> = CreateUnit(Player(15),id,GetUnitX(.cs),GetUnitY(.cs),.angle * i)
            set .eff<i> = AddSpecialEffectTarget(path,.dummies<i>,&quot;origin&quot;)
            set i = i + 1
        endloop
    endmethod
    
    method SetHeight takes real h returns nothing
        local integer i = 0
        loop
        exitwhen i &gt; .count
            call SetUnitFlyHeight(.dummies<i>,h,0.)
            set i = i + 1
        endloop
    endmethod
    
    method SetSize takes real size returns nothing
        local integer i = 0
        loop
        exitwhen i &gt; .count
            call SetUnitScale(.dummies<i>,size,size,size)
            set i = i + 1
        endloop
    endmethod
    
    method SetEndEffect takes boolean b returns nothing
        set .endeffect = b
    endmethod
    
    method SetSpeed takes real r returns nothing
        set .rotatespeed = r * HANDLER_SPEED
    endmethod
    
    method SetFacingStyle takes integer i returns nothing
        if i &gt; 5 then
            set i = 1
        endif
        set .style = i
    endmethod
    
    method SetAttachTarget takes unit u returns nothing
        if GetUnitTypeId(.cs) == DUMMY_ID then
            call RemoveUnit(.cs)
        endif
        set .cs = u
    endmethod
    
    method SetXY takes real x, real y returns nothing
        if GetUnitTypeId(.cs) == DUMMY_ID then
            call SetUnitPosition(.cs,x,y)
        endif
    endmethod
    
    method rotate takes nothing returns nothing
        local integer i = 1
        local real r = 0.
        if .currentangle &gt; 360. then
            set .currentangle = .currentangle - 360.
        endif
            set .currentangle = .currentangle + .rotatespeed
        loop
        exitwhen i &gt; .count
            set r = (.currentangle + (.angle * i )) * .0175
            call SetUnitPosition(.dummies<i>,GetUnitX(.cs) + .range * Cos(r),GetUnitY(.cs) + .range * Sin(r))
            if .style == 1 then
                set r = GetUnitFacing(.cs) + 90.
            elseif .style == 2 then
                set r = 57.2958 * Atan2(GetUnitY(.dummies<i>) - GetUnitY(.cs),GetUnitX(.dummies<i>) - GetUnitX(.cs))
            elseif .style == 3 then
                set r = .currentangle
            elseif .style == 4 then
                set r = GetUnitFacing(.cs)
            elseif .style == 5 then
                set r = 57.2958 * Atan2(GetUnitY(.cs) - GetUnitY(.dummies<i>),GetUnitX(.cs) - GetUnitX(.dummies<i>))
            endif
            call SetUnitFacing(.dummies<i>,r)
            set i = i + 1
        endloop
        if not (.ta == null) then 
            set bj_lastCallbackData = .callbackData
            if TriggerEvaluate(.callback) then
                call TriggerRemoveCondition(.callback,.ta)
                set .ta = null
            endif
        endif
    endmethod
    
    method Start takes nothing returns nothing
        if Counter == 0 then
            call TimerStart(t,HANDLER_SPEED,true,function Handler)
        endif
        set Counter = Counter + 1
        set Data[Counter] = this
    endmethod
    //Cleans up all thingy
    method onDestroy takes nothing returns nothing
        local integer i = 0
        set .stop = true
        loop
        exitwhen i &gt; .count
            call DestroyEffect(.eff<i>)
            if .endeffect then
                call KillUnit(.dummies<i>)
            else
                call RemoveUnit(.dummies<i>)
            endif
            set i = i + 1
        endloop
        if GetUnitTypeId(.cs) == DUMMY_ID then
            call RemoveUnit(.cs)
        endif
        if not (.ta == null) then 
            call TriggerRemoveCondition(.callback,.ta)
            set .ta = null
        endif
    endmethod
    
endstruct

public function Stop takes integer i returns nothing
    set SAT(i).stop = true
endfunction

endlibrary
</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>


JASS:
History :
v1 - First Release
v1.1 - Add some features
v1.2 - Allowing struct syntax
v1.3 - Allowing custom dummies type(I found some effects is ugly when attached on default dummy)

This tool enables users create some spining effects around units.

Screenshot ::eek:
satv13.jpg

satv13part2.jpg


http://www.youtube.com/watch?v=QpeTq7LrM20

[YOUTUBE]http://www.youtube.com/watch?v=QpeTq7LrM20[/YOUTUBE]
 

Attachments

  • SAT v1.3.w3x
    56.6 KB · Views: 279

Exide

I am amazingly focused right now!
Reaction score
448
This is kinda cool, and acutally useful. :thup:
Sadly I don't use NewGen or vJASS, so I personally don't have any use for it. But I imagine others might.

I know nothing about the code, so I leave that to others. :p
 

GoGo-Boy

You can change this now in User CP
Reaction score
40
Though this might look cool at first I have no real idea what you might that be using for. For most stuff it's just too flashy and as a buff or s.th. it takes away a lot performance.
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
You can use it anytime as long as you like.

it's just too flashy
When calling the Add function, put low value as effect_count argument, it won't flashy.
 

Larcenist

REP: Respect, Envy, Prosperity?
Reaction score
211
With a total rewrite of the actual code this could turn out somewhat useful...

First of all, any reason for using degrees from the very beginning rather than radians? Referring to this mainly:

JASS:
    set d.angle = 360. / d.count


And if you exclude all the angle-madness this code brings you, one thing in particular should be fixed. You're using global arrays of the struct and a counter, so why on earth do you let the timer run all the time? Pause it if there's no instances running.
 

XeNiM666

I lurk for pizza
Reaction score
138
Hmmm..
Kinda like a wispwheel of effects.

May I suggest letting the effect "face" the direction depending on the rate? ( Face right when rate is > 0 and Face left when rate is < 0 ) So that it wont look wierd and they will all face the direction based on the rate. ( Kinda like the death coil effect in your screenie )
 

Flare

Stops copies me!
Reaction score
662
Code:
public function Remove takes [B]Data d[/B] returns nothing
    set Data(d).b = false
endfunction
Code:
[B]private[/B] struct Data
1) Why are you casting Data to Data?
2) Since Data is private, end-users can't reference the returned value (from the Add function) with the type Data. I suggest making Add return an integer (as opposed to a struct instance itself), and similarly make Remove take an integer or make Data non-private and pray that people aren't stupid enough to tamper with anything :D

That, and please follow XeNiM's suggestion, the effects looks just plain stupid if they are facing the same direction all the time. Perhaps a string argument whereby:
Code:
"forwards" - faces in the direction of travel
"backwards" - faces in the opposite direction to "forwards"
"inwards" - faces the central unit
"outwards" - faces away from the central unit
 

Kenny

Back for now.
Reaction score
202
How 'bout something like this:

JASS:
library SpinningUnits

    globals
        private constant integer DUMMY_ID          = &#039;n000&#039;
        private constant integer CROW_ID           = &#039;Amrf&#039;
        private constant integer MAX_ATTACH        = 30
        
        private constant real    INTERVAL          = 0.03125
        private constant real    DEFAULT_HEIGHT    = 25.00
        
        private constant boolean DEFAULT_REMOVE    = true // Setting this to true will cause the units to be removed not killed.
        private constant boolean DEFAULT_CLOCKWISE = true // True == clockwise, false == anti-clockwise.
        private constant boolean DEFAULT_FACING    = true // True == units face correct direction, false == unit face the facing angle of the caster.
    endglobals
    
    struct SpinningUnits
    
        private unit    cast   = null
        private real    time   = 0.00
        private real    rate   = 0.00
        private real    rad    = 0.00
        private integer count  = 0
        private boolean rem    = false
        private boolean clock  = false
        private boolean face   = false
        
        boolean         stop   = false
        
        private unit   array dum[MAX_ATTACH]
        private effect array sfx[MAX_ATTACH]
        private real   array ang[MAX_ATTACH]
        
        private static thistype array D
        private static integer  Total = 0
        private static timer    Timer = null
        
        method forceStop takes nothing returns nothing
            set .stop = true
        endmethod
        
        static method create takes unit caster, string sfx, integer counter, real height, real radius, real duration, real speed, boolean remove, boolean clockwise, boolean facing returns thistype
            local thistype d     = thistype.allocate()
            local real     angle = 360.00 / counter
            local real     castx = 0.00
            local real     casty = 0.00
            local real     tempx = 0.00
            local real     tempy = 0.00
            local integer  i     = 0
            
            set d.cast   = caster
            set castx    = GetUnitX(d.cast)
            set casty    = GetUnitY(d.cast)
            set d.time   = duration
            set d.rate   = speed * INTERVAL
            set d.rad    = radius
            set d.count  = counter
            set d.rem    = remove
            set d.clock  = clockwise
            set d.face   = facing
            
            loop
                exitwhen i == d.count
                
                set tempx = castx + d.rad * Cos((angle * i) * bj_DEGTORAD)
                set tempy = casty + d.rad * Sin((angle * i) * bj_DEGTORAD)
                
                if d.face then
                    if d.clock then
                        set d.dum<i> = CreateUnit(GetOwningPlayer(d.cast),DUMMY_ID,tempx,tempy,(Atan2((tempy - casty),(tempx - castx)) * bj_RADTODEG) - 90.00)
                    else
                        set d.dum<i> = CreateUnit(GetOwningPlayer(d.cast),DUMMY_ID,tempx,tempy,(Atan2((tempy - casty),(tempx - castx)) * bj_RADTODEG) + 90.00)
                    endif
                else
                    set d.dum<i> = CreateUnit(GetOwningPlayer(d.cast),DUMMY_ID,tempx,tempy,GetUnitFacing(d.cast))
                endif
                
                set d.sfx<i> = AddSpecialEffectTarget(sfx,d.dum<i>,&quot;origin&quot;)
                set d.ang<i> = angle * i
                
                call UnitAddAbility(d.dum<i>,CROW_ID)
                call UnitRemoveAbility(d.dum<i>,CROW_ID)
                call SetUnitFlyHeight(d.dum<i>,height,0.00)
                
                set i = i + 1
            endloop
            
            if thistype.Total == 0 then
                call TimerStart(thistype.Timer,INTERVAL,true,function thistype.periodic)
            endif
            set thistype.D[thistype.Total] = d
            set thistype.Total = thistype.Total + 1
            
            return d
        endmethod
        
        private static method periodic takes nothing returns nothing
            local thistype d     = 0
            local integer  i     = 0
            local integer  j     = 0
            local real     castx = 0.00
            local real     casty = 0.00
            local real     tempx = 0.00
            local real     tempy = 0.00
            
            loop
                exitwhen i &gt;= thistype.Total
                
                set d = thistype.D<i>
                
                if d.time &lt;= 0.00 or GetWidgetLife(d.cast) &lt; 0.406 or d.stop then
                    call d.destroy()
                    set thistype.Total = thistype.Total - 1
                    set thistype.D<i> = thistype.D[thistype.Total]
                    set i = i - 1
                else
                    set castx = GetUnitX(d.cast)
                    set casty = GetUnitY(d.cast)
                    
                    loop
                        exitwhen j == d.count
                        
                        set tempx = castx + d.rad * Cos(d.ang[j] * bj_DEGTORAD)
                        set tempy = casty + d.rad * Sin(d.ang[j] * bj_DEGTORAD)
                        
                        call SetUnitX(d.dum[j],tempx)
                        call SetUnitY(d.dum[j],tempy)
                        if d.face then
                            if d.clock then
                                call SetUnitFacing(d.dum[j],d.ang[j] - 90.00)
                            else
                                call SetUnitFacing(d.dum[j],d.ang[j] + 90.00)
                            endif
                        else
                            call SetUnitFacing(d.dum[j],GetUnitFacing(d.cast))
                        endif
                        
                        if d.clock then
                            set d.ang[j] = d.ang[j] - d.rate
                        else
                            set d.ang[j] = d.ang[j] + d.rate
                        endif
                        set j = j + 1
                    endloop
                    
                    set d.time = d.time - INTERVAL
                endif
                
                set j = 0
                set i = i + 1
            endloop
            
            if thistype.Total == 0 then
                call PauseTimer(thistype.Timer)
            endif
        endmethod
        
        private method onDestroy takes nothing returns nothing
            local integer i = 0
            
            loop
                exitwhen i == .count
                
                call DestroyEffect(.sfx<i>)
                set .sfx<i> = null
                
                if .rem then
                    call RemoveUnit(.dum<i>)
                else
                    call KillUnit(.dum<i>)
                endif
                
                set .dum<i> = null
                
                set i = i + 1
            endloop
            
            set .cast = null
        endmethod
        
        private static method onInit takes nothing returns nothing
            set thistype.Timer = CreateTimer()
        endmethod
        
    endstruct
    
    public function StartEx takes unit caster, string sfx, integer counter, real height, real radius, real duration, real speed, boolean remove, boolean clockwise, boolean facing returns SpinningUnits
        return SpinningUnits.create(caster,sfx,counter,height,radius,duration,speed,remove,clockwise,facing)
    endfunction
    
    public function Start takes unit caster, string sfx, integer counter, real radius, real duration, real speed returns nothing
        call StartEx(caster,sfx,counter,DEFAULT_HEIGHT,radius,duration,speed,DEFAULT_REMOVE,DEFAULT_CLOCKWISE,DEFAULT_FACING)
    endfunction
    
    public function ForceStop takes SpinningUnits d returns nothing
        call d.forceStop()
    endfunction
    
endlibrary
</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>


Its rough, and can probably be made a little better, but its still a step above what you have right now.

Features:
- Allows for clockwise and anti-clockwise directions.
- Allows dummy units to face the appopriate angle or just face the facing angle of the caster.
- Allows for both struct syntax and regular jass syntax.
- Pretty efficient and clean.

Do with it what you want. But I suggest you at least update yours to match it or be better than it.
 

Trollvottel

never aging title
Reaction score
262
it would be useful if it wasnt just eyecandy. if i wanted the dummies to do damage on hitting a unit or to cast a spell i had to rewrite it. Its just not dynamic enough
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
>>it would be useful if it wasnt just eyecandy. if i wanted the dummies to do damage on hitting a unit or to cast a spell i had to rewrite it. Its just not dynamic enough
This tool is just a shaped effect attachment enabler, adding too many features will lose it's original idea.

v1.1 released.
Features added:

5 styles of facing
Free effect size declare
Effects' height is adjustable.
 

BlackRose

Forum User
Reaction score
239
You could explain more on the function, I only found out what endeffect did from reading, kill or remove -.-

BUT I <3 THIS! In your testmap, it gave me some ideas :D
Also, can I make constant effects be destroyed as wheel? Like.... FrostNova or something.
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
if EndEffect is true, you can see the effects' death animation.

Also, can I make constant effects be destroyed as wheel?
You can. Use SAT_Add and wait for the duration of the effect, then call SAT_Remove.
 

wraithseeker

Tired.
Reaction score
122
The long parameter is ugly and creation should be just a basic wisp wheel and additional one with the rest something like.

JASS:
local wispwheel d = wispwheel.create(parametres)
set d.height = x
set d.others = y
 

Kenny

Back for now.
Reaction score
202
Syntax is a very subjective thing. So why not give people the option for both and be done with it?

Anywho, I think that the '5 styles of facing' is a bit too much. I think the options for facing the way they are spinning and facing the same way as the caster is enough.

Maybe add an option for damage or something as well? Just to make this a little more useful.
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
I am working on the callback. The callback is user-defined function.

New Screenshot : :D
satv12.jpg


I will add the struct syntax, however some variables is not healthy to change, so it is private in struct.
 

Andrewgosu

The Silent Pandaren Helper
Reaction score
716
Firstly, I think it's a little bit too limited at present - you should introduce a "x&y" version and the "unit" version should just expand from that.

Next, if you're using a struct syntax you can get rid of the long parameter lists and do the following:


static method create takes real x, real y, real radius returns whispwheel
endmethod

// true - attach
// false - detach if something is already attached
method attach takes unit whichUnit, boolean flag returns nothing
endmethod

method operator style= string modelPath returns nothing
endmethod

method operator radius= real newRadius returns nothing
endmethod


In additon, add more operators or methods to change data, like the speed, count or whatever.

It would be really convenient.
 
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