• 🏆 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!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

My first attempt at JASS

Status
Not open for further replies.
Level 6
Joined
Oct 26, 2005
Messages
190
So I'm taking the way of the JASS for the first time and I decided to challenge myself with some functions I plan to implement in my map. The purpouse is to declare a set of regions (rects) as "Entrances" and another set as "Exits". So when an unit enters one Entrance, it gets moved to its respective Exit.

JASS:
function Test takes nothing returns nothing
    local unit u
    local rect r
    local rect rexit
    local location l
    local integer i = 0
    set u = GetTriggerUnit()
    loop
        set i = i + 1
        if RectContainsUnit(udg_Entrance[i], u) then
            set rexit = udg_Exit[i]
            set l = GetRectCenter(rexit)
            call SetUnitPositionLoc(u,l)
        endif
    endloop
endfunction

function InitTrig_Test2 takes nothing returns nothing
    local trigger t = CreateTrigger()
    local integer i = 0
    loop
        set i = i + 1
        call TriggerRegisterEnterRectSimple(t, udg_Entrance[i])
        call TriggerAddAction(t, function Test)
    endloop
endfunction

So you have to assume Entrance[array] and Exit[array] are already established (no problem with that). I get good results without the loops (as I was testing with one single "Entrance" and "Exit"), but I thought loops would speed up the whole proccess (main reason I'm learning JASS). So with these loops, I get no starting units (dunno if related) and nothing works.

Any help is apprecciated.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
the problem here is in the way how to made the loop, the reason it doesnt work is becauase you start loop with i=0 but you never exit the loop so the thread crashes and the tree of functions is stopped

for better understanding

lets say I have a function called funca, funcb and funch
Now if I have endless loop in funch and in funca I call funcb and there I call funch the funch is never left because it will loop forever
in Jass you have thread op limit which basically means that after too many things (call, set, anything) the thread crashes which means that the funca will never finish

If you want to exit loop use keyword exitwhen and after that boolean comparation, for instance:
JASS:
loop
    set i = i + 1
    //whatecer code you want
    exitwhen i == 10
    exitwhen i > 6
endloop

note: you can have any number of exitwhen in a loop and when any of them returns true the execution of the loop is stopped

hope this helps you at least a little bit
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Also you don't have luck for your first attempt, region events are bugged.
Depends where the unit is coming (north , east, west, south), when the event fire the unit is inside or outside the region.
Excepted when you move the unit by a trigger action, then it's accurate and instant (it could be even a problem if you use SetUnitX/Y).
 
Level 6
Joined
Oct 26, 2005
Messages
190
Ha, I never got to think about the end of the loop lol

And Troll, so you say it is better to say, calculate the center of the rect as give it some radius so the event actually calculates that location instead of the region for better handling?

Thanks a lot guys, I'm gonna keep the practice!

Edit: So I was playing around again with the code, trying with only 1 region and found what you said, Troll-Brain: I used to display a message whenver the Event is fired and it displayed succesfully, but the unit did not get moved all of the tries as it is supposed to. I will keep working on it.
 
Last edited:
Level 17
Joined
Feb 11, 2011
Messages
1,860
I have made your script a bit more efficient:

JASS:
function Test takes nothing returns boolean     // Change "boolean" to "nothing" if you used TriggerAddAction below.
     local unit u = GetTriggerUnit()
     local rect rexit
     local integer i = 0
     
     loop
        set i = i + 1
        if RectContainsUnit(udg_Entrance[i], u) then
            set rexit = udg_Exit[i]
            // Using co-ordinates is more efficient than locations:
            call SetUnitPosition(u, GetRectCenterX(rexit), GetRectCenterY(rexit))
        endif
        // Remember the exit condition:
        exitwhen i > 6
    endloop

    // Remove leaks:
    set rexit = null
    set u = null
    // Remove this if you use TriggerAddAction below:
    return false
endfunction

function InitTrig_Test2 takes nothing returns nothing
    local trigger t = CreateTrigger()
    local integer i = 0
    
    loop         
        set i = i + 1         
        call TriggerRegisterEnterRectSimple(t, udg_Entrance[i])
        // This is faster than TriggerAddAction.
        // However you need to make Test return a boolen.
        // This can be left as TriggerAddAction though.
        //call TriggerAddCondition(t, function Test)
        call TriggerAddCondition(t, Condition(function Test))
        exitwhen i == 15
    endloop

endfunction
The most important thing is removing the leaks by setting u = null and any local rects as well. There are more things that leak as well, such as players.
 
Last edited:
Level 6
Joined
Oct 26, 2005
Messages
190
So I guess it is about knowing the most efficient function when it comes to JASS. I can't say I understand the whole thing you did, but I kinda get the hang of it.

Anyways, before I read your answer, I noticed global variables don't seem to work on the code (I tried with a region gg_rct_Region_000 instead of udg_Entrance[1] and it worked well (this was a loopless version). This keeps happening with your code. The globals are assigned in another trigger when Elapsed Time is 0 seconds (Also not working on Map Init). What am I doing wrong here?
 
Level 17
Joined
Feb 11, 2011
Messages
1,860
Anyways, before I read your answer, I noticed global variables don't seem to work on the code (I tried with a region gg_rct_Region_000 instead of udg_Entrance[1] and it worked well (this was a loopless version). This keeps happening with your code. The globals are assigned in another trigger when Elapsed Time is 0 seconds (Also not working on Map Init). What am I doing wrong here?

It should still work even if you set the globals when the expired time is 0.0 seconds. I am a little confused as to what is not working; please explain a bit more.

EDIT: If you put a debug message (call BJDebugMsg("Hello")) in the InitTrig_Test2 function, does it display?
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Ha, I never got to think about the end of the loop lol

And Troll, so you say it is better to say, calculate the center of the rect as give it some radius so the event actually calculates that location instead of the region for better handling?

Thanks a lot guys, I'm gonna keep the practice!

Edit: So I was playing around again with the code, trying with only 1 region and found what you said, Troll-Brain: I used to display a message whenver the Event is fired and it displayed succesfully, but the unit did not get moved all of the tries as it is supposed to. I will keep working on it.

This is a naive approach, it will work only if regions are not too much closed and their size are not that different (and other cases).

It's just better to link the region and the associated rect, or eventually make a trigger for each region, then when the event fire you know which rect is involved.
 
Level 6
Joined
Oct 26, 2005
Messages
190
It should still work even if you set the globals when the expired time is 0.0 seconds. I am a little confused as to what is not working; please explain a bit more.

EDIT: If you put a debug message ( call BJDebugMsg("Hello") ) in the InitTrig_Test2 function, does it display?

Yes, the trigger detects the unit is entering, but only when I set for example gg_rct_Region_000 and it triggers the message, followed by moving the unit (again, it will only move it if is not a global variable). I'm no rookie when it comes to assigning variables and such and I know they are properly assigned, yet udg_Entrance (wether I set "i" as array or a valid number) won't fire the event.

This is a naive approach, it will work only if regions are not too much closed and their size are not that different (and other cases).

It's just better to link the region and the associated rect, or eventually make a trigger for each region, then when the event fire you know which rect is involved.

Don't worry, I don't plan to use what JASS calls Regions, only Rects :) (at least not yet) Also the main idea is to merge as much as possible of the "system" so it won't help that much to divide the triggers for each Region.

I'll keep looking if I missed something, your help is very apprecciated!

EDIT: I attached the map, with almost no modifications of Mr. Bean's code. Globals don't get to work and also seem to stop every single action in the Map Initialization (?). Another proof the code doesn't seem to take into account the globals is that if it displays a Debug Message (and exitloop is an integer) it will keep showing the message, and map init trigs won't run since loop is infinite. What exactly is happening?
 

Attachments

  • Teleport.w3m
    17.3 KB · Views: 66
Level 17
Joined
Apr 27, 2008
Messages
2,455
Well, you're already using jass region through the function TriggerRegisterEnterRectSimple, it creates a region and that adds it the rect.

I just mean that your approach is not safe (in fact i've made the same thing in GUI before, as you did or so for a GUIer, but i've explained it the requirements (the rects must not be closed to each other and so one ...)

We have a native function GetTriggeringRegion, but no GetTriggeringRect.
The reason is simple, a region can have multiple rects.

So if you want to know which rect is involved when the region event fire, you have to link the region and the rect.
Then, with GetTriggeringRegion you can know which rect is involved.
You can use an hashtable (as an example) to link a region with a rect.

Also if you set the variable on the time event "0" but use them on map init, it will obviously going to fail.
 
Level 6
Joined
Oct 26, 2005
Messages
190
I think I'm not following (I'm still learning JASS). So what you (may) mean is that I can fire the event with a Region but then check in which Rect the unit is? This, assuming I established X Rects in a Region (like a hashtable).

Maybe it is better to stick on GUI for this one? I did the following:

  • Actions
    • For each (Integer A) from 1 to 8, do (Trigger - Add to Building enter <gen> the event (Unit - A unit enters RectStart[(Integer A)]))
Is it efficient enough? No lags, bugs and such?

Also if you set the variable on the time event "0" but use them on map init, it will obviously going to fail.

I didn't get this part at all. You mean I saved the globals on a Map Initialization event and that fails?
 
Status
Not open for further replies.
Top