HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

"function sequencer" opinions/alternatives

07-19-2009, 03:32 PM#1
fX_
so i have some sort of cinematic intro sequence at the start of my map and i was lead to develop this thing to manage its writing/assembly and execution.

opinions?
or there better alternatives? i don't think it is superfluous... is it?

Script:
Collapse JASS:
library FunctionSequencer uses TimerUtils

    //!//////////////////////////////////////////////////////////////////////////////////////////////////////////////!//
    //!  FunctionSequencer
    //!==============================================================================================================!//
    //!  
    //!  
    //!  
    //!  
    //!  
    //!  
    //!//////////////////////////////////////////////////////////////////////////////////////////////////////////////!//

//!IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII!//
//!IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII!//
//!  - CONFIGURATION -

    globals
        constant integer FUNCSEQUENCER_MAX_NUMBER_OF_SEQUENTS = 100
    endglobals

//!IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII!//
//!IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII!//
//!  - API -

//!IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII!//
//!IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII!//
//!  - FUNCTIONS -

    function interface sequentfunc takes nothing returns nothing

    struct funcsequencer

        readonly sequentfunc array sequent[FUNCSEQUENCER_MAX_NUMBER_OF_SEQUENTS]
        readonly real array duration[FUNCSEQUENCER_MAX_NUMBER_OF_SEQUENTS]
        readonly integer countSequent = 0

        readonly boolean isRunning = false
        readonly boolean isPaused = false
        readonly integer currentSequentIndex = 0
        private timer tim

        public static method create takes nothing returns funcsequencer
            local funcsequencer new = funcsequencer.allocate()

            set new.tim = NewTimer()
            call SetTimerData(new.tim, new)

            return new
        endmethod

        public method onDestroy takes nothing returns nothing
            call .stop()
            call ReleaseTimer(.tim)
        endmethod

        public method addSequent takes sequentfunc sequent, real duration returns boolean
            if .isRunning or .countSequent == FUNCSEQUENCER_MAX_NUMBER_OF_SEQUENTS or duration < 0.00 then
                return false
            endif
            set .sequent[.countSequent] = sequent
            set .duration[.countSequent] = duration
            set .countSequent = .countSequent + 1
            return true
        endmethod

        public method flush takes nothing returns boolean
            if .isRunning then
                return false
            endif
            set .countSequent = 0
            return true
        endmethod

        public method run takes nothing returns boolean
            if .isRunning or .countSequent == 0 then
                return false
            endif
            set .isRunning = true
            set .isPaused = false
            set .currentSequentIndex = 0
            call .iterate()
            return true
        endmethod

        private method iterate takes nothing returns nothing
            loop
                call .sequent[.currentSequentIndex].evaluate()
                if .isRunning == false then
                    return
                endif
                exitwhen .duration[.currentSequentIndex] > 0.00
                set .currentSequentIndex = .currentSequentIndex + 1
                if .currentSequentIndex == .countSequent then
                    call .stop()
                    return
                endif
            endloop
            call TimerStart(.tim, .duration[.currentSequentIndex], false, function funcsequencer.router)
            set .currentSequentIndex = .currentSequentIndex + 1
            if .currentSequentIndex == .countSequent then
                call .stop()
            endif
        endmethod

        private static method router takes nothing returns nothing
            call funcsequencer(GetTimerData(GetExpiredTimer())).iterate()
        endmethod

        public method pause takes boolean do returns boolean
            if not .isRunning then
                return false
            endif
            if do != .isPaused then
                if do then
                    call PauseTimer(.tim)
                elseif .duration[.currentSequentIndex] == 0.00 then
                    call .iterate()
                else
                    call TimerStart(.tim, TimerGetRemaining(.tim), false, function funcsequencer.router)
                endif
                set .isPaused = do
            endif
            return true
        endmethod

        public method stop takes nothing returns nothing
            if .isRunning then
                set .isRunning = false
                call PauseTimer(.tim)
            endif
        endmethod

    endstruct

endlibrary

Example
Collapse JASS:
library Example initializer Initializer requires FunctionSequencer

    globals
        private funcsequencer fs
    endglobals

    private function A takes nothing returns nothing
        call BJDebugMsg("A")
    endfunction

    private function B takes nothing returns nothing
        call BJDebugMsg("B")
    endfunction

    private function C takes nothing returns nothing
        call BJDebugMsg("C")
    endfunction

    private function D takes nothing returns nothing
        call BJDebugMsg("D")
    endfunction

    private function E takes nothing returns nothing
        call BJDebugMsg("E")
    endfunction

    private function F takes nothing returns nothing
        call BJDebugMsg("F")
    endfunction

    private function Run takes nothing returns nothing
        call fs.run()
    endfunction

    private function Initializer takes nothing returns nothing
        local trigger trig = CreateTrigger()

        set fs = funcsequencer.create()
        call fs.addSequent(sequentfunc.A, 1.00)
        call fs.addSequent(sequentfunc.B, 0.00)
        call fs.addSequent(sequentfunc.C, 0.00)
        call fs.addSequent(sequentfunc.D, 0.00)
        call fs.addSequent(sequentfunc.E, 2.00)
        call fs.addSequent(sequentfunc.F, 3.00)

        call TriggerRegisterPlayerChatEvent(trig, Player(0), "-ex", true)
        call TriggerAddAction(trig, function Run)

        set trig = null
    endfunction

endlibrary
07-19-2009, 10:31 PM#2
Anitarf
A linked list seems better suited to this task than an array.
Also, I'm more a fan of timestamps than durations, myself.
07-20-2009, 02:27 AM#3
fX_
what's a timestamp?
07-20-2009, 02:42 AM#4
Anitarf
Similar to the duration between actions, except that it is instead the duration from the start of the sequence to the action.
07-20-2009, 04:06 AM#5
fX_
if i implement that:

if i use 1 timer (small countdown; approximation) it wont be accurate
if i use many timers then ill be using... many timers.

are there other ways to implement timestamp? how is it better than this?
07-20-2009, 11:23 AM#6
Anitarf
Quote:
Originally Posted by fX_
if i implement that:

if i use 1 timer (small countdown; approximation) it wont be accurate
if i use many timers then ill be using... many timers.

are there other ways to implement timestamp?
Sure, the same way you implemented it, with a single non-periodic timer.

Quote:
how is it better than this?
I just find absolute time values rather than relative more intuitive. I couldn't imagine, for example, making a cinematic with relative time values. Plus, with absolute values, you don't have to input the values in the right order, you can instead organize them in different ways.
07-21-2009, 07:34 AM#7
fX_
in a sequence as i conceive it, each sequent may follow from another and may be followed by another, but no two sequents can be simultaneous.

for timestamps to be 'ok', they must be cohesive and prepared with this cohesion in mind, such that no sequent 'overlaps' with another. this doesn't afford 'dynamic sequences' (if that's the term). (although my application here - a cinematic - isn't dynamic, i would like the script to the usable wherever else i might need to use it).
sequents with relative durations are 'ok' with respect to the meaning of 'sequence' (above) because each is never to overlap with another.

so, this far, maybe both ways can be implemented... ???

but is there a 'better' and more general way? maybe one that has these two as just cases?

also, am i right to use LinkedList according to your suggestion? do the .data's of Links get destroyed along with the latter, and along with the latters' parent List's? if not, how can i flush them along?

edit: flush them by a loop through the List on-destroy?