LoopCode

Scripts

9 years
edited 8 years
LoopCode v1.3

This system allows you to register a code that will run every specified timeout. Note that this system only uses one timer for all registered codes. Therefore, codes with periods indivisible by 0.03125 doesn't run with a constant time interval. Although the difference will not exceed 0.03125, you probably don't want it to be that way. But this will not be much of a problem for codes with low frequency period such as those with timeouts greater than 2 seconds since the difference wouldn't be so noticeable.

In short, this works best for codes with timeout divisible by 0.03125 seconds.

Main Script
Code (jass) Select
1
library LoopCode
2
3
4
    //! novjass
5
     ________________
6
    |                |
7
    | Written by AGD |
8
    |________________|
9
10
    |=====|
11
    | API |
12
    |=====|
13
14
      function interface LoopCode takes nothing returns nothing/*
15
        - Interface of functions to be registered in the loop
16
17
    */function RegisterLoopCode takes LoopCode c, real timeout returns boolean/*
18
        - Registers a code to run every <timeout> seconds and returns a boolean value depending
19
        on the success of the operation
20
21
    */function RemoveLoopCode takes LoopCode c returns boolean/*
22
        - Unregisters a code from the loop and returns a boolean value depending
23
        on the success of the operation
24
25
    */function SetCodeTimeout takes LoopCode c, real timeout returns boolean/*
26
        - Sets a new loop timeout for a code
27
28
    *///! endnovjass
29
30
    //======================================================================================
31
32
    globals
33
        private constant real TIMEOUT = 0.03125
34
        private constant boolean AUTO_ADJUST = true
35
    endglobals
36
37
    //======================================================================================
38
39
    globals
40
        private LoopCode array codes
41
        private timer Timer = CreateTimer()
42
        private integer id = 0
43
        private integer count = 0
44
        private real array codeTimeout
45
        private real array elapsed
46
        private integer array index
47
        private boolean array check
48
    endglobals
49
50
    //======================================================================================
51
52
    function interface LoopCode takes nothing returns nothing
53
54
    static if DEBUG_MODE then
55
        private function Debug takes string msg returns nothing
56
            call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "|CFFFFCC00[LoopEvent] :|R" + msg)
57
        endfunction
58
    endif
59
60
    private function RunLoop takes nothing returns nothing
61
        set id = 0
62
        loop
63
            set id = id + 1
64
            set elapsed[id] = elapsed[id] + TIMEOUT
65
            if elapsed[id] >= codeTimeout[id] then
66
                call codes[id].evaluate()
67
                set elapsed[id] = elapsed[id] - codeTimeout[id]
68
            endif
69
            exitwhen id == count
70
        endloop
71
    endfunction
72
73
    function RegisterLoopCode takes LoopCode c, real timeout returns boolean
74
        static if AUTO_ADJUST then
75
            if timeout < TIMEOUT then
76
                set timeout = TIMEOUT
77
                debug call Debug("Entered code execution timeout is less than the minimum value (" + R2S(TIMEOUT) + "), auto-adjusting timeout to (" + R2S(TIMEOUT) + ")")
78
            endif
79
        else
80
            if timeout < TIMEOUT then
81
                debug call Debug("ERROR: Entered code execution timeout is less than the minimum value (" + R2S(TIMEOUT) + ")")
82
                return false
83
            endif
84
        endif
85
        if not check[c] then
86
            debug if timeout - (timeout/TIMEOUT)*TIMEOUT > 0.00 then
87
                debug call Debug("WARNING: Entered code timeout is not divisible by " + R2S(TIMEOUT) + ", this code's execution interval will not be even")
88
            debug endif
89
            set count = count + 1
90
            set elapsed[count] = 0.00
91
            set codeTimeout[count] = timeout
92
            set codes[count] = c
93
            set index[c] = count
94
            set check[c] = true
95
            if count == 1 then
96
                call TimerStart(Timer, TIMEOUT, true, function RunLoop)
97
                debug call Debug("There is one code instance registered, starting to run timer")
98
            endif
99
            return true
100
        endif
101
        debug call Debug("ERROR: Attempt to double register a code")
102
        return false
103
    endfunction
104
105
    function RemoveLoopCode takes LoopCode c returns boolean
106
        local integer i = index[c]
107
        if check[c] then
108
            debug call Debug("Removing a code from the loop")
109
            set check[c] = false
110
            set index[codes[count]] = i
111
            set codes[i] = codes[count]
112
            set codeTimeout[i] = codeTimeout[count]
113
            if id >= i then
114
                set id = id - 1
115
            endif
116
            set count = count - 1
117
            if count == 0 then
118
                call TimerStart(Timer, 0, false, null)
119
                debug call Debug("There are no code instances running, stopping timer")
120
            endif
121
            return true
122
        endif
123
        debug call Debug("ERROR: Attempt to remove a null or an already removed code")
124
        return false
125
    endfunction
126
127
    function SetCodeTimeout takes LoopCode c, real timeout returns boolean
128
        local integer i = index[c]
129
        if check[c] then
130
            static if AUTO_ADJUST then
131
                if codeTimeout[i] >= TIMEOUT then
132
                    set codeTimeout[i] = timeout
133
                else
134
                    set codeTimeout[i] = TIMEOUT
135
                    debug call Debug("Entered code execution timeout is less than the minimum value (" + R2S(TIMEOUT) + "), auto-adjusting timeout to (" + R2S(TIMEOUT) + ")")
136
                endif
137
                return true
138
            else
139
                if codeTimeout[i] >= TIMEOUT then
140
                    set codeTimeout[i] = timeout
141
                    return true
142
                endif
143
                debug call Debug("ERROR: Entered code execution timeout is less than the minimum value (" + R2S(TIMEOUT) + ")")
144
                return false
145
            endif
146
        endif
147
        debug call Debug("ERROR: Specified code is not registered")
148
        return false
149
    endfunction
150
151
152
endlibrary



Sample Script
Spoiler

Code (jass) Select
1
2
scope MySpell initializer Init
3
4
    globals
5
        private constant real TIMEOUT = 0.03125
6
        private integer maxIndex = 0
7
        private real array elapsed
8
    endglobals
9
10
    private function Loop takes nothing returns nothing
11
        local integer index = 0
12
        loop
13
            set index = index + 1
14
            if elapsed < 10 then
15
                set elapsed[index] = elapsed[index] + TIMEOUT
16
            else
17
                set elapsed[index] = elapsed[maxIndex]
18
                set maxIndex = maxIndex - 1
19
                set index = index - 1
20
                if maxIndex == 0 then
21
                    call RemoveLoopCode(LoopCode.Loop)
22
                endif
23
            endif
24
            exitwhen index == maxIndex
25
        endloop
26
    endfunction
27
28
    private function OnCast takes nothing returns boolean
29
        // Setup spell data and oncast effects
30
        set maxIndex = maxIndex + 1
31
        set elapsed[maxIndex] = 0.00
32
        call RegisterLoopCode(LoopCode.Loop, TIMEOUT)
33
        return false
34
    endfunction
35
36
    private function Init takes nothing returns nothing
37
        local trigger t = CreateTrigger()
38
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
39
        call TriggerAddCondition(t, FIlter(function OnCast))
40
    endfunction
41
42
endscope


Changelogs
Spoiler

v1.3
- Fixed a minor error concerning the index of a registered code in the RunLoop not being decremented by 1 when a code is removed from the loop.

v1.2
- Replaced TriggerEvaluate() with .evaluate() through the use of function interface
- Added an option to the configuration whether or not the system will automatically adjust the code timeout in case the entered timeout is lesser than the minimum supported timeout
- Removed the requirement Table. Instead, uses arrays which were made possible through using interface functions as the index.

v1.1
- Fixed the bug regarding the incorrect unregistering and re-registering codes to the loop
- Uses a TableArray instead of two separate tables

v1.0
- Initial release

Feedback will be appreciated.