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

[vJASS] How to use LinkedListModule?

Status
Not open for further replies.
Level 8
Joined
Feb 3, 2013
Messages
277
hi all;;

I've decided to start learning how to use collection modules, I'm already having problems using the most basic one :p

JASS:
library LinkedListModule /* v2.3.1

Easy implementation of linked lists into structs.

***********************************************************************
*
*   module LinkedList
*
*       -   Implement at the top of your struct, must extend array
*
*       thistype next
*       thistype prev
*       boolean  head
*
*       readonly static thistype base
*           -   Precreated head, useful for non-dynamic lists.
*
*       static method allocate takes nothing returns thistype
*       method deallocate takes nothing returns nothing
*
*       static method createNode takes nothing returns thistype
*           -   Allocates a new node pointing towards itself.
*           -   These nodes are considered "heads" therefore it's head
*           -   boolean member is set to true.
*       method insertNode takes thistype toInsert returns thistype
*           -   Inserts the instance before the node.
*       method removeNode takes nothing returns nothing
*           -   Removes the node from the list.
*       method clearNode takes nothing returns nothing
*           -   Deallocates all the instances within the node's range.
*       method flushNode takes nothing returns nothing
*           -   Clears and deallocates the node.
*
*   module LinkedListLite
*       -   Only has the members and the allocation methods.
*       -   To be used with the provided textmacros.
*
*       textmacro LINKED_LIST_HEAD takes node
*           -   Turns the node into a head.
*       textmacro LINKED_LIST_INSERT takes node, toInsert
*           -   Inserts the instance before the node.
*       textmacro LINKED_LIST_REMOVE takes node
*           -   Removes the node from the list.
*       textmacro LINKED_LIST_CLEAR takes node
*           -   Deallocates all the instances within the node's range.
*       textmacro LINKED_LIST_FLUSH takes node
*           -   Clears and deallocates the node.
*       textmacro LINKED_LIST_MERGE takes nodeA, nodeB
*           -   Merges two lists together (Don't merge loose nodes!)
*
**********************************************************************/
    
    module LinkedListLite

        private static integer instanceCount = 0

        thistype next
        thistype prev
        boolean  head
        
        static method allocate takes nothing returns thistype
            local thistype this = thistype(0).prev
            if this==0 then
                debug if instanceCount==8190 then
                    debug call BJDebugMsg("[LinkedList] Error: attempted to allocate too many instances.")
                    debug return 0
                debug endif
                set instanceCount = instanceCount+1
                return instanceCount
            endif
            set thistype(0).prev = prev
            return this
        endmethod
        
        method deallocate takes nothing returns nothing
            set this.prev=thistype(0).prev
            set thistype(0).prev=this
            set this.head=false
        endmethod

    endmodule

    module LinkedList
        implement LinkedListLite
        
        static method operator base takes nothing returns thistype
            return 8190
        endmethod
        
        static method createNode takes nothing returns thistype
            local thistype this=allocate()
            //! runtextmacro LINKED_LIST_HEAD("this")
            return this
        endmethod
        
        method clearNode takes nothing returns nothing
            //! runtextmacro LINKED_LIST_CLEAR("this")
        endmethod
        
        method flushNode takes nothing returns nothing
            //! runtextmacro LINKED_LIST_FLUSH("this")
        endmethod
        
        method insertNode takes thistype toInsert returns nothing            
            //! runtextmacro LINKED_LIST_INSERT("this","toInsert")
        endmethod
        
        method removeNode takes nothing returns nothing
            //! runtextmacro LINKED_LIST_REMOVE("this")
        endmethod
        
        private static method onInit takes nothing returns nothing
            set thistype(8190).next = 8190
            set thistype(8190).prev = 8190
            set thistype(8190).head = true
        endmethod
        
        static if DEBUG_MODE then
            method print takes nothing returns nothing
                local string s=""
                local thistype exit=this
                loop
                    set s=s+I2S(this)
                    set this = next
                    exitwhen this==exit
                    set s = s+" - "
                endloop
                call BJDebugMsg("[ "+s+" ]")
            endmethod
        endif
        
    endmodule

    //! textmacro LINKED_LIST_HEAD takes node
        set $node$.next = this
        set $node$.prev = this
        set $node$.head = true
    //! endtextmacro
        
    //! textmacro LINKED_LIST_CLEAR takes node
        if $node$!=$node$.next then
            set $node$.next.prev = thistype(0).prev
            set thistype(0).prev = $node$.prev
            set $node$.next = $node$
            set $node$.prev = $node$
        endif
    //! endtextmacro
        
    //! textmacro LINKED_LIST_FLUSH takes node
        set $node$.next.prev = thistype(0).prev
        set thistype(0).prev = $node$
        set $node$.head = false
    //! endtextmacro
        
    //! textmacro LINKED_LIST_INSERT takes node, toInsert
        set $node$.prev.next = $toInsert$
        set $toInsert$.prev = $node$.prev
        set $node$.prev = $toInsert$
        set $toInsert$.next = $node$
    //! endtextmacro
        
    //! textmacro LINKED_LIST_REMOVE takes node
        set $node$.prev.next = $node$.next
        set $node$.next.prev = $node$.prev
    //! endtextmacro

    //! textmacro LINKED_LIST_MERGE takes nodeA, nodeB
        set $nodeA$.next.prev = $nodeB$.prev
        set $nodeB$.prev.next = $nodeA$.next
        set $nodeA$.next = $nodeB$
        set $nodeB$.prev = $nodeA$
    //! endtextmacro

endlibrary

can someone show me how i loop through this?

JASS:
scope Test

    private struct testStruct extends array
        implement LinkedList
        
        static timer tmr = CreateTimer()
        static method looping takes nothing returns nothing
            local thistype this = thistype.allocate
            
            call .insertNode(this)
            loop
                exitwhen .head
                call BJDebugMsg(I2S(this))
                set this = .next
            endloop
        endmethod
        
        static method onInit takes nothing returns nothing
            local thistype this = thistype.createNode()
            call .insertNode(this)
            call TimerStart(tmr, 1.0, true, function thistype.looping)
        endmethod
    endstruct

endscope
I have something like this, but it doesn't seem to be working properly
 
Untested, but let's say you have a spell where you just need one linked list:
JASS:
struct Spell
    implement LinkedList

    static timer t = CreateTimer() 

    unit u

    static method onExpire takes nothing returns nothing 
        local thistype this = base.next
        loop
            exitwhen this == base

            /* Random spell-related actions */
            call SetUnitState(this.u, GetWidgetLife(this.u) - 25)
            if GetWidgetLife(this.u) < 0.405 then
                call this.deallocate()
                call this.remove()
            endif

            set this = this.prev
        endloop
    endmethod

    /* Some random method that will be called on a spell's cast */
    static method onSpellCast takes nothing returns nothing
        local thistype this = thistype.allocate()
        set this.u = GetTriggerUnit()
        
        /* Start the timer if the list is initially empty */
        if base.next == base then
            call TimerStart(t, 0.03125, true, function thistype.onExpire)
        endif

        call base.insertNode(this)
    endmethod
endstruct

For multiple lists per struct, you would have particular nodes that were made with .createNode(), and they would essentially serve in place of "base". In the loop, you could then just check if this.head == true.

However, I don't really like that LinkedListModule. For one thing, the base node is 8190 instead of 0 (it uses 0 for allocation purposes). If old information is anything to rely on, then that means that it allocates all slots of the array in memory (because arrays allocate more memory as you enter higher indexes--up to 8191). While memory is indeed cheap, it is still a drawback.

Another thing is that it requires you to iterate backwards, which is just a personal peeve. :p
 
Dunno what list module that is, but this is the one i'm using:

JASS:
library ListModule
//===========================================================================
// Information:
//==============
//
//     This library provides the List module, which allows you to easily create
// a linked list of all of the allocated instances of a struct-type. Iterating
// through a linked list is about 12% faster than iteratating through an array
// in JASS. There is no faster method to iterate through a list of structs than
// the method used by this module. Aside from the marginal speed gain, the best
// use of this library is to hide some ugly low-level code from your structs.
// Rather than manually building and maintaining a list of struct instances,
// just implement the List module, and your code will become much prettier.
//
//===========================================================================
// How to use the List module:
//=============================
//
//     Using the List module is pretty simple. First, implement it in your
// struct (preferably at the top to avoid unnecessary TriggerEvaluate calls).
// In the struct's create method, you must call listAdd(). In the onDestroy
// method, you must also call listRemove(). An example is shown below:
/*
    struct Example
        implement List
        
        static method create takes nothing returns Example
            local Example this = allocate()
                call listAdd() //This method adds the instance to the list.
            return this
        endmethod
        
        method onDestroy takes nothing returns nothing
            call listRemove() //This method removes the instance from the list.
        endmethod
    endstruct
*/
//     The requirement to call listAdd() and listRemove() will be done away
// with once JassHelper supports module onDestroy and module onCreate, but
// for now, it is not too much of a burden.
//
//     Once this is done, your struct will gain all of the methods detailed
// in the API section. Below is an example of how to iterate through the list
// of allocated structs of the implementing struct-type:
/*
    function IterationExample takes nothing returns nothing
        local Example e = Example.first
            loop
                exitwhen e == 0
                //Do something with e here.
                set e = e.next
            endloop
        //Use .last and .prev instead to iterate backwards.
    endmethod
*/
//
//===========================================================================
// List module API:
//==================
//
// (readonly)(static) first -> thistype
//   This member contains the first instance of thistype in the list.
//
// (readonly)(static) last -> thistype
//   This member contains the last instance of thistype in the list.
//
// (readonly)(static) count -> integer
//   This member contains the number of allocated structs of thistype.
//
// (readonly) next -> thistype
//   This member contains the next instance of thistype in the list.
//
// (readonly) prev -> thistype
//   This member contains the previous instance of thistype in the list.
//
// listAdd()
//   This method adds this instance to the list of structs of thistype.
//   This should be called on each instance after it is allocated (within
//   the create method).
//
// listRemove()
//   This method removes this instance from the list of structs of thistype.
//   This should be called on each instance before it is destroyed (within
//   the onDestroy method).
//
// (static) listDestroy()
//   This method destroys all the structs of thistype within the list.
//
//===========================================================================

module List
    private static boolean destroying = false
    private boolean inlist = false
    
    readonly static integer count = 0
    
    readonly thistype next = 0
    readonly thistype prev = 0
    
    static method operator first takes nothing returns thistype
        return thistype(0).next
    endmethod
    
    static method operator last takes nothing returns thistype
        return thistype(0).prev
    endmethod
    
    method listRemove takes nothing returns nothing
        if not inlist then
            return
        endif
        set inlist = false
        set prev.next = next
        set next.prev = prev
        set count = count - 1
    endmethod

    method listAdd takes nothing returns nothing
        if inlist or destroying then
            return
        endif
        set inlist = true
        set last.next = this
        set prev = last
        set thistype(0).prev = this
        set count = count + 1
    endmethod
    
    static method listDestroy takes nothing returns nothing
        local thistype this = last
            set destroying = true
            loop
                exitwhen this == 0
                call destroy()
                set this = prev
            endloop
            set destroying = false
    endmethod
    
endmodule

endlibrary

And it is really, really straightforward. I like this one better because your struct doesn't have to extend array (so you can use interfaces).

At the top of your struct, just type:

JASS:
implement List

And then in your "create" method, just add ".listAdd()", like this:

JASS:
static method create takes nothing returns thistype
    local thistype this = thistype.allocate()
    
    call .listAdd()

    return this
endmethod

And in your onDestroy method, you do the same, except this time it's ".listRemove()":

JASS:
method onDestroy takes nothing returns nothing
    call .listRemove()
endmethod

There! Now your struct instances will be registered into a linked list. If you ever want to iterate through all instances of your struct, you just do this:

JASS:
static method onLoop takes nothing returns nothing
    local thistype this = .first

    loop
        exitwhen this == 0
        //Do stuff here
        set this = .next
    endloop
endmethod

Within this loop, you can treat every struct as if this was a nonstatic method. I.e., if you have an integer member called "i", you can just do this below the comment line:

JASS:
set .i = .i+1

To increase "i" by 1 for each instance of the struct!!

You can also use ".count" to check how many instances are currently in the list (for starting your timer).

EDIT: Oh, and i KNOW that for some reason the whole JASS community disapproves of this, but you don't HAVE to type out "this" when refering to its members, you just need the dot, as seen in my example. In my opinion, this looks much cleaner and more readable, and i can't see why anyone would ever want MORE redundant text in their code.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
These are the standard THW collection modules

http://www.hiveworkshop.com/forums/jass-resources-412/collections-index-239205/

The one you are using is gy'd as it is deprecated


So you'd want to use this for your linked list

http://www.hiveworkshop.com/forums/jass-resources-412/snippet-list-239400/


If you want some serious error checking while you experiment, use this

http://www.hiveworkshop.com/forums/jass-resources-412/snippet-sharedlist-240363/


Look at the top of collections index for a key that states what everything means



Every single linked collection is iterated over the exact same way

JASS:
set node = first //where this == collection and node == some variable

loop
    exitwhen node == sentinel //sentinel is a member within struct

    //code

    set node = node.next
endloop
 
Oh, so you made a list standardizing all your own resources. That is neat.

There is really nothing that can be deprecated in the list module i'm using, since it is so compact. Much more so than yours. Also it has a pedagogical description suitable for an amateur community like this, which is more to say than, well, any of your work.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
The one you showed is a static unique list that's missing push/dequeue/pop. Static unique collections are extremely compact. Right now, no static unique list is written in that index, so I'll link to static unique queue. If you drop all of the debug code stuff, it is extremely tiny.

http://www.hiveworkshop.com/forums/jass-resources-412/snippet-staticuniquequeue-239199/

JASS:
library StaticUniqueQueue /* v1.0.0.4
************************************************************************************
*
*   */uses/*
*  
*       */ ErrorMessage /*         hiveworkshop.com/forums/submissions-414/snippet-error-message-239210/
*
************************************************************************************
*
*   module StaticUniqueQueue
*
*       Description
*       -------------------------
*
*           Node Properties:
*
*               Unique
*               Allocated
*               Not 0
*
*       Fields
*       -------------------------
*
*           readonly static integer sentinel
*
*           readonly static thistype first
*           readonly thistype next
*
*       Methods
*       -------------------------
*
*           static method enqueue takes thistype node returns nothing
*           static method pop takes nothing returns nothing
*
*           static method clear takes nothing returns nothing
*
************************************************************************************/
    module StaticUniqueQueue
        private static thistype last = 0
       
        readonly thistype next
       
        //inlined
        //static method operator first takes nothing returns thistype
            //return thistype(0).next
        //endmethod
       
        static method enqueue takes thistype node returns nothing
            set last.next = node
            set last = node
            set node.next = 0
        endmethod
        static method pop takes nothing returns nothing
            set thistype(0).next = thistype(0).next.next
            if (thistype(0).next == 0) then
                set last = 0
            endif
        endmethod
        static method clear takes nothing returns nothing
            set last = 0
            set thistype(0).next = 0
        endmethod
    endmodule
endlibrary
So no, your code is no more compact than my code is. Trying to compare a static unique list to a non-static unique one and going, oh, the static unique one is so much more compact, is stupid -.-, lol. You also can't include method operators or debug code.

Your destroy function also sucks. You are taking arbitrary node values that may or may not be allocated and then you are destroying them. The user may not want to destroy nodes within a list, they may only want to destroy the list. Plus the list is static, so destroying the list is equivalent to setting first/last to 0 >.>


Let's not argue about which thing is better, because I can continue to point out more and more bad design decisions in what you pasted =).

So let's leave comments like these out

There is really nothing that can be deprecated in the list module i'm using, since it is so compact. Much more so than yours. Also it has a pedagogical description suitable for an amateur community like this, which is more to say than, well, any of your work.
And tell the user what they are getting with a given package instead + how to use it. I listed those because those are the standard resources for THW, that is they passed the collection test and/or have been around for a long time. They also follow a common API.

This means that you should not be attacking what someone else posted and going, "mine is so much more awesome and their thing sucks." Simply state what the user is getting by using your thing. If it is good, you won't need to blatantly attack what other people put up.
 
In my opinion, that is everything you need to iterate through struct instances. To be fair, i'm not familiar with any other usages of linked lists within wc3.

I am generally opposed to implementing more code than you really need. It makes your map larger and the general structure of your trigger editor more messy. Also, adding an error handler to a system that pretty much never errors seems redundant to me.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
In my opinion, that is everything you need to iterate through struct instances. To be fair, i'm not familiar with any other usages of linked lists within wc3.

Then your opinion would be wrong.

List of buffs on a unit, list of auras on unit, list of w/e on a unit

List of things in a rect

List of things for a player

List of lists in a list...

etc...
 
You were the one saying the list module i'm using is deprecated (unless you were refering to OPs code), going:

"mine is so much more awesome and their thing sucks."

As for my sample code, if a node is created in the "create" method, it must be assumed to exist when it is removed in the "onRemove" method. You don't HAVE to remove it there ofcourse, but if you are only using the linked list to list all your struct instances, it is the safest way to make sure that instances are added and removed to the list only once. And like you said, destroying the list is just a matter of nulling the head and tail of the list.

I can agree though that your static list is as short as mine. So perhaps the question would instead be about wether you really need it to be non-static. Regardless of what you are listing, the fact remains that you are just adding forward/backward reference points to a struct. I rarely find the need to have my structs sorted in a certain order.

You can type whatever you want in your descriptions, but the people on this site are not professional programmers, and if they don't understand the applications of your code, they will not use it. So i will keep recommending people to use the libraries that are well documented and user friendly rather than yours.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
You were the one saying the list module i'm using is deprecated (unless you were refering to OPs code), going:

I was referring to code in OP. It's code I wrote a long, long, long time ago and it's in the gy.

The one you are using is gy'd as it is deprecated

Is what you posted in the gy? No.



You can recommend what you like, just don't attack other people's recommendations saying that yours is the best is all I was saying.
 
Level 8
Joined
Feb 3, 2013
Messages
277
@nest:shouldn't this trigger make it so that in game
every second it displays 1, 21, 321, 4321, 54321??

could you also clarify what enqueue/dequeue compared to pop/push?

JASS:
scope Test

    private struct Testruct
        implement List
        
        static method looping takes nothing returns nothing
            local thistype this = thistype.create()
             
            call .push()
            
            loop
                exitwhen this == sentinel
                
                call BJDebugMsg(I2S(this))
                
                set this = prev
            endloop
        endmethod
        
        static method onInit takes nothing returns nothing
            local thistype this = thistype.create()
            
            call .push()
            call BJDebugMsg(I2S(this))
            call TimerStart(CreateTimer(), 1., true, function thistype.looping)
        endmethod
    endstruct
endscope
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
Sorry about that, I thought you already knew what fifo and filo policies are.
pop/push
The last item you push on the list is also the first to be popped, for example, if you pushed 10 to the list, once you pop, the list will return 10 also. consider this list: 1,2,3,4; 4 being the last item, when you do a pop operation, the list will give you 4. When you push 8, the list will look like 1,2,3,8.
enqueue/dequeue
The first item on the list is the first item you can retrieve, consider this list: 8,5,4,3; the head (first item) is 8, when you dequeue, 8 will be returned, if you enqueue 10 after that, the list will look like this: 5,4,3,10.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
I was never good with the fifo lifo terminology myself. This is how I think of it.


You have your list

1,2,3,4,5,6,7,8,9

push would add an element to the beginning of the list

push(20)

20,1,2,3,4,5,6,7,8,9

pop removes element form beginning of list

pop()

1,2,3,4,5,6,7,8,9

enqueue adds element to end of list

enqueue(20)

1,2,3,4,5,6,7,8,9,20

dequeue removes element form end of list

dequeue()

1,2,3,4,5,6,7,8,9


so push/pop = manipulate beginning
enqueue/dequeue = manipulate end

push = add
pop = remove

enqueue = add
dequeue = remove


Next, you are iterating incorrectly. Put debug mode on so that you can see the error messages, and be sure to use SharedList so that it really gives you hell. Keep trying until you get rid of the error messages =).

prev = iterate backwards
next = iterate forwards

first = first element of the list

I'm going to quote myself here

JASS:
local thistype this = //this is your list
local thistype node node = first //first element of list

loop
    exitwhen node == sentinel //sentinel is a member within struct

    //code

    set node = node.next
endloop


For more information, click the Data Structures link in my signature and look at stacks and queues. Be sure to look at the linked list implementations.




Also, the display makes sense because you are iterating over the lists incorrectly. If you enable debug mode and used SharedList, it'll throw errors at you.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
no, push puts it at the beginning of the list

if you are confused, click the Data Structures link in my signature and look at Stack: Linked List Implementation

this is precisely why the fifo lifo stuff is confusing. lifo, which applies to stacks, means that the last element that you added to the stack is the first element that is removed from the stack. fifo means that the first element you added to the queue is the first element that will be removed from the queue.


So if we add an element to the stack, then the next element that will be removed is the element that we just added.

If we add an element to the queue, then the element that was added to the queue the earliest is the element that is removed.
 
Level 8
Joined
Feb 3, 2013
Messages
277
i think i knew what i was doing wrong, i realized i was trying to loop through lists, which doesn't quite work unless i set them up that way, but Ithink im doing it right this time?
JASS:
scope Test

    private struct Testruct
        implement SharedList
        static method looping takes nothing returns boolean
            local thistype this = TT_GetData()
            call .enqueue()
            
            set this = first
            loop
                exitwhen this == sentinel
                call CreateUnit(Player(0), 'hpea', 0.,0.,0.)
                set this = next
            endloop
            
            return false
        endmethod
        
        static method onInit takes nothing returns nothing
            local thistype this = thistype.create()
            
            call TT_StartEx(function thistype.looping, this, 1.0)
        endmethod
    endstruct
endscope
 
Level 8
Joined
Feb 3, 2013
Messages
277
^ kk

I also have this, how come I get an error saying its expecting a node?
JASS:
    private struct List extends array
        implement SharedList
    endstruct
    
    private struct CTLStruct extends array
        List l
        
        static integer i = 0
        implement CTLExpire
            call l.enqueue()
            
            set i = l.first
            loop
                exitwhen i == l.sentinel
                call CreateUnit(Player(0), 'hpea', 0., 0., 0.)
                set i = l.next
            endloop
        implement CTLEnd
        
        static method onInit takes nothing returns nothing
            local thistype this = create()
            set l = List.create()
        endmethod
    endstruct
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
JASS:
    // Iterates through the list.
    set m=l.first
    loop
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60.00,I2S(m))
        set m=m.next
        exitwhen m==l.sentinel
    endloop

What if the list is empty?

sentinel is also static

Once again, third time

JASS:
local thistype this = //this is your list
local thistype node node = first //first element of list

loop
    exitwhen node == sentinel //sentinel is a member within struct

    //code

    set node = node.next
endloop


This was right

JASS:
scope Test

    private struct Testruct
        implement SharedList
        static method looping takes nothing returns boolean
            local thistype this = TT_GetData()
            call .enqueue()
            
            set this = first
            loop
                exitwhen this == sentinel
                call CreateUnit(Player(0), 'hpea', 0.,0.,0.)
                set this = next
            endloop
            
            return false
        endmethod
        
        static method onInit takes nothing returns nothing
            local thistype this = thistype.create()
            
            call TT_StartEx(function thistype.looping, this, 1.0)
        endmethod
    endstruct
endscope
 
Level 8
Joined
Feb 3, 2013
Messages
277
why doesn't this work?

thx to nest and cho for keeping this thread alive ;)
JASS:
    private struct List extends array
        implement SharedList
    endstruct
    
    private struct CTLStruct extends array
        List l
        
        static integer i = 0
        implement CTLExpire
            call l.enqueue()
            
            set i = l.first
            loop
                exitwhen i == l.sentinel
                call CreateUnit(Player(0), 'hpea', 0., 0., 0.)
                set i = l.next
            endloop
        implement CTLEnd
        
        static method onInit takes nothing returns nothing
            local thistype this = create()
            set l = List.create()
        endmethod
    endstruct
 
Level 8
Joined
Feb 3, 2013
Messages
277
i dont get why it i.next not l.next

the List i is just a variable for refernece isn't it?

anyways.. it works - Nest you are a magician lmao

//
wow i just realized what CTL really does... it's fucking impressive
it's like a list and a timer combined into one... i just wish you could set different times for it

there's no need for me to put in a list in combination with CTL unless I need to list index multiple units per instance or something

mind is blown
 
Last edited:
Level 8
Joined
Feb 3, 2013
Messages
277
ooo so should i use it or not?

regardless -- amidoinitrite?
one timer for every instance of this spell?
JASS:
private struct TTStruct extends array 
        implement TimerHead
        integer c
        
        static Timer timer
        static boolexpr oeC
        static integer oeI
        
        static method looping takes nothing returns boolean
            local thistype this = thistype(Timer.expired).first
            
            loop
                exitwhen this == 0
                
                if .c == 0 then
                    set timer = this
                    call timer.destroy()
                    call remove(this)
                else
                    call DisplayTextToPlayer(Player(0), 0, 0, I2S(this) + "." + I2S(.c))
                    set .c = .c - 1
                endif
                
                set this = Timer(this).next
            endloop 
            return false 
        endmethod
        
        static method alloc takes nothing returns nothing
            local thistype this = Timer.create(1.0, oeC, oeI)
            call add(this)
            
            set .c = 5
        endmethod
        
        static method onInit takes nothing returns nothing
            call RegisterSpellEffectEvent('A000', function thistype.alloc)
            
            set oeC = Condition(function thistype.looping)
            set oeI = thistype.looping
        endmethod
    endstruct
if so then
JASS:
//===============================================
//
//          Lacerate
//  idea and original skill by Maker (Lighting Speed Laceration)
//  [url]http://www.hiveworkshop.com/forums/spells-569/lightning-speed-laceration-1-09-a-178653/[/url]
// 
//  Triggers Required:
//      RegisterPlayerUnitEvent/SpellEffectEvent
//      Fade System
//      Functions
//      TimerTools
//  Imports Required:
//      Illusion Dummy
//      Lacerate Ability
//
//===============================================     

scope Lacerate

    globals
        private constant integer ABIL_ID            = 'A000'                // ID for Lacerate
        private constant integer ILLU_ID            = 'e001'                // ID for Illu Dummy
                                                                            // Effect to be made on each hit
        private constant string FX                  = "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl"
        private constant boolean MELEE              = false                 // Is it a melee attack?    
        private constant boolean RANGED             = true                  // Is it a ranged attack?
        
        private constant real SPACE_APART           = 95.00                 // Distance between created illusions and target unit
        
        private constant real PERIOD                = 0.2                   // Time between each hit
        
        private constant integer F_START            = 0xc864ffff
        private constant integer F_END              = 0x00000000
        private constant real    F_TIME             = 1.35                  // Time it takes to fade
    endglobals
        
    private function damage takes unit u returns real                       // Damage dealt per strike
        return ((GetUnitAbilityLevel(u, ABIL_ID) * .10) + .55) * GetHeroAgi(u, true)
    endfunction
    
    private function hits takes unit u returns integer                      // Amount of hits
        return GetRandomInt(GetUnitAbilityLevel(u, ABIL_ID), GetUnitAbilityLevel(u, ABIL_ID) + 1)
    endfunction
    
//========================================================
//
    
    private struct Hit extends array
        implement TimerHead
        unit cast
        unit targ
        player play
        integer id
        integer count
        
        static Timer timer
        static boolexpr oeC
        static integer oeI
        
        static method looping takes nothing returns boolean
            local thistype this = thistype(Timer.expired).first
            local real x
            local real y
            local real ang
            local unit d
            
            loop
                exitwhen this == 0
                
                //
                
                if .count == 0 then
                    set .cast = null
                    set .targ = null
                    set .play = null
                    
                    set timer = this
                    call timer.destroy()
                    call remove(this)
                else
                    // Deal with creation of illusion and fade stuff First
                    set ang = GetAtan(GetUnitX(.targ), GetUnitY(.targ), GetUnitX(.cast), GetUnitY(.cast))
                    set x = GetUnitX(.targ) + SPACE_APART * Cos(ang)
                    set y = GetUnitY(.targ) + SPACE_APART * Sin(ang)
                    set ang = GetAtan(GetUnitX(.cast), GetUnitY(.cast), GetUnitX(.targ), GetUnitY(.targ)) * bj_RADTODEG
                    set d = CreateUnit(.play, .id, x, y, ang)
                    call FadeUnitStart(d, F_START, F_END, F_TIME, true)
                    call SetUnitAnimation(d, "attack")
                    call QueueUnitAnimation(d, "stand")
                    set d = null
                    
                    // Deal damage afterwards
                    call UnitDamageTarget(.cast, .targ, damage(.cast), MELEE, RANGED, ATK_TYPE, DMG_TYPE, WPN_TYPE)
                    call DestroyEffect(AddSpecialEffectTarget(FX, .targ, "origin"))
                    
                    set .count = .count - 1
                endif
                
                //
                
                set this = Timer(this).next
            endloop
            
            return false
        endmethod
        
        static method alloc takes nothing returns nothing
            local thistype this = Timer.create(PERIOD, oeC, oeI)
            
            //
            
            set .cast = GetTriggerUnit()
            set .play = GetOwningPlayer(.cast)
            set .targ = GetSpellTargetUnit()
            set .id   = ILLU_ID
            set .count = hits(.cast)
            
            //
            
            call add(this)
        endmethod
        
        static method onInit takes nothing returns nothing
            call RegisterSpellEffectEvent(ABIL_ID, function thistype.alloc)
            set oeC = Condition(function thistype.looping)
            set oeI = thistype.looping
        endmethod
        
    endstruct
    
endscope

edit: it would be kewl if the min expire time could be lowered in TimerTools nest :p
 
Last edited:
Level 8
Joined
Feb 3, 2013
Messages
277
aww cmonn i just found one of the coolest things and yer telling me not to use it :/

ill be awaiting that update lol

new edit:
so... when i dequeue an and the node is null it give this gives me an error.. how do i walk around this?
JASS:
    private struct ListStruct extends array
        implement SharedList
        
        integer c
        
        static thistype l
        static real period = 0.2000
        static timer tmr = CreateTimer()
        
        static method looping takes nothing returns nothing
            local thistype this = l.first 
            
            loop
                exitwhen this == thistype.sentinel
                
                if .c == 0 then
                    call remove()
                else
                    set .c = .c - 1
                    call DisplayTextToPlayer(Player(0), 0, 0, I2S(this) + "." + I2S(.c))
                endif
                
                set this = .next
            endloop
        endmethod
        
        static method alloc takes nothing returns nothing
            local thistype this = l.enqueue()
            
            set .c = 5
            
            if l.first == this then
                call TimerStart(tmr, period, true, function thistype.looping)
            endif
        endmethod
        static method onInit takes nothing returns nothing
            set l = thistype.create()
            call RegisterSpellEffectEvent('A000', function thistype.alloc)
        endmethod
    endstruct
 
Last edited:
Level 8
Joined
Feb 3, 2013
Messages
277
lol i know jack about c++

anyways here we go, this seems to be working for me

btw thx a lot nest for all the help
JASS:
    private struct ListStruct extends array
        implement SharedList
        
        integer c
        
        static thistype l
        static real period = 0.2000
        static timer tmr = CreateTimer()
        
        static method looping takes nothing returns nothing
            local thistype this = l.first 
            local thistype nodeNext
            
            loop
                exitwhen this == l.sentinel
                set nodeNext = .next
                
                if .c == 0 then
                    call l.pop()
                else
                    set .c = .c - 1
                    call DisplayTextToPlayer(Player(0), 0, 0, I2S(this) + "." + I2S(.c))
                endif
                
                set this = nodeNext
            endloop
            
            if l.first == l.sentinel then
                call PauseTimer(tmr)
            endif
        endmethod
        
        static method alloc takes nothing returns nothing
            local thistype this = l.enqueue()
            
            set .c = 5
            
            if l.first == this then
                call TimerStart(tmr, period, true, function thistype.looping)
            endif
        endmethod
        static method onInit takes nothing returns nothing
            set l = thistype.create()
            call RegisterSpellEffectEvent('A000', function thistype.alloc)
        endmethod
    endstruct
 
Status
Not open for further replies.
Top