• 🏆 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!

[vJASS] Particle

Level 33
Joined
Apr 24, 2012
Messages
5,113
JASS:
library Particle/* v1.0.0
*************************************************************************************
*
*   1.29 Effect API Handling and Wrappers
*
*************************************************************************************
*
*   struct Particle extends array 
*       readonly string model
*
*       static method create takes string mdx, real tx, real ty, real tz returns thistype 
*       method destroy takes nothing returns nothing 
*
*   Position API
*
*       method operator x= takes real r returns nothing 
*       method operator x takes nothing returns real 
*
*       method operator y= takes real r returns nothing 
*       method operator y takes nothing returns real 
*
*       method operator z= takes real r returns nothing 
*       method operator z takes nothing returns real 
*
*   Orientation API
*
*       method operator yaw= takes real r returns nothing 
*       method operator yaw takes nothing returns real 
*
*       method operator pitch= takes real r returns nothing 
*       method operator pitch takes nothing returns real 
*       
*       method operator roll= takes real r returns nothing 
*       method operator roll takes nothing returns real 
*
*   Appearance API
*
*       method operator scale= takes real r returns nothing 
*       method operator scale takes nothing returns real 
*
*       method operator alpha= takes integer r returns nothing 
*       method operator alpha takes nothing returns integer
*
*       method setColor takes integer r, integer g, integer b returns nothing 
*
*       method operator red takes nothing returns integer 
*       method operator green takes nothing returns integer 
*       method operator blue takes nothing returns integer 
*
*************************************************************************************/

    private module I 
        private static method onInit takes nothing returns nothing 
            call init() 
        endmethod 
    endmodule 

    struct Particle extends array 
        readonly string model 
       
        private effect effect 
       
        private integer t__a 
        private integer t__r 
        private integer t__g 
        private integer t__b 
       
        private real t__x 
        private real t__y 
        private real t__z 
       
        private real t__yaw 
        private real t__pitch 
        private real t__roll
       
        private real t__scale
       
        private static thistype array recycler 
   
        static method create takes string mdx, real tx, real ty, real tz returns thistype 
            local thistype this = recycler[0]
            if(recycler[this] == 0) then 
                set recycler[0] = this + 1 
            else 
                set recycler[0] = recycler[this] 
            endif 
            debug set recycler[this] = -1 
           
            set model = mdx
            set t__x = tx 
            set t__y = ty 
            set t__z = tz 
           
            set effect = AddSpecialEffect(mdx, tx, ty)
            call BlzSetSpecialEffectZ(effect, tz)
           
            set t__yaw = 0. 
            set t__pitch = 0.
            set t__roll = 0.
            set t__scale = 1.
            set t__a = 255
            set t__r = 255
            set t__g = 255 
            set t__b = 255
           
           
           
            return this 
        endmethod 
       
        method destroy takes nothing returns nothing 
            debug if (recycler[this] == -1) then 
                set recycler[this] = recycler[0]
                set recycler[0] = this 
               
                call DestroyEffect(effect)
                set effect = null 
               
                set model = ""
                set t__x = 0 
                set t__y = 0 
                set t__z = 0 
               
                set t__yaw = 0. 
                set t__pitch = 0.
                set t__roll = 0.
                set t__scale = 0.
               
                set t__a = 0
                set t__r = 0
                set t__g = 0 
                set t__b = 0
            debug endif 
        endmethod 
       
        /*
         *
         *  Position API 
         *
         */
        method operator x= takes real r returns nothing 
            set t__x = r
            call BlzSetSpecialEffectX(effect, r)
        endmethod 
       
        method operator x takes nothing returns real 
            return t__x 
        endmethod 
       
        method operator y= takes real r returns nothing 
            set t__y = r 
            call BlzSetSpecialEffectY(effect, r)
        endmethod 
       
        method operator y takes nothing returns real 
            return t__y 
        endmethod 
       
        method operator z= takes real r returns nothing 
            set t__z = r 
            call BlzSetSpecialEffectZ(effect, r)
        endmethod 
       
        method operator z takes nothing returns real 
            return t__z 
        endmethod 
       
        /**
         *
         *  Orientation API 
         *
         */
        method operator yaw= takes real r returns nothing 
            set t__yaw = r 
            call BlzSetSpecialEffectYaw(effect, r)
        endmethod 
       
        method operator yaw takes nothing returns real 
            return t__yaw 
        endmethod 
       
       
        method operator pitch= takes real r returns nothing 
            /*
            *   As of 1.29, changing the effect's pitch over time
            *  (at least on 32 frames per second) will cause it 
            *   not to render correctly, as if it was trying to turn
            *   on the opposite direction and then tries to correct
            *   it on the next frame.
            *
            *   we have to reapply the previous orientation before
            *   applying the new one
            */
            call BlzSetSpecialEffectPitch(effect, t__pitch)
            set t__pitch = r 
            call BlzSetSpecialEffectPitch(effect, r)
        endmethod 
       
        method operator pitch takes nothing returns real 
            return t__pitch
        endmethod 
       
       
        method operator roll= takes real r returns nothing 
            set t__roll = r 
            call BlzSetSpecialEffectRoll(effect, r)
        endmethod 
       
        method operator roll takes nothing returns real 
            return t__roll
        endmethod 
       
        /*
         *
         *  Appearance API
         *
         */
       
        method operator scale= takes real r returns nothing 
            set t__scale = r 
            call BlzSetSpecialEffectScale(effect, r)
        endmethod 
       
        method operator scale takes nothing returns real 
            return t__scale 
        endmethod 
       
        method operator alpha= takes integer r returns nothing 
            set t__a = r 
            call BlzSetSpecialEffectAlpha(effect, r)
        endmethod 
       
        method operator alpha takes nothing returns integer
            return t__a 
        endmethod 
       
        method setColor takes integer r, integer g, integer b returns nothing 
            set t__r = r 
            set t__g = g 
            set t__b = b 
            call BlzSetSpecialEffectColor(effect, r, g, b)
        endmethod 
       
        method operator red takes nothing returns integer 
            return t__r 
        endmethod 
       
        method operator green takes nothing returns integer 
            return t__g 
        endmethod 
       
        method operator blue takes nothing returns integer 
            return t__b 
        endmethod 
       
        private static method init takes nothing returns nothing 
            set recycler[0] = 1
        endmethod 
        implement I 
    endstruct 
endlibrary

Pitch per frame demo:
JASS:
library Tests requires Particle

    private module I 
        private static method onInit takes nothing returns nothing 
            call init() 
        endmethod 
    endmodule 
    private struct T extends array 
        private static constant timer timer = CreateTimer()
       
        private static Particle effect
        private static integer state 
        private static real r 
        private static method u takes nothing returns nothing 
            set r = r + (bj_PI/4)*0.03125
            if(r > bj_PI*2) then 
                set r = 0.
                set state = state + 1
                if(state > 2) then 
                    set state = 0 
                endif 
            endif 
            if(state == 0) then 
                call BJDebugMsg("yaw")
                set effect.yaw = r 
            elseif(state == 1) then 
                call BJDebugMsg("pitch")
                set effect.pitch = r 
            elseif(state == 2) then 
                call BJDebugMsg("roll")
                set effect.roll = r 
            endif 
        endmethod 
        private static method init takes nothing returns nothing 
            set effect = Particle.create("units\\human\\Knight\\Knight.mdl", 0, 0, 64.)
            set effect.scale = 5
            set state = 0 
            set r = 0
            call TimerStart(timer, 0.03125, true, function thistype.u)
        endmethod 
        implement I 
    endstruct 

endlibrary
 
Last edited:
Level 33
Joined
Apr 24, 2012
Messages
5,113
You don't need to store x and y. Just use GetUnitX() and GetUnitY().
Meh, I hate function calls that much >_<

Some nitpicking:
Wrong nomenclature
http://howthingsfly.si.edu/flight-dy...-pitch-and-yaw. It should be called 'pitch'.
Thank you for pointing that out, I was really confused on those 3 XD

method operator scale= only changes the x-scale.
we are already been doing that years ago because they have already stated that y and z are not necessary.

And last, I hate the fact that SetUnitVertexColor will be called 4 times when you want to completely change RGBA
been through this for some moments, tho there will be occurrences that the user will still try to change only one field. I'll be thinking this as between Worst-Case and Best-Case :)

Add setting absoluteZ of the particle
I want to, tho I would be implementing a ZLibrary and also that will be hard for some users to get the actual terrain height. Still going to be decided.

[edit]
Updated
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
JASS:
        public method setColor takes integer r, integer g, integer b, integer a returns nothing
            set t_red = r
            set t_green = g
            set t_blue = b
            set t_alpha = a
            call SetUnitVertexColor(u, t_red, t_green, t_blue, t_alpha)
        endmethod

I ussually do this.
Then I make redirects to this function.
As long as the variables are readonly, you can use this function while only changing one color.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
You still have to make the variables readable.
Also the unit should be made readable imo.

Something like scale by factor would be nice.

I recently started making a Unit struct:
JASS:
library Unit
    
    struct Unit
        
        readonly unit ref
        readonly Gamer owner
        
        readonly Color color
        readonly PlayerColor playerColor
        readonly real scaleX
        readonly real scaleY
        readonly real scaleZ
        
        public static method cast takes unit whichUnit returns thistype
            return GetUnitUserData(whichUnit)
        endmethod
        
        public static method create takes Gamer owner, integer unitTypeId, real x, real y, real facing returns thistype
            local thistype this = .allocate()
            
            set .ref = CreateUnit(owner.ref, unitTypeId, x, y, facing)
            set .owner = owner
            
            set .color = Color.create(255, 255, 255, 255)
            set .playerColor = owner.playerColor
            set .scaleX = 1
            set .scaleY = 1
            set .scaleZ = 1
            
            call SetUnitUserData(.ref, this)
            return this
        endmethod
        
        //Creation method when units are created by other systems or the game itself.
        public static method assign takes unit whichUnit returns thistype
            local thistype this = .allocate()
            set .ref = whichUnit
            set .owner = Gamer.get[GetPlayerId(GetOwningPlayer(.ref))]
            
            set .color = Color.create(255, 255, 255, 255)
            set .scaleX = 1
            set .scaleY = 1
            set .scaleZ = 1
            
            call SetUnitUserData(.ref, this)
            return this
        endmethod
        
        public method remove takes nothing returns nothing
            call RemoveUnit(.ref)
            set .ref = null
            call .color.remove()
            call .deallocate()
        endmethod
        
        public method isAlive takes nothing returns boolean
            return UnitAlive(.ref)
        endmethod
        
        public method setOwner takes Gamer newOwner, boolean changeColor returns nothing
            set .owner = newOwner
            call SetUnitOwner(.ref, newOwner.ref, changeColor)
        endmethod
        
        public method select takes boolean flag returns nothing
            call SelectUnit(.ref, flag)
        endmethod
        
        public method addAbility takes integer abilityId returns boolean
            if UnitAddAbility(.ref, abilityId) then
                call UnitMakeAbilityPermanent(.ref, true, abilityId)
                return true
            endif
            return false
        endmethod
        
        public method removeAbility takes integer abilityId returns boolean
            return UnitRemoveAbility(.ref, abilityId)
        endmethod
        
        public method addSpecialEffect takes string filePath, string attachmentPoint returns effect
            return AddSpecialEffectTarget(filePath, .ref, attachmentPoint)
        endmethod
        
        public method setPlayerColor takes PlayerColor pc returns nothing
            set .playerColor = pc
            call SetUnitColor(.ref, pc.ref)
        endmethod
        
        public method setColor takes integer r, integer g, integer b, integer a returns nothing
            set .color.r = r
            set .color.g = g
            set .color.b = b
            set .color.a = a
            call SetUnitVertexColor(.ref, r, g, b, a)
        endmethod
        
        public method addExperience takes integer experience, boolean showEffect returns nothing
            call AddHeroXP(.ref, experience, showEffect)
        endmethod
        
    endstruct
    
endlibrary

A few things like scaling still had to be done, but there might be a few things that are interesting.

For dummy units, I had a different one in my window library.
It would be useful to have panColor, panPosition, panScale in addition to setColor, setPosition, setScale and scale (multiplication of old/current value and param values).
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
It works for 2d stuff.
For actual real models, I thought setting y and z also had some effect on it.

Also:
JASS:
        method scale takes real x, real y, real z returns nothing
            set t_scale_x = t_scale_x * x
            set t_scale_y = t_scale_y * y
            set t_scale_z = t_scale_z * z
            call SetUnitScale(u, t_scale_x, t_scale_y, t_scale_z)
        endmethod
In the case that y and z do something.
If not, then only for x scale.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
there is no real way to correct this, but you could warn users about the fact that the color values may be completly different from reality, since some models do not start at 255,255,255(the purple golem for instance has at least one of those on 240 or lower).
 
Level 33
Joined
Apr 24, 2012
Messages
5,113
Well, let me remind you that a similar library exists:

JASS:
/*
    Prioritized Unit Appearance
        v 1.0.2
            by kingking
    
    ===================
    What does PUA do?
    ===================
    Spell makers often find unit's colour,scale and time scale can be overwritten by other spells.
    Example :
    Unit A has 1.0 of scale.
    Spell A set the unit's scale to 2.0
    Spell B set the unit's scale to 4.5
    The unit now has the scale of 4.5
    
    When spell A is removed, the unit's scale will be set back to 1.0.
    Spell B's scale effect is removed along it.
    
    PUA is aimed to solve that.
    
    ===================
    Working principle :
    ===================
    PUA attaches a list of settings to unit. When the spell is removed, it will check, if the spell
    is at the top of the list. If it is, then PUA will set the setting to lower node. Otherwise,
    the unit will remain on same setting.
    
    ===================
    APIs :
    ===================
    ~ UnitType based.
        SetUnitTypeDefaultScale takes integer unitid, real scalex, real scaley, real scalez
        - If you got the unit type with custom scale, please set.
        
        SetUnitTypeDefaultColour takes integer unitid, integer red, integer green, integer blue, integer alpha
        - If you got the unit type with customer colour, please set.
        
    **** Unit types that are not set with functions above will be assigned to default settings automatically.
    **** It will not work with units that were created before the function is called.
    
    ~ Unit based.
        SetUnitDefaultScale takes unit u, real scalex, real scaley, real scalez
        - Unit's default scale.
        
        SetUnitDefaultColour takes unit u, integer red, integer green, integer blue, integer alpha
        - Unit's default colour.
        
        SetUnitDefaultTimeScale takes unit u, real timescale
        - Unit's default time scale.
    
        AddUnitScale takes unit u, string key, real scalex, real scaley, real scalez
        - Assign scale to unit.
        
        AddUnitColour takes unit u, string key, integer red, integer green, integer blue, integer alpha
        - Assign colour to unit.
        
        AddUnitTimeScale takes unit u, string key, real timescale
        - Assign time scale to unit.
        
        AddUnitScaleForPlayer takes unit u, string key, real scalex, real scaley, real scalez, boolean condition
        - Assign scale to unit.
        
        AddUnitColourForPlayer takes unit u, string key, integer red, integer green, integer blue, integer alpha, boolean condition
        - Assign colour to unit.
        
        AddUnitTimeScaleForPlayer takes unit u, string key, real timescale, boolean condition
        - Assign time scale to unit.
    
        RemoveUnitScale takes unit u, string key
        - Remove assigned scale from unit.
        
        RemoveUnitColour takes unit u, string key
        - Remove assigned colour from unit.
        
        RemoveUnitTimeScale takes unit u, string key
        - Remove assigned time scale from unit.
        
    ****The key parameter must be same when assigning and removing the setting from unit, otherwise, it will not work.
    ****It is ideal to put spell's name into the key paramater.
    
    ===================
    Known limitation :
    ===================
    ~ PUA will not work in onInit method in struct.
    
    ===================
    Requirements :
    ===================
    AIDS, by Jesus4Lyf
    Latest jasshelper, to compile the code.
    
*/

library PUA requires AIDS

    globals
        private constant integer HASH_NEXT=53
        private constant integer MAX_HASH_VALUE=8191
        private integer array HashedInt
    endglobals

    private function Hash takes integer int returns integer
        local integer hash=int-(int/MAX_HASH_VALUE)*MAX_HASH_VALUE
        loop
            exitwhen HashedInt[hash]==int
            if HashedInt[hash]==0 then
                set HashedInt[hash]=int
                return hash
            endif
            set hash=hash+HASH_NEXT
            if hash>=MAX_HASH_VALUE then
                set hash=hash-MAX_HASH_VALUE
            endif
        endloop
        return hash
    endfunction
    //Handy function from Jesus4Lyf
    
    //! textmacro PUA_DATA takes NAME
    private struct $NAME$Data
        private static integer array data
        static method operator []= takes integer i, integer d returns nothing
            set data[Hash(i)]=d
        endmethod
        static method operator [] takes integer i returns integer
            return data[Hash(i)]
        endmethod
    endstruct
    //! endtextmacro PUA_DATA
    //! runtextmacro PUA_DATA ("Colour")
    //! runtextmacro PUA_DATA ("Scale")
    //! runtextmacro PUA_DATA ("TimeScale")
    private struct UnitColour
        integer r
        integer g
        integer b
        integer a
        private static method onInit takes nothing returns nothing
            local thistype this=thistype(0)
            set this.r=255
            set this.g=255
            set this.b=255
            set this.a=255
        endmethod
    endstruct
    
    private struct UnitScale
        real x
        real y
        real z
        private static method onInit takes nothing returns nothing
            local thistype this=thistype(0)
            set this.x=1.0
            set this.y=1.0
            set this.z=1.0
        endmethod
    endstruct
    
    private struct UnitTimeScale
        real value
        private static method onInit takes nothing returns nothing
            local thistype this=thistype(0)
            set this.value=1.0
        endmethod
    endstruct
    
    //Since the structs are either list head or node, so I just use unified structure for them.
    private module ListElements
        readonly thistype prev
        readonly thistype next
        boolean flag
        string word
        
        static method createHead takes nothing returns thistype
            local thistype this=thistype.allocate()
            set this.prev=this
            set this.next=this
            return this
        endmethod
        
        method link takes thistype c returns nothing
            set this.prev.next=c
            set c.prev=this.prev
            set this.prev=c
            set c.next=this
        endmethod
        
        method unlink takes nothing returns nothing
            set this.prev.next=this.next
            set this.next.prev=this.prev
        endmethod
        
        method search takes string word returns thistype
            local thistype c=this
            set this=this.next
            loop
            exitwhen this==c
                if this.word==word then
                    return this
                endif
                set this=this.next
            endloop
            return 0
        endmethod
        
        method chainDestroy takes nothing returns nothing
            local thistype c=this
            set this=this.next
            loop
            exitwhen this==c
                call this.destroy()
                set this=this.next
            endloop
            call this.destroy()
        endmethod
    endmodule
    
    //! textmacro PUA_VARS takes NAME, TYPE
        private $TYPE$ $NAME$x
        method operator $NAME$= takes $TYPE$ v returns nothing
            set this.$NAME$x=v
        endmethod
        method operator $NAME$ takes nothing returns $TYPE$
            if this.flag==true then
                return this.prev.$NAME$
            endif
            return this.$NAME$x
        endmethod
    //! endtextmacro
    
    private struct ColourList
        implement ListElements
        //! runtextmacro PUA_VARS ("r","integer")
        //! runtextmacro PUA_VARS ("g","integer")
        //! runtextmacro PUA_VARS ("b","integer")
        //! runtextmacro PUA_VARS ("a","integer")
    endstruct
    
    private struct ScaleList
        implement ListElements
        //! runtextmacro PUA_VARS ("x","real")
        //! runtextmacro PUA_VARS ("y","real")
        //! runtextmacro PUA_VARS ("z","real")
    endstruct
    
    private struct TimeScaleList
        implement ListElements
        //! runtextmacro PUA_VARS ("value","real")
    endstruct
    
    private struct UnitStruct extends array
        ColourList clist
        ScaleList slist
        TimeScaleList tlist
        
        private method AIDS_onCreate takes nothing returns nothing
            local integer id=GetUnitTypeId(this.unit)
            local UnitColour c=ColourData[id]
            local UnitScale s=ScaleData[id]
            local UnitTimeScale t=TimeScaleData[id]
            
            set this.clist=ColourList.createHead()
            set this.slist=ScaleList.createHead()
            set this.tlist=TimeScaleList.createHead()
            
            set this.clist.r=c.r
            set this.clist.g=c.g
            set this.clist.b=c.b
            set this.clist.a=c.a
            set this.clist.flag=false
            
            set this.slist.x=s.x
            set this.slist.y=s.y
            set this.slist.z=s.z
            set this.slist.flag=false
            
            set this.tlist.value=t.value
            set this.tlist.flag=false
        endmethod
        
        private method AIDS_onDestroy takes nothing returns nothing
            call this.clist.chainDestroy()
            call this.slist.chainDestroy()
            call this.tlist.chainDestroy()
        endmethod
        
        //! runtextmacro AIDS()
    endstruct
    
    function SetUnitTypeDefaultScale takes integer unitid, real x, real y, real z returns nothing
        local UnitScale s=ScaleData[unitid]
        if s==0 then
            set s=UnitScale.create()
            set ScaleData[unitid]=s
        endif
        set s.x=x
        set s.y=y
        set s.z=z
    endfunction
    
    function SetUnitTypeDefaultColour takes integer unitid, integer r, integer g, integer b, integer a returns nothing
        local UnitColour c=ColourData[unitid]
        if c==0 then
            set c=UnitColour.create()
            set ColourData[unitid]=c
        endif
        set c.r=r
        set c.g=g
        set c.b=b
        set c.a=a
    endfunction
    
    function SetUnitDefaultScale takes unit u, real x, real y, real z returns nothing
        local ScaleList s
        if u==null then
            return
        endif
        set s=UnitStruct[u].slist
        set s.x=x
        set s.y=y
        set s.z=z
    endfunction
    
    function SetUnitDefaultColour takes unit u, integer r, integer g, integer b, integer a returns nothing
        local ColourList c
        if u==null then
            return
        endif
        set c=UnitStruct[u].clist
        set c.r=r
        set c.g=g
        set c.b=b
        set c.a=a
    endfunction
    
    function SetUnitDefaultTimeScale takes unit u, real value returns nothing
        if u==null then
            return
        endif
        set UnitStruct[u].tlist.value=value
    endfunction
    
    function AddUnitScale takes unit u, string word, real x, real y, real z returns nothing
        local UnitStruct dat
        local ScaleList s
        if u==null then
            return
        endif
        set dat=UnitStruct[u]
        set s=ScaleList.create()
        set s.word=word
        set s.x=x
        set s.y=y
        set s.z=z
        set s.flag=false
        call dat.slist.link(s)
        call SetUnitScale(u,x,y,z)
    endfunction
        
    function AddUnitColour takes unit u, string word, integer r, integer g, integer b, integer a returns nothing
        local UnitStruct dat
        local ColourList c
        if u==null then
            return
        endif
        set dat=UnitStruct[u]
        set c=ColourList.create()
        set c.word=word
        set c.r=r
        set c.g=g
        set c.b=b
        set c.a=a
        set c.flag=false
        call dat.clist.link(c)
        call SetUnitVertexColor(u,r,g,b,a)
    endfunction
    
    function AddUnitTimeScale takes unit u, string word, real value returns nothing
        local UnitStruct dat
        local TimeScaleList t
        if u==null then
            return
        endif
        set dat=UnitStruct[u]
        set t=TimeScaleList.create()
        set t.word=word
        set t.value=value
        set t.flag=false
        call dat.tlist.link(t)
        call SetUnitTimeScale(u,value)
    endfunction
    
    function AddUnitScaleForPlayer takes unit u, string word, real x, real y, real z, boolean boo returns nothing
        local UnitStruct dat
        local ScaleList s
        if u==null then
            return
        endif
        set dat=UnitStruct[u]
        set s=ScaleList.create()
        set s.word=word
        set s.flag=not boo
        if boo then
            set s.x=x
            set s.y=y
            set s.z=z
        endif
        call dat.slist.link(s)
        call SetUnitScale(u,s.x,s.y,s.z)
    endfunction
    
    function AddUnitColourForPlayer takes unit u, string word, integer r, integer g, integer b, integer a, boolean boo returns nothing
        local UnitStruct dat
        local ColourList c
        if u==null then
            return
        endif
        set dat=UnitStruct[u]
        set c=ColourList.create()
        set c.word=word
        set c.flag=not boo
        if boo then
            set c.r=r
            set c.g=g
            set c.b=b
            set c.a=a
        endif
        call dat.clist.link(c)
        call SetUnitVertexColor(u,c.r,c.g,c.b,c.a)
    endfunction
    
    function AddUnitTimeScaleForPlayer takes unit u, string word, real value, boolean boo returns nothing
        local UnitStruct dat
        local TimeScaleList t
        if u==null then
            return
        endif
        set dat=UnitStruct[u]
        set t=TimeScaleList.create()
        set t.word=word
        set t.flag=not boo
        if boo then
            set t.value=value
        endif
        call dat.tlist.link(t)
        call SetUnitTimeScale(u,t.value)
    endfunction
    
    function RemoveUnitScale takes unit u, string word returns nothing
        local ScaleList dat
        if u==null then
            return
        endif
        set dat=UnitStruct[u].slist.search(word)
        if dat!=0 then
            call dat.unlink()
            call dat.destroy()
            set dat=UnitStruct[u].slist.prev
            call SetUnitScale(u,dat.x,dat.y,dat.z)
        endif
    endfunction
    
    function RemoveUnitColour takes unit u, string word returns nothing
        local ColourList dat
        if u==null then
            return
        endif
        set dat=UnitStruct[u].clist.search(word)
        if dat!=0 then
            call dat.unlink()
            call dat.destroy()
            set dat=UnitStruct[u].clist.prev
            call SetUnitVertexColor(u,dat.r,dat.g,dat.b,dat.a)
        endif
    endfunction
    
    function RemoveUnitTimeScale takes unit u, string word returns nothing
        local TimeScaleList dat
        if u==null then
            return
        endif
        set dat=UnitStruct[u].tlist.search(word)
        if dat!=0 then
            call dat.unlink()
            call dat.destroy()
            set dat=UnitStruct[u].tlist.prev
            call SetUnitTimeScale(u,dat.value)
        endif
    endfunction
endlibrar

But to me, it is kind of outdated, and contains unnecessary parts.
 
Level 33
Joined
Apr 24, 2012
Messages
5,113
Updated.

See Changelogs.


The reason I added a "destroyed" method is that users can check whether or not a particle is a null. I was disappointed when I created a particle system and frame rates drop because of unhandled null particles

Also,I have update this so that particles won't cost 1 food and won't show the Idle Worker Icon if it is unpaused (THANKS BRIBE)
 
How about the name "UnitEffect" or so, "Particle" confused me actually a bit and I thought of something like missles or actually had no idea.
Because it seems that's actually exactly what it is. There are functions to attach an effect to your unit and functions to handle it's apperance.

Using DummyUnit seems useful. Maybe you might also think of using a unit appearance system. :)
____________________

Was the one by Nestharus approved? How did it work?
When I think about it and read the code it's all syntax sugar, but the user can do like everything easily by his own if he has access to the dummy unit.
Wrappers for setting x/y, angle etc are not what should make the system. Though the pitch is certainly good, and auto destroying effects is also nice, but well...

Could you defend the code's purpose a bit so we can discuss it to make a decission easier? :)

DummyRecycler is a requirement (not optional) -> no static ifs to execute code.
 
Last edited:
Level 14
Joined
Jan 16, 2009
Messages
716
This doesn't work correctly:
JASS:
scope Demo
    private struct Demo extends array
        static Particle effect
        static real r
        static method u takes nothing returns nothing
            set r = r + (bj_PI/4)*0.03125
            if(r > bj_PI*2) then
                set r = 0.
            endif
            set effect.pitch = r
        endmethod
        static method onInit takes nothing returns nothing
            set effect = Particle.create("units\\human\\Knight\\Knight.mdl", 0, 0, 64.)
            set effect.scale = 5
            set effect.roll = - bj_PI/4
            set r = 0
            call TimerStart(CreateTimer(), 0.03125, true, function thistype.u)
        endmethod
    endstruct
endscope
The effect rotations aren't relative like you assumed but absolute.
 
Level 33
Joined
Apr 24, 2012
Messages
5,113
This doesn't work correctly:
JASS:
scope Demo
    private struct Demo extends array
        static Particle effect
        static real r
        static method u takes nothing returns nothing
            set r = r + (bj_PI/4)*0.03125
            if(r > bj_PI*2) then
                set r = 0.
            endif
            set effect.pitch = r
        endmethod
        static method onInit takes nothing returns nothing
            set effect = Particle.create("units\\human\\Knight\\Knight.mdl", 0, 0, 64.)
            set effect.scale = 5
            set effect.roll = - bj_PI/4
            set r = 0
            call TimerStart(CreateTimer(), 0.03125, true, function thistype.u)
        endmethod
    endstruct
endscope
The effect rotations aren't relative like you assumed but absolute.

absolute and relative in what context?
 
Top