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

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,183

JASS:
//! zinc
    library Wanderer {
 
        hashtable hash = InitHashtable();
 
        function Move(unit u) {
            integer id = GetHandleId(u);
            integer dist = GetRandomInt(500,1500);
            real angle = GetRandomReal(0, 360);
            real x = GetUnitX(u) + dist * Cos(angle * bj_DEGTORAD);
            real y = GetUnitY(u) + dist * Sin(angle * bj_DEGTORAD);
       
            SaveInteger(hash, id, 0, GetTerrainType(x, y));
       
            SaveReal(hash, id, 1, x);
            SaveReal(hash, id, 2, y);
       
            IssuePointOrder(u, "move", x, y);
            SetTerrainType(x, y, 'Nsnw', -1, 1, 0);
        }
   
        function GetDistance(real cx, real cy, real dx, real dy) -> real {
            real x = dx - cx;
            real y = dy - cy;
            return SquareRoot(x * x + y * y);
        }
   
        function GroupActions() {
            unit u = GetEnumUnit();
            integer id = GetHandleId(u);
            real x = LoadReal(hash, id, 1);
            real y = LoadReal(hash, id, 2);
            if(GetDistance(GetUnitX(u), GetUnitY(u), x, y) < 50) {
                SetTerrainType(x, y, LoadInteger(hash, id, 0), -1, 1, 0);
                //chosing to not clear the hashtable since the values gets replaced anyway
                Move(u);
            }
            u = null;
        }
   
        function onLoop() {
            group g = GetUnitsInRectMatching(bj_mapInitialPlayableArea, null);
            ForGroup(g, function GroupActions);
            DestroyGroup(g);
            g = null;
        }
 
        function onInit() {
            timer t = CreateTimer();
            TimerStart(t, 0.03, true, function onLoop);
            Move(CreateUnit(Player(0), 'hgry', 0, 0, 0));
            t = null;
        }
    }
//! endzinc
 

Attachments

  • 2 Wanderer.w3m
    16.5 KB · Views: 36
Last edited:
This method using a group is a work around for the desired task; no group is needed at all, and hashtable can be used directly instead. Your way does also pick all other units, which is unwanted behaviour.

You don't have to, but I believe the mission can be solved with 2 functions, one init function that sets everything up, and one callback function.
 

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,183
JASS:
//! zinc
    library Wanderer {
   
        hashtable hash = InitHashtable();
        unit toMove;
   
        function Move(unit u) {
            integer id = GetHandleId(u);
            integer dist = GetRandomInt(500,1500);
            real angle = GetRandomReal(0, 360);
            real x = GetUnitX(u) + dist * Cos(angle * bj_DEGTORAD);
            real y = GetUnitY(u) + dist * Sin(angle * bj_DEGTORAD);
           
            SaveInteger(hash, id, 0, GetTerrainType(x, y));
           
            SaveReal(hash, id, 1, x);
            SaveReal(hash, id, 2, y);
           
            IssuePointOrder(u, "move", x, y);
            SetTerrainType(x, y, 'Nsnw', -1, 1, 0);
        }
       
        function GetDistance(real cx, real cy, real dx, real dy) -> real {
            real x = dx - cx;
            real y = dy - cy;
            return SquareRoot(x * x + y * y);
        }
       
        function Actions() {
            integer id = GetHandleId(toMove);
            real x = LoadReal(hash, id, 1);
            real y = LoadReal(hash, id, 2);
            if(GetDistance(GetUnitX(toMove), GetUnitY(toMove), x, y) < 50) {
                SetTerrainType(x, y, LoadInteger(hash, id, 0), -1, 1, 0);
                //chosing to not clear the hashtable since the values gets replaced anyway
                Move(toMove);
            }
        }
   
        function onInit() {
            timer t = CreateTimer();
            TimerStart(t, 0.03, true, function Actions);
            toMove = CreateUnit(Player(0), 'hgry', 0, 0, 0);
            Move(toMove);
        }
    }
//! endzinc
 
It doesn't match this part:
Global variabels other than the hashtable are not allowed.
^It's very intended, because hashtable power should be introduced instead. I believe the crash course does help, in case you're confused what I mean.

Logicaly there's nothing wrong with your distance calculation, but I want also point out that there exists a native function to check if a unit is in range of certain x/y coordinates.

Please attach demo, too, when you make updates, so it can be tested.
 

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,183
That is not a global.
By default it is a private member.

*being 'clever'*

edit:
Hm, actually the Zinc manual still calls it a global for some reason which is retarded because a private "global" is not global

Will have to update it because of that I suppose :-/

edit2:
JASS:
//! zinc
    library Wanderer {
   
        hashtable hash = InitHashtable();
   
        function Move(unit u) {
            integer id = GetHandleId(u);
            integer dist = GetRandomInt(500,1500);
            real angle = GetRandomReal(0, 360);
            real x = GetUnitX(u) + dist * Cos(angle * bj_DEGTORAD);
            real y = GetUnitY(u) + dist * Sin(angle * bj_DEGTORAD);
           
            SaveInteger(hash, id, 0, GetTerrainType(x, y));
           
            SaveReal(hash, id, 1, x);
            SaveReal(hash, id, 2, y);
           
            IssuePointOrder(u, "move", x, y);
            SetTerrainType(x, y, 'Nsnw', -1, 1, 0);
        }
       
        function GetDistance(real cx, real cy, real dx, real dy) -> real {
            real x = dx - cx;
            real y = dy - cy;
            return SquareRoot(x * x + y * y);
        }
       
        function Actions() {
            unit u = LoadUnitHandle(hash, 0, 0);
            integer id = GetHandleId(u);
            real x = LoadReal(hash, id, 1);
            real y = LoadReal(hash, id, 2);
            if(GetDistance(GetUnitX(u), GetUnitY(u), x, y) < 50) {
                SetTerrainType(x, y, LoadInteger(hash, id, 0), -1, 1, 0);
                //chosing to not clear the hashtable since the values gets replaced anyway
                Move(u);
            }
            u = null;
        }
   
        function onInit() {
            timer t = CreateTimer();
            unit u = CreateUnit(Player(0), 'hgry', 0, 0, 0);
            TimerStart(t, 0.03, true, function Actions);
            SaveUnitHandle(hash, 0, 0, u);
            Move(u);
            u = null;
        }
    }
//! endzinc
 

Attachments

  • 2 Wanderer.w3m
    16.5 KB · Views: 45
Last edited:

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,183
I can use multiple ways to save the unit into an hashtable.
1. Unit groups
2. raw values
3. timer as parent
4. trigger as parent
5. function pointers

Every single way follows the rules given damn it :<

JASS:
//! zinc
    library Wanderer {
   
        hashtable hash = InitHashtable();
   
        function Move(unit u) {
            integer id = GetHandleId(u);
            integer dist = GetRandomInt(500,1500);
            real angle = GetRandomReal(0, 360);
            real x = GetUnitX(u) + dist * Cos(angle * bj_DEGTORAD);
            real y = GetUnitY(u) + dist * Sin(angle * bj_DEGTORAD);
           
            SaveInteger(hash, id, 0, GetTerrainType(x, y));
           
            SaveReal(hash, id, 1, x);
            SaveReal(hash, id, 2, y);
           
            IssuePointOrder(u, "move", x, y);
            SetTerrainType(x, y, 'Nsnw', -1, 1, 0);
        }
       
        function GetDistance(real cx, real cy, real dx, real dy) -> real {
            real x = dx - cx;
            real y = dy - cy;
            return SquareRoot(x * x + y * y);
        }
       
        function Actions() {
            unit u = LoadUnitHandle(hash, GetHandleId(GetExpiredTimer()), 0);
            integer id = GetHandleId(u);
            real x = LoadReal(hash, id, 1);
            real y = LoadReal(hash, id, 2);
            if(GetDistance(GetUnitX(u), GetUnitY(u), x, y) < 50) {
                SetTerrainType(x, y, LoadInteger(hash, id, 0), -1, 1, 0);
                //chosing to not clear the hashtable since the values gets replaced anyway
                Move(u);
            }
            u = null;
        }
   
        function onInit() {
            timer t = CreateTimer();
            unit u = CreateUnit(Player(0), 'hgry', 0, 0, 0);
            TimerStart(t, 0.03, true, function Actions);
            SaveUnitHandle(hash, GetHandleId(t), 0, u);
            Move(u);
            u = null;
        }
    }
//! endzinc
 

Attachments

  • 2 Wanderer.w3m
    16.5 KB · Views: 47
It seems correct, but the logics is a bit mixed unnecessarily into multiple functions, which makes it less intuitive.

The sense of a function argument is to give explicit values to a function, which you must have.
The sense of a hashtable entry is that you have one entry key as implicit value, for example the timer handle-id in our situation, and we use this entry to get our concrete values, like the binded unit.
So, when we already use the hashtable powers, then it becomes unnecessary to require explicit arguments for our function call.

I would ask you to match this goal and to get rid off the extra "Move(unit u)" funtion, and rely on the implicit callback function which does all logics for the binded unit and also all for terrain change.
there exists a native function to check if a unit is in range of certain x/y coordinates.
Have you read this? :)
 
Hm due to this conversation Missions - Wanderer - Submission,
I maybe think it's acceptable, too, even I would prefer my suggestion. But you can keep it in mind for further missions probably.

Good job.

full
 
Status
Not open for further replies.
Top