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

Wanderer - Submission

Status
Not open for further replies.
vJASS:
scope Wanderer initializer Init

    globals
        hashtable hash = InitHashtable()
    endglobals
 
    private function Conditions takes nothing returns boolean
        local unit u = LoadUnitHandle(hash, 0, GetHandleId(Player(0)))
        local real x = LoadReal(hash, 0, GetHandleId(u))
        local real y = LoadReal(hash, 1, GetHandleId(u))
        if RectContainsUnit(RectFromCenterSizeBJ(Location(x,y), 100, 100), u) then
            return true
        endif
        return false
    endfunction

    private function Actions takes nothing returns nothing
        local real x
        local real y
        local unit u = LoadUnitHandle(hash, 0, GetHandleId(Player(0)))
        local integer t = LoadInteger(hash, 2, GetHandleId(u))
        local location l = PolarProjectionBJ(GetUnitLoc(u), GetRandomReal(500,1500), GetRandomReal(0,360))
     
        //SETTING X AND Y TO CURRENT LOCATION
        set x = LoadReal(hash, 0, GetHandleId(u))
        set y = LoadReal(hash, 1, GetHandleId(u))
     
        //SETTING CURRENT LOCATION ORIGINAL TERRAIN
        call SetTerrainType(x, y, t, 1, 1, 0)
     
        //UPDATING X AND Y TO NEW LOCATION
        set x = GetLocationX(l)
        set y = GetLocationY(l)
     
        //SAVING NEW LOCATION ORIGINAL TERRAIN
        call SaveInteger(hash, 2, GetHandleId(u), GetTerrainType(x, y))
     
        //SAVING NEW LOCATION
        call SaveReal(hash, 0, GetHandleId(u), x)
        call SaveReal(hash, 1, GetHandleId(u), y)
     
        //ISSUING ORDER AND CHANGING NEW LOCATION TO SNOW
        call IssuePointOrderLoc(u, "move", l)
        call SetTerrainType(x,y,'Wsnw',-1,1,0)
    endfunction
 
    private function Init takes nothing returns nothing
        local trigger trg = CreateTrigger()
        local unit u
        local real x
        local real y
        local integer c = CountUnitsInGroup(GetUnitsOfTypeIdAll('hgry'))
     
        if c == 0 then
            set u = CreateUnitAtLoc(Player(0), 'hgry', GetRectCenter(GetPlayableMapRect()), GetRandomReal(0,360))
            set x = GetUnitX(u)
            set y = GetUnitY(u)
            call SaveReal(hash, 0, GetHandleId(u), x)
            call SaveReal(hash, 1, GetHandleId(u), y)
            call SaveInteger(hash, 2, GetHandleId(u), GetTerrainType(x, y))
            call SaveUnitHandle(hash, 0, GetHandleId(Player(0)), u)
        endif
     
        call TriggerRegisterTimerEvent(trg, 1, true)
        call TriggerAddCondition(trg, Condition(function Conditions))
        call TriggerAddAction(trg, function Actions)
    endfunction
 
endscope

vJASS:
scope Wanderer initializer Init

    globals
        hashtable hash = InitHashtable()
    endglobals  
   
    private function Conditions takes nothing returns boolean
        local unit u = LoadUnitHandle(hash, 0, GetHandleId(GetLocalPlayer()))
        local real x = LoadReal(hash, 0, GetHandleId(u))
        local real y = LoadReal(hash, 1, GetHandleId(u))
        local location l = Location(x,y)
        local rect r = RectFromCenterSizeBJ(l,100,100)
        if RectContainsUnit(r,u) then
            call RemoveRect(r)
            call RemoveLocation(l)
            set u = null
            return true
        endif
        call RemoveRect(r)
        call RemoveLocation(l)
        set u = null
        return false
    endfunction

    private function Actions takes nothing returns nothing
        local real x
        local real y
        local unit u = LoadUnitHandle(hash, 0, GetHandleId(GetLocalPlayer()))
        local location ul = GetUnitLoc(u)
        local integer t = LoadInteger(hash, 2, GetHandleId(u))
        local location l = PolarProjectionBJ(ul, GetRandomReal(500,1500), GetRandomReal(0,360))
       
        //SETTING X AND Y TO CURRENT LOCATION
        set x = LoadReal(hash, 0, GetHandleId(u))
        set y = LoadReal(hash, 1, GetHandleId(u))
       
        //SETTING CURRENT LOCATION ORIGINAL TERRAIN
        call SetTerrainType(x, y, t, 1, 1, 0)
       
        //UPDATING X AND Y TO NEW LOCATION
        set x = GetLocationX(l)
        set y = GetLocationY(l)
       
        //SAVING NEW LOCATION ORIGINAL TERRAIN
        call SaveInteger(hash, 2, GetHandleId(u), GetTerrainType(x, y))
       
        //SAVING NEW LOCATION
        call SaveReal(hash, 0, GetHandleId(u), x)
        call SaveReal(hash, 1, GetHandleId(u), y)
       
        //ISSUING ORDER AND CHANGING NEW LOCATION TO SNOW
        call IssuePointOrderLoc(u, "move", l)
        call SetTerrainType(x,y,'Wsnw',-1,1,0)
       
        //CLEARING LEAKS
        set u = null
        call RemoveLocation(l)
        call RemoveLocation(ul)
    endfunction
   
    private function Init takes nothing returns nothing
        local trigger trg = CreateTrigger()
        local unit u = CreateUnit(GetLocalPlayer(),'hgry',0,0,GetRandomReal(0,360))
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)

        call SaveReal(hash, 0, GetHandleId(u), x)
        call SaveReal(hash, 1, GetHandleId(u), y)
        call SaveInteger(hash, 2, GetHandleId(u), GetTerrainType(x, y))
        call SaveUnitHandle(hash, 0, GetHandleId(GetLocalPlayer()), u)
       
        call TriggerRegisterTimerEvent(trg, 0.2, true)
        call TriggerAddCondition(trg, Condition(function Conditions))
        call TriggerAddAction(trg, function Actions)
       
        set u = null
        set trg = null
    endfunction
   
endscope
 

Attachments

  • JASS Class - Wanderer.w3x
    25.2 KB · Views: 59
Last edited:
It works :).
Some optimizing:

You Leak a Rect in your function Conditions:
RectFromCenterSizeBJ(Location(x,y), 100, 100) <- this creates a rect on each timeout, which you should Remove: with "call RemoveRect(rect)"​

function Init: Not as tragic as the one above cause done only once
GetRectCenter(GetPlayableMapRect()) <- A Location, you might use the other CreateUnit using cordinates
GetUnitsOfTypeIdAll('hgry') <- A Group, sadly you can't use bj_wantDestroyGroup on it.
Saving the unit as Player(0) feels a bit static can't you save it on something else, afterall Player(0) hasn't much do with this function Actions at all?
 
Thanks for the tips, I've optimized it following what you said:

vJASS:
scope Wanderer initializer Init

    globals
        hashtable hash = InitHashtable()
    endglobals  
   
    private function Conditions takes nothing returns boolean
        local unit u = LoadUnitHandle(hash, 0, GetHandleId(GetLocalPlayer()))
        local real x = LoadReal(hash, 0, GetHandleId(u))
        local real y = LoadReal(hash, 1, GetHandleId(u))
        local rect r = RectFromCenterSizeBJ(Location(x,y),100,100)
        if RectContainsUnit(r,u) then
            call RemoveRect(r)
            return true
        endif
        call RemoveRect(r)
        return false
    endfunction

    private function Actions takes nothing returns nothing
        local real x
        local real y
        local unit u = LoadUnitHandle(hash, 0, GetHandleId(GetLocalPlayer()))
        local integer t = LoadInteger(hash, 2, GetHandleId(u))
        local location l = PolarProjectionBJ(GetUnitLoc(u), GetRandomReal(500,1500), GetRandomReal(0,360))
       
        //SETTING X AND Y TO CURRENT LOCATION
        set x = LoadReal(hash, 0, GetHandleId(u))
        set y = LoadReal(hash, 1, GetHandleId(u))
       
        //SETTING CURRENT LOCATION ORIGINAL TERRAIN
        call SetTerrainType(x, y, t, 1, 1, 0)
       
        //UPDATING X AND Y TO NEW LOCATION
        set x = GetLocationX(l)
        set y = GetLocationY(l)
       
        //SAVING NEW LOCATION ORIGINAL TERRAIN
        call SaveInteger(hash, 2, GetHandleId(u), GetTerrainType(x, y))
       
        //SAVING NEW LOCATION
        call SaveReal(hash, 0, GetHandleId(u), x)
        call SaveReal(hash, 1, GetHandleId(u), y)
       
        //ISSUING ORDER AND CHANGING NEW LOCATION TO SNOW
        call IssuePointOrderLoc(u, "move", l)
        call SetTerrainType(x,y,'Wsnw',-1,1,0)
    endfunction
   
    private function Init takes nothing returns nothing
        local trigger trg = CreateTrigger()
        local unit u = CreateUnit(GetLocalPlayer(),'hgry',0,0,GetRandomReal(0,360))
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)

        call SaveReal(hash, 0, GetHandleId(u), x)
        call SaveReal(hash, 1, GetHandleId(u), y)
        call SaveInteger(hash, 2, GetHandleId(u), GetTerrainType(x, y))
        call SaveUnitHandle(hash, 0, GetHandleId(GetLocalPlayer()), u)
       
        call TriggerRegisterTimerEvent(trg, 0.2, true)
        call TriggerAddCondition(trg, Condition(function Conditions))
        call TriggerAddAction(trg, function Actions)
    endfunction
   
endscope
 
Well the init is now fine, but you leak locations sorry for didn't seeing that previously.
In the conditions Location(x,y) <- Creates an Location Object
Actions:
Location l is not Removed
GetUnitLoc(u) <- Location which is not removed either​
call RemoveLocation(Loc)

Edit: Stuff that does not have to be removed/Destroyed are the basic Types from which the more advanced inherit / or which they contain: they are (integer, real, boolean, String, handle, Code; according to JASS Manual: Types )
 

Jampion

Code Reviewer
Level 15
Joined
Mar 25, 2016
Messages
1,327
I think it would be better to use coordinates (as I already said in another thread). There is no need to create a location and a rect every time, if you can just make a simple distance comparison.
Rects are also rectangular, but in this case it does not make much of a difference.
If you decide to use locations and rects though, you should null them.
The destroy/remove functions only free space in the memory, where the handle variable points to. You still need to null the variable to avoid handle leak. It's a very small leak, but it should still be avoided.
 
Thanks Tasyen for reviewing this code and Jampion for all the tips, including the other missions I've submitted. It is surely helping me to improve a lot.

vJASS:
scope Wanderer initializer Init

    globals
        hashtable hash = InitHashtable()
    endglobals  
   
    private function Actions takes nothing returns nothing
        local unit u = LoadUnitHandle(hash, 0, GetHandleId(GetLocalPlayer()))
        local real x = LoadReal(hash, 0, GetHandleId(u))
        local real y = LoadReal(hash, 1, GetHandleId(u))
        local real tx = x + GetRandomReal(500,1500) * Cos(GetRandomReal(0,360) * bj_DEGTORAD)
        local real ty = y + GetRandomReal(500,1500) * Sin(GetRandomReal(0,360) * bj_DEGTORAD)
        local integer t = LoadInteger(hash, 2, GetHandleId(u))
       
        if IsUnitInRangeXY(u,x,y,20) then
            call SetTerrainType(x, y, t, 1, 1, 0)        
            call SaveInteger(hash, 2, GetHandleId(u), GetTerrainType(tx,ty))        
            call SaveReal(hash, 0, GetHandleId(u), tx)
            call SaveReal(hash, 1, GetHandleId(u), ty)        
            call IssuePointOrder(u,"move",tx,ty)
            call SetTerrainType(tx,ty,'Wsnw',-1,1,0)
        endif
       
        set u = null
    endfunction
   
    private function Init takes nothing returns nothing
        local timer t = CreateTimer()
        local unit u = CreateUnit(GetLocalPlayer(),'hgry',0,0,GetRandomReal(0,360))
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)

        call SaveReal(hash, 0, GetHandleId(u), x)
        call SaveReal(hash, 1, GetHandleId(u), y)
        call SaveInteger(hash, 2, GetHandleId(u), GetTerrainType(x, y))
        call SaveUnitHandle(hash, 0, GetHandleId(GetLocalPlayer()), u)
       
        call TimerStart(t,0.2,true,function Actions)
       
        set u = null
    endfunction
   
endscope
 

Attachments

  • JASS Class - Wanderer.w3x
    24.5 KB · Views: 54
It works, though it's not very properly structured.

  1. The code only works if the unit is located at 0/0 at initial state. - this works in this specific case, but making it as restriction is not favourable.
  2. Your unit is functionaly binded to the timer, because it handles the callback, but technicaly binded to the player -- why is this inconsistency needed? I think it should be technicaly binded to the timer, too. : )
  3. There are several actions that are executed, even if not used; it makes no functional difference in your case, but only a technical one. A good architecture considers avoiding actions when not needed; for example the tx/ty assigning each callback.
  4. hashtable could be private
 
I see what you mean, it took me some time to figure out how to optimize the code accordingly, but I guess I've done it:

vJASS:
scope Wanderer initializer Init

    globals
        private hashtable hash = InitHashtable()
    endglobals  
   
    private function MoveOrder takes unit u returns nothing
        local real x = LoadReal(hash,0,GetHandleId(u))
        local real y = LoadReal(hash,1,GetHandleId(u))
        local real tx = x + GetRandomReal(500,1500) * Cos(GetRandomReal(0,360) * bj_DEGTORAD)
        local real ty = y + GetRandomReal(500,1500) * Sin(GetRandomReal(0,360) * bj_DEGTORAD)
        local integer t = LoadInteger(hash,2,GetHandleId(u))
       
        call SetTerrainType(x, y, t, 1, 1, 0)        
        call SaveInteger(hash, 2, GetHandleId(u), GetTerrainType(tx,ty))        
        call SaveReal(hash, 0, GetHandleId(u), tx)
        call SaveReal(hash, 1, GetHandleId(u), ty)        
        call IssuePointOrder(u,"move",tx,ty)
        call SetTerrainType(tx,ty,'Wsnw',-1,1,0)
    endfunction
   
    private function PositionCheck takes nothing returns nothing
        local timer tim = GetExpiredTimer()
        local unit u = LoadUnitHandle(hash,0,GetHandleId(tim))
        local real x = LoadReal(hash,0,GetHandleId(u))
        local real y = LoadReal(hash,1,GetHandleId(u))
       
        if IsUnitInRangeXY(u,x,y,20) then            
            call MoveOrder(u)
        endif
       
        set u = null
    endfunction
   
    private function Init takes nothing returns nothing
        local timer t = CreateTimer()
        local unit u = CreateUnit(GetLocalPlayer(),'hgry',0,0,GetRandomReal(0,360))
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)

        call SaveReal(hash, 0, GetHandleId(u), x)
        call SaveReal(hash, 1, GetHandleId(u), y)
        call SaveInteger(hash, 2, GetHandleId(u), GetTerrainType(x, y))
        call SaveUnitHandle(hash,0,GetHandleId(t),u)
        call MoveOrder(u)
        call TimerStart(t,0.2,true,function PositionCheck)

        set u = null
    endfunction
   
endscope
 

Attachments

  • JASS Class - Wanderer.w3x
    24.7 KB · Views: 53
Status
Not open for further replies.
Top