Structs are great for storing multiple values to one thing. When you "create" a struct, you are creating a new instance. Each instance can have its own members, and those members vary depending on which instance you have (that's what I meant by storing multiple values to one thing). So let's take this example:
JASS:
struct A
real x
real y
endstruct
function Example takes nothing returns nothing
local A myStruct = A.create()
set myStruct.x = 5
set myStruct.y = 10
endfunction
The A.create() will return a specific instance, and then you can assign the member values to that instance. In this case, x = 5 and y = 10. If you have another instance, those x and y values won't be the same unless you make it so.
Now, you want to assign some variables to a unit, correct? Well, that just means we have to associate a unit with the struct instance. After all, if each instance has its own variables with values, and we have an instance for each unit, then you will have a bunch of variables that you can assign for one unit! (which is what you seem to be trying to do)
The problem is the association. How do we get the struct instance from the unit? If you just create an instance like so:
JASS:
struct A
unit u
endstruct
/* .. some code later .. */
local A temp = A.create()
set A.u = GetTriggerUnit()
How will you get the instance later on? You have to have some way to point back to the instance. Some people will use unit indexing systems for this, in that you can have a struct instance that is equal to the unit's index. Whenever you need to get the struct instance, you would just do A(GetUnitIndex(<unit>)), or something similar.
I assume you don't want to use a custom system. Therefore, your best bet is to use hashtables. This is actually pretty efficient, so don't worry about it being slow or anything. You basically would assign it under the unit's handle ID:
JASS:
call SaveInteger(hash, 0, GetHandleId(<unit>), myInstance)
So let me give you an example. I want to store a unit's last point order in a struct. I want to store the real x and y of it.
JASS:
scope Example initializer onInit
/* scopes are just wrappers */
/* I use it to declare an initialization function */
/* initializers are called on map initialization */
globals
private hashtable hash /* for associating unit with struct */
endglobals
struct LastOrder
real x
real y
endstruct
private function onPointOrder takes nothing returns boolean
/* this function is called when a unit is issued a point order */
/* see the function onInit for the setup */
/* first we declare the instance and create it */
local LastOrder node = LastOrder.create()
/* next we set the member values */
set node.x = GetOrderPointX()
set node.y = GetOrderPointY()
/*
now if we want to associate it with a unit
we can simply save it under a hashtable
*/
call SaveInteger(hash, 0, GetHandleId(GetTriggerUnit()), node)
/* you can save struct instances as integers */
endfunction
private function onInit takes nothing returns nothing
local trigger t = CreateTrigger()
set hash = InitHashtable() /* initialize our hashtable */
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
/* the function above registers when a unit is issued a point order */
call TriggerAddCondition(t, Condition(function onPointOrder))
endfunction
endscope
Now that we have it all saved, how do we retrieve it? That part is pretty simple:
JASS:
local LastOrder temp = LoadInteger(hash, 0, GetHandleId(<unit>))
That is all you need to do! Then you can refer to
temp.x
and
temp.y
freely. When you are done using the instance, you can call the
.destroy()
method if you are not going to use that specific instance at all anymore.
You may be wondering, if we can consider struct instances as integers, can't we just save under the handle ID and use that as the struct instance? Well, sadly the struct instance value must be a number between 0-8191. Of course, you can use subtraction or hash the value into that number, but it gets complex, messy, and it can be dangerous if you have too many handles and aren't careful. That's why a hashtable or unit indexer is the best route.
As an advanced tip -- if you think using
LoadInteger(hash, 0, GetHandleId(<unit>)
is ugly for each time you want to use it, you can take advantage of operators:
JASS:
globals
hashtable hash = InitHashtable()
endglobals
struct LastOrder
real x
real y
static method operator [] takes unit u returns thistype
return LoadInteger(hash, 0, GetHandleId(u))
endmethod
endstruct
If you used the same code above, then instead of:
JASS:
local LastOrder temp = LoadInteger(hash, 0, GetHandleId(GetTriggerUnit()))
You could simply do:
JASS:
local LastOrder temp = LastOrder[GetTriggerUnit()]
Pretty cool, huh? I won't go into too much detail about that, because it requires a bit more practice. It is just to show you what cool things you can do with vJASS.
If you want to know more, you should check out Vexorian's jasshelper manual, look at some tutorials around here, or just go out and start practicing with some code.
It is daunting at first but very powerful.
----
Note: I did not compile or test any of this, so I apologize if there are some syntax errors.