Tutorial tods, splits and joins

Sgqvur

FullOfUltimateTruthsAndEt ernalPrinciples, i.e shi
Reaction score
62
First thing first, what does TOD mean?
Well it means Time Of Day (Off Topic: also it's the nickname of the former professional Warcraft 3 TFT player Tod (aka 4K.Tod)
who I think is now a decent SC2 player as well =), so yeah go Tod!), which can be tweaked in Warcraft 3 as I think we all know.
There are two functions below that act as a wrappers for the natives, that I think work more "intuitively".
Well you might ask, what's so bad about the natives? Well say for example that you need/want to set the TOD to 01:30.
You can do that with [ljass]SetFloatGameState(GAME_STATE_TIME_OF_DAY, 1.5)[/ljass]. See the "problem"? The second argument 1.5
is what the wrappers try to "fix". Now say you want to set the TOD to 01:47? Not so "intuitive" eh? So what the wrapper allows you
is to just use 1.47 as an argument or in general x.y (0 <= x <= 23, 0 <= y <= 59).

The two wrappers:
JASS:

function settod takes real time returns nothing
    local integer whole_part = R2I(time)
    local real    real_part  = time - whole_part

    set real_part = real_part / 60 * 100
 
    call SetFloatGameState(GAME_STATE_TIME_OF_DAY, whole_part + real_part)
endfunction

function TriggerRegisterTODEvent takes trigger t, real time returns event
    local integer whole_part = R2I(time)
    local real    real_part  = time - whole_part
 
    set real_part = real_part / 60 * 100
      
    return TriggerRegisterGameStateEvent(t, GAME_STATE_TIME_OF_DAY, EQUAL, whole_part + real_part)
endfunction

// example usage:
// call settod(13.37)
// call TriggerRegisterTODEvent(t, 5.50)



The second things are the functions split and join. These functions work in the following way:
split:

The split function takes a "pattern" argument and a string to split and returns an array
containing the substrings, I think an example might help to clarify things:

[ljass]string array sa = split(":", "a:b:c:d")[/ljass]

the result of the above line (which is not a valid [v]Jass[2], nor I think anything else for that matter)
simply sets (it creates a new array) the first element of sa to a, the second to b, etc. So the sa will look like:

---- 0 1 2 3
sa: |a|b|c|d|

join:

The join function does the opposite, it takes an array and a string parameter and it "fuses/glues/concatenates" the elements of
the array in to a string, ex:

[ljass]string s = join(".", ["the", "helper", "net"])[/ljass]

the result would be that s == "the.helper.net" (again the above line is not a valid [v]Jass[2])


Okay, but the problem with [v]Jass[2] is that functions can't take nor return arrays. So does that mean
that the split and join can't be used? Of course not. The workaround is to make them use implicit arrays,
not explicitly accept arrays as arguments.


So the following is a textmacro that allows users to make their own split/join functions that work
on a implicit array specified also in the textmacro arguments:

JASS:


function index takes string source, string pattern, integer offset returns integer
    local integer source_len  = StringLength(source)
    local integer pattern_len = StringLength(pattern)
    local integer str_p       = 0

    if offset &lt; 0 then
        set str_p = source_len + offset
    else
        set str_p = str_p + offset
    endif

    loop
        exitwhen str_p &gt;= source_len - pattern_len  + 1
        
        if SubString(source, str_p, str_p + pattern_len) == pattern then
            return str_p
        endif

        set str_p = str_p + 1
    endloop

    return -1
endfunction

//! textmacro SPLIT_JOIN takes ARRAY_NAME, SPLIT_NAME, JOIN_NAME
globals
    string array $ARRAY_NAME$
    integer $ARRAY_NAME$_size = 0
endglobals

function $SPLIT_NAME$ takes string pattern, string source returns nothing
    local integer a = 0
    local integer b = 0

    set $ARRAY_NAME$_size = 0

    if pattern != &quot;&quot; and pattern != null then
        set b = index(source, pattern, a)
        loop
            exitwhen b &lt; 0
        
            set $ARRAY_NAME$[$ARRAY_NAME$_size] = SubString(source, a, b)
            set $ARRAY_NAME$_size = $ARRAY_NAME$_size + 1

            set a = b + 1
            set b = index(source, pattern, a)
        endloop
        set $ARRAY_NAME$[$ARRAY_NAME$_size] = SubString(source, a, StringLength(source))
        set $ARRAY_NAME$_size = $ARRAY_NAME$_size + 1
    else
        loop
            exitwhen $ARRAY_NAME$_size &gt;= StringLength(source)
            set $ARRAY_NAME$[$ARRAY_NAME$_size] = SubString(source, $ARRAY_NAME$_size, $ARRAY_NAME$_size + 1)
            set $ARRAY_NAME$_size = $ARRAY_NAME$_size + 1
        endloop
    endif
endfunction

function $JOIN_NAME$ takes string glue returns string
    local string  result      = &quot;&quot;
    local integer split_index = 0

    loop
        exitwhen split_index == $ARRAY_NAME$_size - 1
         
        set result = result + $ARRAY_NAME$[split_index] + glue
        rpu
        set split_index = split_index + 1
    endloop
    set result = result + $ARRAY_NAME$[split_index]

    return result
endfunction   
//! endtextmacro


An example usage might be:

[ljass]//! runtextmacro SPLIT_JOIN("S", "split", "join")[/ljass]
[ljass]//! runtextmacro SPLIT_JOIN("S1", "split1", "join1")[/ljass]

I recommend short names for both the functions (you can call them whatever you like,
not just split/join) and the implicit array, which will make both using them easier and some folks
think scripts will run faster, which is rather curious (but it can reduce readability of course).

So what good are the split/join combo in the realm of [v]Jass[2]?
Well as you can find out in the attached map, they can be really, really helpful for handling commands by the player(s)/"learning" purposes.

I will try to give here an arguable senseless example that uses two splits.
Say you have a save/load code in your map, that uses the format [ljass][str:agi:int x:y:z i1:i2:i3:i4:i5:i6][/ljass],

and you want to "load/init" your hero struct with those values.

Lets assume we have 2 split functions called split (uses S[] as implicit array) and split1 (uses S1[] as implicit array)

if we call split(" ", player_inputed_string) then
S[0] will be "str:agi:int"

now if we split1(":", S[0]) we will have

S1[0] = "str"
S1[1] = "agi"
S1[2] = "int"

and we can now easily set those values to our struct.

The same goes for S[1] which is "x:y:z" and S[2] which is "i1:i2:...:i6"

So I think this demonstrates how useful splits can be.

But what about join(s)? Well join can be useful as well, but I really can't think of an even
arguably good example (other than just printing the contents of the implicit array) for it in [v]Jass[2],
this doesn't mean that some more creative folks won't find it useful of course.


And of course if more split(s) and join(s) are required then simply run another textmacro =)!

PS: the split function is just like the StringExploader(I might be wrong about the name) that Romek (I might be wrong again =))
had uploaded a while back, but I think it's name was Php inspired, and split/join are borrowed from Perl =)
(which are names that probably many other programming languages use [no, not that many other languages are called Perl but
functions with same/similar functionality are called the same [split/join] =)).
 

Attachments

  • tods_splits_joins.w3m
    16.5 KB · Views: 358

Dirac

22710180
Reaction score
147
Straight to graveyard resource. Is there even a resource here?

Nestharus already made a system that handles strings in a better way (and i've never thought i would say this, but's also more understandable than this), why on earth are you using textmacros instead of struct allocation for arrays???
 

UndeadDragon

Super Moderator
Reaction score
448
Is this supposed to have a tutorial prefix?
 
General chit-chat
Help Users

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top