• 🏆 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!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

[JASS] A few odds-and-ends questions

Status
Not open for further replies.
Level 5
Joined
Sep 19, 2006
Messages
152
Here's a few questions for all you pros out there:

1) I haven't posted in a very long time, and can't remember what to enclose between the "[ ]" when posting triggers. Is it something like jass and .jass, or .jass and /.jass?

2) In "regular" JASS (not that vJASS stuff), is it necessary to determine if "u" (for example) will return a null unit? For instance, in the following trigger....

set u1 = GetTriggerUnit ()
set u2
if u2 != null then
call IssueTargetOrder (u2, "smart", u1)
endif

is the "if/then" line in the above trigger really necessary, or can it (and the endif) be omitted?

3) Somewhere along the line, my project map went from 3500 kbs in size to about 3700, but the loading time went from 3 minutes to about 6. Are there any tricks to reduce this horrific loading time?

4) Lastly, when used in a loop, is call PolledWait better or worse than TriggerSleepAction? And for these functions, what is the shortest duration recommended?

loop
call PolledWait (2.00) / TriggerSleepAction (2.00)
exitwhen GetUnitAbilityLevel (trig_unit, 'BOhx') == 0
endloop


I certainly appreciate the help; this site has proven an invaluable resource!
 
Level 5
Joined
Sep 19, 2006
Messages
152
Thank you for your quick reply, Axarion. But please point me in the right direction: where can I find a map optimizer and what do you mean by a timer loop? Thanks!
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
JASS:
set u1 = GetTriggerUnit ()
set u2
if u2 != null then
call IssueTargetOrder (u2, "smart", u1)
endif

The line set u2 will give you a syntax error because you set a variable but don't have = something.

Also, if you're issuing an order with a null unit then the function will probably return false and not do anything, so it's up to you whether or not you include the if-statement. In some situations if-statements are necessary (for example, to avoid divide-by-zero errors).

DistanceHaze said:
1) I haven't posted in a very long time, and can't remember what to enclose between the "[ ]" when posting triggers. Is it something like jass and .jass, or .jass and /.jass?

It's
JASS:
[code=jass]
. In order to end the tags you have to add a "/" before "jass". So, like [/icode]. Funny, in order to make that work properly I had to add purposeless tags after the
JASS:
[code=jass]
part so that it wouldn't tag my text. Weird though when I try to make it look like my JASS tags aren't working they do!
 
4) Timers -> Best, most accurate. However, it requires attaching systems.
PolledWait -> Doesn't null the timer. (which is bad) However, it is less random than TriggerSleepAction because it will check to see if it passed the waiting duration. However, the least time you can wait is .250 seconds for PolledWait.
TriggerSleepAction -> Generally, in large waits you won't notice the difference. However, in small waits, where accuracy is important, this is not preferable because its actual wait time is very random. Inputting 0 or a very low number can yield anywhere from about 0.78 seconds wait to .250 seconds. (or something along those lines if memory serves me correctly)
 
Level 5
Joined
Sep 19, 2006
Messages
152
Thank you, Berbanog. Actually, the line in the trigger was supposed to read something like:

set u2 = bj_ghoul [9999]

but I must have missed the rest.

Do you know anything about the map optimizer or timer loop that Axarion mentioned earlier? I appreciate any assistance that you (or anyone) can offer.
 
Level 5
Joined
Sep 19, 2006
Messages
152
Thanks, PurgeandFire1111. Using the small loop:

loop
call PolledWait (2.00)
exitwhen GetUnitAbilityLevel (trig_unit, 'BOhx') == 0
endloop

can you show me an example of "best, most accurate" timer you mention in your post?
 
This tutorial might help:
Timers, the Tricks and the Traps

Once you read through that, you'll generally understand that it is a matter of attachment that is tricky. After reading that tutorial (it is outdated), you might want to read:
Hashtables and MUI

After that, you'll get the basics of normal attaching. Then you will want to look into reading some vJASS tutorials to optimize the attachment method even further. Generally put, just try to read as many tutorials as you can to get yourself started off. ;)
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
If you're using JNGP with JassHelper then I strongly suggest you try using structs along with stacks instead. What a stack basically represents is a long list of data (which you can shape anyway you want using struct definitions) that you can access at any given time, typically used when applying actions to various objects on a timed interval.

Let's say you have a struct. Let's call it "example":

JASS:
struct example
    unit ex_unit = null //handles must be nulled
    unit ex_unit2 = null

    real ex_a //primitives do not
    real ex_b
    boolean ex_c
endstruct

Okay, so now you want a stack of these. What that will entail is creating a global array that will represent your stack. Make sure you keep track of how large your stack is at all times as well.

JASS:
globals
    example array dataStack
    integer dataStackSize = 0 //none exist at initialization
endglobals

Okay, so now you have your struct and your stack. Now you're going to have to make sure that you supply the struct with appropriate methods to recycle the necessary components of the stack when they are no longer required.

For example, let's say you created one instance of example. What you'll want this to do is get added to the stack that was declared in the globals block, and add to the size so that it is an accurate representation of the size of your stack. This would look as follows:

JASS:
struct example
    //...
    static method create takes nothing returns thistype
        local thistype data = allocate() //allocate struct to be returned

        //now we want to add "data" to the stack:
        set dataStack[dataStackSize] = data
        set dataStackSize = dataStackSize + 1 //update size

        //finally we can return the data, and it has been added to the stack
        return data
    endmethod
    //...
endstruct

Now in order to make sure that each item is removed from the stack when necessary (when the struct is destroyed), we're going to need to declare method onDestroy.

JASS:
struct example
    //...
    method onDestroy takes nothing returns nothing

    endmethod
endstruct

Now, in order to make the onDestroy method work properly we're going to need to be able to reference something from the struct. We need to be able to reference which index of the stack the current struct resides at so that when it is destroyed its position in the stack can be shifted with the last as to not lose data.

JASS:
struct example
    //...
    private integer index

    static method create takes nothing returns thistype
        local thistype data=allocate()
        set data.index=dataStackSize
        set dataStack[dataStackSize]=data
        set dataStackSize=dataStackSize+1
        return data
    endmethod
endstruct

Now that we've got reference to the index, we can define the onDestroy method.

JASS:
method onDestroy takes nothing returns nothing
    //reduce the size of the data-stack first.
    set dataStackSize = dataStackSize - 1

    //now, we must swap the position of this instance and 
    //the last instance so that data from the stack is not
    //lost in any situation.
    set dataStack[ index ] = dataStack[ dataStackSize ]

    //in addition, we need to adjust the value of "index" 
    //in the replaced struct so that it points to the correct
    //index value
    set dataStack[ index ].index = index
endmethod

Now when you want to iterate through this data with a timer all you need to do is run an integer from dataStackSize to 0 (so values that are swapped do not interfere with the order in which they are seen), in which case you could reference each instance of the struct as dataStack[intVar]. In many situations this is the most efficient way of "attaching" data to a timer, as it only requires a single timer and is allows the same amount of control over what you are referencing. When using a unique handle ID with hash-tables it means you have to use a separate timer with a unique handle ID for each data set that you want to associate.

I should really write a tutorial on this.

PurgeandFire111 said:
(or something along those lines if memory serves me correctly)

That would be considered accurate for TriggerSleepAction. Also, PolledWait just uses TriggerSleepAction so at the roots its got the same problems. I would say it's even worse since it leaks a timer (if that is true, just going on what you've said). Typically with the sleep function the result can vary by more than a second, not to mention if it is used in the wrong place (I doubt this is a problem in GUI) it can cause the thread to be aborted, thus stopping the map's script. I think this only happens if used in initialization scripts though.
 
Status
Not open for further replies.
Top