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

[JASS] Array Question

Status
Not open for further replies.
Level 4
Joined
Nov 25, 2008
Messages
76
I read the Array tutorial but there are a couple of things I don't understand.

For instance, is it possible to dynamically create an array and fill it in game? In all the examples I have seen, you manually define the objects inside the array when you create it. However, in my map I require the game to store x amounts of data in 1 array, as the game goes on. Can this be done?

Also, is there a function that gets the size (or length) of an array so I can add a variable to the end of the array? [Like Getsize(A1) ] I know I'm talking more about lists here than an array but is this possible (other than defining another global integer variable as the "size" of the array)?

What I mean by size is how many variables are currently stored in the array, not the maximum value that can be put in.
 
Last edited:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
Arrays in WC3 are hard coded to a max of 8192 indexes ( 0 - 8191). No matter how you difine the array this limate will apply even if you only use 10 or if you use all indexes.

You can not treat arrays as objects but you can have local arrays, again the siaze ov 8192 indexes applies to them.
The WC3 engine automatically enlarges the arrays as needed (as more indexes are used) so they can grow as you use them.
The "limate" in GUI is fake and is purly how many are predifined. You can exceed that limate with no problems as long as you are under the index 8192.
 
Level 4
Joined
Nov 25, 2008
Messages
76
So the solution here is to create a counter as a global variable, which will contain the number of things I have already stored in the array?

Basically what I want to do is a system that memorizes the locations of buildings built by the player as he goes on, which means the array rapidly gets updated. The problem is, how can I update the array to tell it to only fill the empty indexes rather than the indexes I have already used? The only thing that comes to my mind is by using an external counter but surely there must be another way than to use system resources to create another variable.
 
Level 4
Joined
Nov 23, 2007
Messages
113
If I understand your issue correctly, you want to have an array for each player that keeps track of the location he has built each building. Not sure if you need to record both the building AND its location, but assuming you do, that means you need to store 2 different types of data (unit and location). This means 2 arrays.

JASS:
unit array PlayerBuildings
location array PlayerBuildingLocs
It would be a lot of code and messy to create 12 arrays (one for each player) so you are best to create a "fake structure" (unfortunately, they all have to be the same data type) assuming you are not using vjass.

In situations like this (without vjass) you can create a fake structure by using the same array for all 12 players then use an offset into that array for each player. Since the array size is 8192, divided by 12 roughly gives you 682 elements of storage for each player. Since I doubt the player would be creating 682 buildings, this should be plenty of space.

You will need an array to store the number of buildings each player has already created in order to use it as an index.

JASS:
integer array PlayerBuildingsCount

Initialize the first 12 elements to 0

When a player builds a building you can save it into the arrays something like this (playerId is a zero-based index):

JASS:
function StorePlayerBuildingLoc takes integer playerId, unit building, location buildingLoc returns nothing

	// Initialize offset to player data in fake structure
	local integer offsetToPlayerData = (playerId * 682) 

	// store building data for player for building created at location
	set PlayerBuildings[offsetToPlayerData + PlayerBuildingsCount[playerId]] = building
	set PlayerBuildingLocs[offsetToPlayerData + PlayerBuildingsCount[playerId]] = buildingLoc
	
	// Increment the number of buildings the player has built
	set PlayerBuildingsCount[playerId] = PlayerBuildingsCount[playerId] + 1

endfunction

Of course, prior to calling this you would need to determine it is a building being built etc.

hope this helps and that I understand your goal correctly.
 
Level 4
Joined
Nov 25, 2008
Messages
76
That was excellent, just what I needed. Thank you very much. I'm also using Jass newgen so (I think) I'm using vjass. You said this is the way to make it without vjass, is it easier on vjass? If so, could you please explain?

This was very enlightening, thank you again...
 
Level 4
Joined
Nov 23, 2007
Messages
113
Arrays have to be of the same type so a 2/3d array here isn't going to solve much.

However, since vjass structs allow different data types, a structure array would be a better solution. I haven't looked at vjass much (too lazy to install it) but from glancing at its syntax, I assume it is capable of an array of type struct.

So... I'm not very familiar with it's syntax (so someone feel free to correct it) but I assume it would go something like this:

JASS:
struct SBuildingData
unit Building
location Loc
endstruct

// create a type of SBuildingData
type TBuildingData extends SBuildingData


struct SPlayerBuildingData
TBuildingData BuildingData[100]
integer BuildingCount
endstruct

Then somewhere in your code, create an array of type SPlayerBuildingData[12] (which contains one element for each player).

Then you can just use playerId to index the array of building data and the structure elements to access each players building data.

Of course, you could then add methods to the struct to handle adding of the building data (unit and loc) and incrementing of the BuildingCount etc.

Sorry, I know it probably isn't the right syntax for vjass but you can look that up. It would be easier to demonstrate it in C++ but that might confuse you even more.

Just think of the above as pseudocode ;)
 
Level 4
Joined
Nov 23, 2007
Messages
113
I had a look around regarding structures and found that they can be declared like this:

struct mystruct [100]


However, I have a feeling that this method would simply restrict the number of instances a structure of that type could be declared, and not declare it as an array.

It would be nice if someone in-the-know could demonstrate how (and if) a structure is defined as an array, and the syntax used to access the elements of it (I'm assuming mystruct[index].member but confirmation would be good).

If you get no reply, perhaps just try it and see what compiler errors (if any) you get, and those errors may actually indicate whether structs can be arrays. For example, you could also try declaring the SPlayerBuildingData as a new type, then somewhere in your code declare the following to see if any errors are produced:

JASS:
type TPlayerBuildingData extends SPlayerBuildingData
TPlayerBuildingData PlayerBuildingData[12]

Then try to iterate through each array element and access the members with something like:

JASS:
local integer i = 0
loop
set PlayerBuildingData[i].BuildingCount = i
exitwhen i >= 12
endloop

See if that produces any compiler errors.

Sorry I can't be of more help. I suppose one day when I get the time I should install vjass and play around with it.
 
Level 4
Joined
Nov 25, 2008
Messages
76
Sorry for double post, but I still cannot achieve this and help is really appreciated.Let me break down the problem to it's basics:

I'm trying to have a global array whose members are structs of type A. What mannoroth have suggested did not seem to work, as it limited the number of structs to be defined rather than defining a struct as an array.

If this is not possible, then I could work with global structs that I can access with more than one functions and store it. Could anyone point me to the right direction?
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
Don't really understand what you mean...

Are you trying to make an array inside the struct identifier, like:

JASS:
struct MyStruct
    integer array ints [12]
endstruct

// in a function:
local MyStruct ms = GetUnitUserData(u) // or wherever you store struct data
set ms.ints[0] = 5
set ms.ints[11] = 15

Or are you trying to make an array of type MyStruct?

JASS:
local MyStruct array ms
ms[0] = MyStruct.create()
ms[1] = MyStruct.create()
etc.

Or are you trying to make a global array of MyStruct?
JASS:
globals
    MyStruct array ms
endglobals

Or are you trying to define some custom array type which can be allocated manually during the game with a define size, like:
JASS:
    local MyStruct array ms [12]
    set ms[11] = MyStruct.create()

The last one isn't possible, unless you make your own array type through jass (I've done so, it seems to work)
 
Level 4
Joined
Nov 25, 2008
Messages
76
Don't really understand what you mean...


Or are you trying to make an array of type MyStruct?

JASS:
local MyStruct array ms
ms[0] = MyStruct.create()
ms[1] = MyStruct.create()
etc.

Or are you trying to make a global array of MyStruct?
JASS:
globals
    MyStruct array ms
endglobals

Both actually... Does defining a struct inside globals make it global? Also is the second one an array of MyStruct? Like, each member of the array being MyStruct?

I have a Struct named Guardpost which should be created and put into a global array. So the array's all members should be Guardpost structures, but I should be able to say, reach the first structure and change its variables with functions (hence why the global part).
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
A struct is always global. Well, at least, in the vjass implementation of a struct it is always global.

Both of the jass scripts you've quoted me on are arrays of MyStruct, as in: each variable in the array being of type "MyStruct". In the first case, it's a local array. In the second case it's a global array. But the actual GuardPost variables are always global, whether or not you assign local or global variables to them.

Compare it to unit variables:
JASS:
set global_unit_var = CreateUnit(...)
// or
local unit local_unit_var = CreateUnit(...)
In both cases the actual unit is still global (unless you use the RemoveUnit() function, they will STILL be on your map), whether or not the unit_var itself is global or local.

If you want a global array of GuardPost's, then you should go for:
JASS:
globals
    GuardPost array gp
endglobals
so whenever you write "gp" anywhere in your code, it'll refer to the GuardPost array.

I do think there are some ... "problems" with arrayed structs. Well, I can't really call them problems (there are no bugs, it's just syntactically "strange"), but still:
If you want to do something to a struct in an array, you'll have some tiny "problems indeed". I'm talking of this:
JASS:
globals
    GuardPost array gp
endglobals

// in a function:
set gp[0].member = 5
// this will not compile, because for some reason it does not accept a period (.) after square brackets ( [] ). Instead, do this:

// in a function:
local GuardPost outpost = gp[0]
set outpost.member = 5 // this will work.
 
Level 4
Joined
Nov 25, 2008
Messages
76
That was great, thank you! I think I tried to bite more than I can chew at this stage, but thanks to you, I should be able to get that to work.
 
Status
Not open for further replies.
Top