• 🏆 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!

Need Good JASS Writer to Convert Short GUI Code to JASS

Status
Not open for further replies.
Level 4
Joined
Aug 9, 2012
Messages
84
Can someone please rewrite this short trigger from GUI to vJASS, minus the errors, leaks, etc.

I do work in NewGen editor, so whatever coding you do my map will support.

http://www.hiveworkshop.com/forums/pastebin.php?id=6vngks

My map supports 10 players, and I need this trigger to run through Player 1 Red to Player 10 Light Blue.

The regions this trigger relates to are consistent.

They are: Red Teleport Area 1 to Light Blue Teleport Area 10 (in that order). Grey's teleport area is spelled Grey, not Gray.

And for the Exit Areas there are:

Red Exit 1 to Light Blue Exit 10 (in that order)

People I have consulted suggested I rewrite the code but I don't know how.

What I originally have in my map is ten of this same code for each player divided into separate GUI codes on their own. I have been told this doesn't run very smoothly and that it's possible to all be included in just one trigger / strip of JASS.

With that being said, yes, WC3 does allow offset Z to work like that, and it does work, but it's not the best it can be. A few experienced ppl I talked to were surprised with my offset Z usage in GUI for some reason.



Thank You.
 
Level 20
Joined
Jul 6, 2009
Messages
1,885
JASS:
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+) 2.0
//* ----------
//*
//*  To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//*  To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass)   More scripts: htt://www.wc3c.net
//*
//* For your timer needs:
//*  * Attaching
//*  * Recycling (with double-free protection)
//*
//* set t=NewTimer()      : Get a timer (alternative to CreateTimer)
//* set t=NewTimerEx(x)   : Get a timer (alternative to CreateTimer), call
//*                            Initialize timer data as x, instead of 0.
//*
//* ReleaseTimer(t)       : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2)     : Attach value 2 to timer
//* GetTimerData(t)       : Get the timer's value.
//*                         You can assume a timer's value is 0
//*                         after NewTimer.
//*
//* Multi-flavor:
//*    Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************

//================================================================
    globals
        //How to tweak timer utils:
        // USE_HASH_TABLE = true  (new blue)
        //  * SAFEST
        //  * SLOWEST (though hash tables are kind of fast)
        //
        // USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = true  (orange)
        //  * kinda safe (except there is a limit in the number of timers)
        //  * ALMOST FAST
        //
        // USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = false (red)
        //  * THE FASTEST (though is only  faster than the previous method
        //                  after using the optimizer on the map)
        //  * THE LEAST SAFE ( you may have to tweak OFSSET manually for it to
        //                     work)
        //
        private constant boolean USE_HASH_TABLE      = true
        private constant boolean USE_FLEXIBLE_OFFSET = false

        private constant integer OFFSET     = 0x100000
        private          integer VOFFSET    = OFFSET
              
        //Timers to preload at map init:
        private constant integer QUANTITY   = 256
        
        //Changing this  to something big will allow you to keep recycling
        // timers even when there are already AN INCREDIBLE AMOUNT of timers in
        // the stack. But it will make things far slower so that's probably a bad idea...
        private constant integer ARRAY_SIZE = 8190

    endglobals

    //==================================================================================================
    globals
        private integer array data[ARRAY_SIZE]
        private hashtable     ht
    endglobals
    
    

    //It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
    function SetTimerData takes timer t, integer value returns nothing
        static if(USE_HASH_TABLE) then
            // new blue
            call SaveInteger(ht,0,GetHandleId(t), value)
            
        elseif (USE_FLEXIBLE_OFFSET) then
            // orange
            static if (DEBUG_MODE) then
                if(GetHandleId(t)-VOFFSET<0) then
                    call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
                endif
            endif
            set data[GetHandleId(t)-VOFFSET]=value
        else
            // new red
            static if (DEBUG_MODE) then
                if(GetHandleId(t)-OFFSET<0) then
                    call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
                endif
            endif
            set data[GetHandleId(t)-OFFSET]=value
        endif        
    endfunction

    function GetTimerData takes timer t returns integer
        static if(USE_HASH_TABLE) then
            // new blue
            return LoadInteger(ht,0,GetHandleId(t) )
            
        elseif (USE_FLEXIBLE_OFFSET) then
            // orange
            static if (DEBUG_MODE) then
                if(GetHandleId(t)-VOFFSET<0) then
                    call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
                endif
            endif
            return data[GetHandleId(t)-VOFFSET]
        else
            // new red
            static if (DEBUG_MODE) then
                if(GetHandleId(t)-OFFSET<0) then
                    call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
                endif
            endif
            return data[GetHandleId(t)-OFFSET]
        endif        
    endfunction

    //==========================================================================================
    globals
        private timer array tT[ARRAY_SIZE]
        private integer tN = 0
        private constant integer HELD=0x28829022
        //use a totally random number here, the more improbable someone uses it, the better.
        
        private boolean       didinit = false
    endglobals
    private keyword init

    //==========================================================================================
    // I needed to decide between duplicating code ignoring the "Once and only once" rule
    // and using the ugly textmacros. I guess textmacros won.
    //
    //! textmacro TIMERUTIS_PRIVATE_NewTimerCommon takes VALUE
    // On second thought, no.
    //! endtextmacro

    function NewTimerEx takes integer value returns timer
        if (tN==0) then
            if (not didinit) then 
                //This extra if shouldn't represent a major performance drawback
                //because QUANTITY rule is not supposed to be broken every day. 
                call init.evaluate()
                set tN = tN - 1
            else
                //If this happens then the QUANTITY rule has already been broken, try to fix the
                // issue, else fail.
                debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, make sure all timers are getting recycled correctly")
                set tT[0]=CreateTimer()
                static if( not USE_HASH_TABLE) then
                    debug call BJDebugMsg("In case of errors, please increase it accordingly, or set TimerUtils_USE_HASH_TABLE to true")
                    static if( USE_FLEXIBLE_OFFSET) then
                        if (GetHandleId(tT[0])-VOFFSET<0) or (GetHandleId(tT[0])-VOFFSET>=ARRAY_SIZE) then
                            //all right, couldn't fix it
                            call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
                            return null
                        endif
                    else
                        if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
                            //all right, couldn't fix it
                            call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
                            return null
                        endif
                    endif
                endif
            endif
        else
            set tN=tN-1
        endif
        call SetTimerData(tT[tN],value)
     return tT[tN]
    endfunction
    
    function NewTimer takes nothing returns timer
        return NewTimerEx(0)
    endfunction


    //==========================================================================================
    function ReleaseTimer takes timer t returns nothing
        if(t==null) then
            debug call BJDebugMsg("Warning: attempt to release a null timer")
            return
        endif
        if (tN==ARRAY_SIZE) then
            debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")

            //stack is full, the map already has much more troubles than the chance of bug
            call DestroyTimer(t)
        else
            call PauseTimer(t)
            if(GetTimerData(t)==HELD) then
                debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
                return
            endif
            call SetTimerData(t,HELD)
            set tT[tN]=t
            set tN=tN+1
        endif    
    endfunction

    private function init takes nothing returns nothing
     local integer i=0
     local integer o=-1
     local boolean oops = false
        if ( didinit ) then
            return
        else
            set didinit = true
        endif
     
        static if( USE_HASH_TABLE ) then
            set ht = InitHashtable()
            loop
                exitwhen(i==QUANTITY)
                set tT[i]=CreateTimer()
                call SetTimerData(tT[i], HELD)
                set i=i+1
            endloop
            set tN = QUANTITY
        else
            loop
                set i=0
                loop
                    exitwhen (i==QUANTITY)
                    set tT[i] = CreateTimer()
                    if(i==0) then
                        set VOFFSET = GetHandleId(tT[i])
                        static if(USE_FLEXIBLE_OFFSET) then
                            set o=VOFFSET
                        else
                            set o=OFFSET
                        endif
                    endif
                    if (GetHandleId(tT[i])-o>=ARRAY_SIZE) then
                        exitwhen true
                    endif
                    if (GetHandleId(tT[i])-o>=0)  then
                        set i=i+1
                    endif
                endloop
                set tN = i
                exitwhen(tN == QUANTITY)
                set oops = true
                exitwhen not USE_FLEXIBLE_OFFSET
                debug call BJDebugMsg("TimerUtils_init: Failed a initialization attempt, will try again")               
            endloop
            
            if(oops) then
                static if ( USE_FLEXIBLE_OFFSET) then
                    debug call BJDebugMsg("The problem has been fixed.")
                    //If this message doesn't appear then there is so much
                    //handle id fragmentation that it was impossible to preload
                    //so many timers and the thread crashed! Therefore this
                    //debug message is useful.
                elseif(DEBUG_MODE) then
                    call BJDebugMsg("There were problems and the new timer limit is "+I2S(i))
                    call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low:")
                    call BJDebugMsg("a) Change USE_FLEXIBLE_OFFSET to true (reduces performance a little)")
                    call BJDebugMsg("b) or try changing OFFSET to "+I2S(VOFFSET) )
                endif
            endif
        endif

    endfunction

endlibrary
JASS:
library Teleport initializer init requires TimerUtils

    globals
        private region array enters
        private hashtable table = InitHashtable()
    endglobals
    
    private function end takes nothing returns nothing
        call SetUnitInvulnerable(LoadUnitHandle(table, GetHandleId(GetExpiredTimer()), 0), false)
        call ReleaseTimer(GetExpiredTimer())
    endfunction 
    
    private function playSound takes nothing returns nothing
        if GetLocalPlayer() == GetOwningPlayer(LoadUnitHandle(table, GetHandleId(GetExpiredTimer()), 0))
            call StartSound(gg_snd_ResurrectTarget)
        endif
        call TimerStart(GetExpiredTimer(), 3.00, false, function end)
    endfunction

    private function teleport takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local rect r
        local real x
        local real y
        local timer t
        if IsUnitType(u, UNIT_TYPE_HERO) then
            set r = LoadRectHandle(table, GetHandleId(GetTriggeringRegion()), 0)
            set x = GetRectCenterX(r)
            set y = GetRectCenterY(r)
            set r = null
            call SetUnitX(u, x)
            call SetUnitY(u, y)
            call IssueImmediateOrder(u, "stop")
            if (GetLocalPlayer() == GetOwningPlayer(u)) then
                call PanCameraToTimed(x, y, 0.00)
            endif
            call SetUnitInvulnerable(u, true)
            set t = NewTimer()
            call SaveUnitHandle(table, GetHandleId(t), 0 , u)
            call TimerStart(t, 0.25, false, function playSound)
            set t = null      
        endif     
        set u = null
    endfunction

    private function init takes nothing returns nothing
        local trigger t = CreateTrigger()
        set enters[0] = CreateRegion()
        set enters[1] = CreateRegion()
        set enters[2] = CreateRegion()
        set enters[3] = CreateRegion() 
        set enters[4] = CreateRegion()  
        set enters[5] = CreateRegion()  
        set enters[6] = CreateRegion()
        set enters[7] = CreateRegion()
        set enters[8] = CreateRegion()          
        set enters[9] = CreateRegion()
        call RegionAddRect(enters[0], gg_rct_Red_Teleport_Area_1)
        call RegionAddRect(enters[1], gg_rct_Blue_Teleport_Area_2)
        call RegionAddRect(enters[2], gg_rct_Teal_Teleport_Area_3)
        call RegionAddRect(enters[3], gg_rct_Purple_Teleport_Area_4)
        call RegionAddRect(enters[4], gg_rct_Yellow_Teleport_Area_5)
        call RegionAddRect(enters[5], gg_rct_Orange_Teleport_Area_6)
        call RegionAddRect(enters[6], gg_rct_Green_Teleport_Area_7)
        call RegionAddRect(enters[7], gg_rct_Pink_Teleport_Area_8)
        call RegionAddRect(enters[8], gg_rct_Grey_Teleport_Area_9)
        call RegionAddRect(enters[9], gg_rct_Light_Blue_Teleport_Area_10)
        call SaveRectHandle(table, GetHandleId(enters[0]), 0, gg_rct_Red_Exit_1)
        call SaveRectHandle(table, GetHandleId(enters[1]), 0, gg_rct_Blue_Exit_2)
        call SaveRectHandle(table, GetHandleId(enters[2]), 0, gg_rct_Teal_Exit_3)
        call SaveRectHandle(table, GetHandleId(enters[3]), 0, gg_rct_Purple_Exit_4)
        call SaveRectHandle(table, GetHandleId(enters[4]), 0, gg_rct_Yellow_Exit_5)
        call SaveRectHandle(table, GetHandleId(enters[5]), 0, gg_rct_Orange_Exit_6)
        call SaveRectHandle(table, GetHandleId(enters[6]), 0, gg_rct_Green_Exit_7)
        call SaveRectHandle(table, GetHandleId(enters[7]), 0, gg_rct_Pink_Exit_8)
        call SaveRectHandle(table, GetHandleId(enters[8]), 0, gg_rct_Gray_Exit_9)
        call SaveRectHandle(table, GetHandleId(enters[9]), 0, gg_rct_Light_Blue_Exit_10) 
        call TriggerRegisterEnterRegion(t, enters[0], null)          
        call TriggerRegisterEnterRegion(t, enters[1], null)         
        call TriggerRegisterEnterRegion(t, enters[2], null)    
        call TriggerRegisterEnterRegion(t, enters[3], null)       
        call TriggerRegisterEnterRegion(t, enters[4], null)
        call TriggerRegisterEnterRegion(t, enters[5], null)     
        call TriggerRegisterEnterRegion(t, enters[6], null)
        call TriggerRegisterEnterRegion(t, enters[7], null)     
        call TriggerRegisterEnterRegion(t, enters[8], null)     
        call TriggerRegisterEnterRegion(t, enters[9], null)
        call TriggerAddAction(t, function teleport)
        set t = null
    endfunction

endlibrary
The Waits you use aren't really accurate (Warcraft's fault) and thus not recommended, but if it works as intended I guess you may leave them be (they're used in the code above). If not, I can use an alternate way that is accurate, but requires more code. Done.

Also note that other players may enter regions that do not belong to them and get teleported, as long as the entering unit is a hero.
I didn't add a limitation for this as it wasn't in your code and you may want it that way, but I can add it if you want.
 
Last edited:
Level 4
Joined
Aug 9, 2012
Messages
84
Yes, I understand that the unit must only be a Hero. My kind of map is like the new Blades n' Gore map yet all ranged-based, not close quarters combat (CQC). When I say like I mean gamestyle-wise, being a duel / tournament-based game.

Anyway, yeah, the only units entering these regions and exiting them are heroes only.

If you could rework it so it is more accurate in the times that would be appreciated. You will see I did 3.20 seconds in one of the lines of GUI code because I tried to guess how much the wait time is off. This shows I have knowledge that I do know the waits are off. I need it to be exactly 3 seconds for each player, not 3.20, as seen in my original GUI code. 0.25 seconds would be more accurate where it says 0.28. I want it 0.25.

P.S. How off is GUI's wait times? If I set something to last 1 second, 2 seconds, 3 seconds or 45 seconds, how much would those integers I just said be off?

I ask this so I can correct them because a lot of my code is in GUI. So what would I set those integers to to equal what I want them to?



Thank You so much!
Siryan
 
Level 4
Joined
Aug 9, 2012
Messages
84
I don't know who it is you're referring to, the person who wrote the code in vJASS or me in my GUI code (which does work the way I want(ed) it). I just think being in vJASS it'd be more smoother.

That's the idea.
 
Last edited by a moderator:
Level 20
Joined
Jul 6, 2009
Messages
1,885
Edited first post and changed it to Action. But why would it not work? All of the used event responses work in condition.

Also replaced Waits with Timers that are accurate. Though you'll have to use one more library (TimerUtils) which I have included in first post.
 
Last edited:
Status
Not open for further replies.
Top