Have an interest in art design, but unsure of what sort of map to make, or not really thrilled about the inner workings of gameplay coding? The map team I'm on is looking for an artist with an interest in user interface, terrain, skin, or model design. You can download and try out a development version of the map on the project page here. You can have the freedom to do what you enjoy - creative artwork - without being bogged down by all the other elements that go into a map.
If you might be interested, just send me a private message.
Passing multiple integers to a function is something I needed to do, so came up with the simple library in the attached map in a few minutes' time.
Technically, the editor and galaxy language don't allow us to pass arrays to functions. Strings are arrays however, and as such can substitute as arrays. We have very limited functionality dealing with strings, but basic storage can be done easily, if inefficiently.
If we had more powerful tools, a better solution could be created... we could even create our own dynamic allocation system using strings as a memory space. There doesn't appear to be a way to access characters of a string by index however, nor are there atoi or itoa functions, nor even a logarithm function to easily get the position of values in an integer, and implicit casting is disallowed. I was attempting to create a system where the integers would be converted into byte values with an ascii character representation, but got frustrated with the roadblocks of the galaxy language, so stuck with this. The list isn't something I use often or store large values in, so simply converting integers to strings is good enough for my purposes.
The functions here can also be easily extended to use floating point values or other numbers as well, if you need to do that. Any sort of lists involving spaces (such as unit names) will need a different solution for storage however.
I've also included some examples in the map using the functions.
Note: The import/export library functions of the editor are broken (hint and grammar text erase when you use import), so follow the method detailed in this post: Library Import/Export Bug
When you load the map in the editor, does the editor say there's a problem reading map info? If so, likely this bug here. If you're not getting that map info message, then I dunno.
Yes, exactly that. I looked through all their preprocessor usage in the libraries, but wasn't able to find anything that might be useful. They might have simply never implemented parsing single quotes as force string or escape characters because they didn't anticipate people using function calls in macros...
I noticed Blizzard assigned parenthesis a higher precedence than the double quote character " for their Galaxy Editor trigger parser (the parenthesis are evaluated first, even if they're in a string). How can I include a parenthesis in a preprocessor directive string?
I tried the standard escape characters \ and /, and the "force string and don't process" operator (single quote) instead of double quotes. I even tried backquotes, none of it worked, the parenthesis were always processed first.
I suppose this is a project so I'm posting here, though it's a library, not a map. Flags are lists of properties you can check-mark, like the "flags" entry of a units in the data editor. The operators are missing from the editor, and are necessary to use bit flag presets, so I created a library of basic functions:
Variable - Modify Flags (set, clear, shift)
General - For Each Flag
General - For Each Flag by Index
General - For Each Flag Matching Conditions
General - For Each Flag Matching Conditions by Index
Conversions - Convert Preset to Integer
Index - Index of Single Flag
Logic - Flags Match Filters (any, all)
Logic - Flags And/Or
Logic - Flags Exclusive Or
Logic - Flags Not
All these but "index of bit flag" internally use a concept called macros, so there's no overhead compared to scripting it directly1. I also included an example bit flag preset variable, and functions useful to work around the editor bug with assigning flag values. If you're using one specific preset a lot, you can set the "number of flags" in the For Each Flag functions to default to some function or global where you store the number of flags for your preset.
Note: The import/export library functions of the editor are broken (hint and grammar text erase when you use import), so follow the method detailed in this post: Library Import/Export Bug
If you have any questions or problems, just ask.
Update:
I've updated the functions using new discoveries of how Blizzard does their macros. I combined several of the functions. Set, clear, shift left, and shift right are now all in the "modify flags" function, for example. I've also categorized the functions with similar functions. All the 'for each' loops are now in the General category with other loops.
1 With macros, the function calls are replaced by the actual operations when compiled, and the functions vanish entirely - they aren't even defined. You can see this by compiling your map in the script test window. If we had a log<sub>2</sub>x function in galaxy (or any logarithm at all), could make "index of single flag" a macro too.
I think it's the power splat that shows up (power is the actor, and it's categorized as a splat). The unit in particular is a deployed warp prism, and if I add the no draw flag, the power grid also disappears. My attempts to use the power splat directly have been unsuccessful.
The invisible unit model is excellent, thank you for mentioning that! Do you know any way to selectively apply it to specific units? I attempted to make the actor itself have the invisible model and then attach the visible one to origin, overhead, and other points using AttachModelToUnit, but that didn't work.
The purpose of this whole endeavor is to allow multiple people to use the same unit, and since that's likely not possible, simulate it with the method described in my post above. It works fine for various other buildings I use this for, but this particular unit has a power grid I want to remain visible.
The only thing i can mention is that alot context switches (locks) are expensive. so you need wisely to design your threading. otherwise you can even get lower with performance. etc. etc. so actually it's a complex task. but yes it's cool what gaylaxy allows to thread your script...
Good point. That's why I made the wait between checks have a slight random range to alleviate potential performance hits with many simultaneous accesses; same principal as collision avoidance in ethernet. The frequency and spread of the checks can be varied to balance performance with responsiveness.
The separate timer and critical section aren't even necessary for this situation, but I included them to give an example of synchronization. It'd be more efficient (and unit responses would look more realistic) for all the threads to simply wait a random 5-10 seconds between processing cycles.
I was asked a question in PM's, and with the sender's permission I'm reposting my response here.
Quote from tardcartrider:
Saw your post on multithreading & AI. First, great post I certainly appreciate it and I'm sure many others do as well. I am very interested in learning more about how to write an AI - specifically unit behaviors for a map that I am working on. Nothing too complicated (yet) I'd like to start with some simple actions like having a high templar cast Psi Storm when he encounters a group of enemies and then retreat during cooldown. I can pick up on a lot of the framework from your post, but obviously not enough to accomplish what I am trying to achieve.
I am sure you are busy with your own projects (if you're looking for more let me know =P ), so I would like to know if you know of any other resources that would help me to learn this. Thanks again for the post you made and I would appreciate any other information you can point me in the direction of,
TC
Well, here's what I'd do off the top of my head. It might not be the most efficient method since my experience is with other things, not really any in-depth AI, but this is some basics that might help.
A global preset (data > new preset) like this:
ActionValueType:IntegerValuesAdvancingRetreating
In the AI action, create local variables like these:
Current Action <Action>
Target <Point array[2]>
Nearby Units <Unit Group>
Then in the "core AI" section indicated in the tutorial, add actions like these:
switch (Current Action)
if (Advancing)
set Nearby Units = all enemy units within (sight range of templar)
if (number of units in Nearby Units > somenumber) and (templar has enough energy)
cast psi storm on (random unit from Nearby Units)
set Current Action = Retreating
set Target[Retreating] = pick some point, could be directly away from Target[Advancing]. To calculate distance, you can get the cooldown of psi storm and movement speed of the templar, and time * speed = distance. I think the Data Table functions might be able to do it directly, or you could store them in variables.
wait 2 seconds or so for psi storm to cast
order the templar to move to Target[Retreating]
else
order templar to move to Target[Advancing]
if (Retreating)
if (distance from position of unit to Target <= some range)
set Current Action = Advancing
order templar to move to Target[Advancing]
else
order templar to move to Target[Retreating]
You'll also want to put your stuff in there telling the unit what point it should be advancing to and such, check if its psi storm target is visible, maybe even loop through all NearbyUnits to check if a certain number of units are around that picked unit, to make sure Psi Storm would be effective there. There's a "center of unit group" function that could be useful for that. Depending on your map terrain, you might also need to be careful with picking the Target[Retreating] so your unit doesn't try to go up cliffs or somewhere else inaccessible. There might be a way to do some of this with orders directly, but after looking into that a bit it seemed difficult to set up, so I went with simple presets.
You can send your unit AI instructions from outside the function by using custom values on the unit (set unit custom value action). I'd create another preset to store the indexes of various things you might want to use to control the unit, like this:
Then set those custom values from outside the function (set custom unit value "Advance Point X" to somevalue) and read them from inside the function (set (X of point Target[Advancing]) = custom unit value "Advance Point X").
I don't really know where to find a general guide to AI, but you can probably locate a lot of info with google searches. Sorry I can't help you more, my knowledge is mostly with other things, not AI specifically.
Do you mind if I copy this into the thread for others with similar questions?
The specific combination of variables in the attached map below causes the game to freeze, then crash, immediately after the loading screen. If a single one of the variables are removed (or the variables are used on a different map!) the freeze does not occur. It's some combination of events here that's causing a game crash bug to occur.
There is nothing else in the trigger module, and the script generated by the trigger editor can be seen below. No custom script is used.
The names don't matter, I changed them to these generic names for demonstration purposes. Needless to say, this took hours to narrow down out of all the variables and triggers I had in my map. Easily the most bizzare bug I've seen so far!
//==================================================================================================// // Generated Map Script// // Name: Storm the Base// Author: Zerahan & Thalassicus// //==================================================================================================include"TriggerLibs/NativeLib"//--------------------------------------------------------------------------------------------------// Library Initialization//--------------------------------------------------------------------------------------------------voidInitLibs(){libNtve_InitLib();}//--------------------------------------------------------------------------------------------------// Global Structures//--------------------------------------------------------------------------------------------------structgs_Record1Type{unitgrouplv_unitGroup;};structgs_Record2Type{timerlv_timer;unitgroup[21]lv_unitGroup;gs_Record1Type[41]lv_record1;};structgs_Record3Type{gs_Record2Type[21]lv_record2;};//--------------------------------------------------------------------------------------------------// Global Variables//--------------------------------------------------------------------------------------------------playergroup[17]gv_playerGroup;gs_Record2Type[22]gv_record2;gs_Record3Type[22]gv_record3;timer[21]gv_timer;unitgroup[21][21]gv_unitGroup;voidInitGlobals(){intinit_i;intinit_j;intinit_i1;intinit_i2;init_i=0;while(init_i<=16){gv_playerGroup[init_i]=PlayerGroupEmpty();init_i=init_i+1;}init_i=0;while(init_i<=21){gv_record2[init_i].lv_timer=TimerCreate();init_i1=0;while(init_i1<=20){gv_record2[init_i].lv_unitGroup[init_i1]=UnitGroupEmpty();init_i1=init_i1+1;}init_i1=0;while(init_i1<=40){gv_record2[init_i].lv_record1[init_i1].lv_unitGroup=UnitGroupEmpty();init_i1=init_i1+1;}init_i=init_i+1;}init_i=0;while(init_i<=21){init_i1=0;while(init_i1<=20){gv_record3[init_i].lv_record2[init_i1].lv_timer=TimerCreate();init_i2=0;while(init_i2<=20){gv_record3[init_i].lv_record2[init_i1].lv_unitGroup[init_i2]=UnitGroupEmpty();init_i2=init_i2+1;}init_i2=0;while(init_i2<=40){gv_record3[init_i].lv_record2[init_i1].lv_record1[init_i2].lv_unitGroup=UnitGroupEmpty();init_i2=init_i2+1;}init_i1=init_i1+1;}init_i=init_i+1;}init_i=0;while(init_i<=20){gv_timer[init_i]=TimerCreate();init_i=init_i+1;}init_i=0;while(init_i<=20){init_j=0;while(init_j<=20){gv_unitGroup[init_i][init_j]=UnitGroupEmpty();init_j=init_j+1;}init_i=init_i+1;}}//--------------------------------------------------------------------------------------------------// Map Initialization//--------------------------------------------------------------------------------------------------voidInitMap(){InitLibs();InitGlobals();}
Good point UmbraLamina and thank you, that's something I forgot to mention. If there's a need for more than 1 type of lock in a thread, it's a good idea to research advanced topics in multithreading - can check the wiki articles and other resources for starters:
If a thread only requests 1 type of lock (like the examples in the tutorial), there's no worry of deadlocks, since circular waits like described above won't occur. Requesting and releasing the same lock several times in a thread is ok too.
I'd like to also get rid of some other error messages (like 'need more supply')... it's really unfortunate all validator errors appears to be hardcoded. I haven't found anything that might be able to change them in weeks now.
Well, what I have is 1 visible unit, and on top of its position, 1 invisible unit of the same type for each player. The visible one selects the appropriate invisible one. Ideally I'd like to do it with just one unit/actor/etc... so as to not spend two hours duplicating a half dozen units and trying to ensure all the actors are appropriately linked.
0
Greetings!
Have an interest in art design, but unsure of what sort of map to make, or not really thrilled about the inner workings of gameplay coding? The map team I'm on is looking for an artist with an interest in user interface, terrain, skin, or model design. You can download and try out a development version of the map on the project page here. You can have the freedom to do what you enjoy - creative artwork - without being bogged down by all the other elements that go into a map.
If you might be interested, just send me a private message.
0
If you export a library from a map, then import it to a new map, all the grammar and hint text is erased.
Workaround
This method also ensures any "Labels" are preserved.
0
Passing multiple integers to a function is something I needed to do, so came up with the simple library in the attached map in a few minutes' time.
Technically, the editor and galaxy language don't allow us to pass arrays to functions. Strings are arrays however, and as such can substitute as arrays. We have very limited functionality dealing with strings, but basic storage can be done easily, if inefficiently.
If we had more powerful tools, a better solution could be created... we could even create our own dynamic allocation system using strings as a memory space. There doesn't appear to be a way to access characters of a string by index however, nor are there atoi or itoa functions, nor even a logarithm function to easily get the position of values in an integer, and implicit casting is disallowed. I was attempting to create a system where the integers would be converted into byte values with an ascii character representation, but got frustrated with the roadblocks of the galaxy language, so stuck with this. The list isn't something I use often or store large values in, so simply converting integers to strings is good enough for my purposes.
The functions here can also be easily extended to use floating point values or other numbers as well, if you need to do that. Any sort of lists involving spaces (such as unit names) will need a different solution for storage however.
I've also included some examples in the map using the functions.
Note: The import/export library functions of the editor are broken (hint and grammar text erase when you use import), so follow the method detailed in this post: Library Import/Export Bug
Hope this is useful for you.
0
Is there any way to use the char data type?
0
@Fullachain: Go
When you load the map in the editor, does the editor say there's a problem reading map info? If so, likely this bug here. If you're not getting that map info message, then I dunno.
0
@xhatix: Go
Yes, exactly that. I looked through all their preprocessor usage in the libraries, but wasn't able to find anything that might be useful. They might have simply never implemented parsing single quotes as force string or escape characters because they didn't anticipate people using function calls in macros...
I'm attempting to do something similar:
More complex than that, but it's the basic idea. If backslash is used:
After the preprocessor runs, the result of passing 0, 1, 2 is:
There could very well be some non-standard escape character or method we just don't know about due to it not being used in the game's libraries . . .
0
I noticed Blizzard assigned parenthesis a higher precedence than the double quote character " for their Galaxy Editor trigger parser (the parenthesis are evaluated first, even if they're in a string). How can I include a parenthesis in a preprocessor directive string?
I tried the standard escape characters \ and /, and the "force string and don't process" operator (single quote) instead of double quotes. I even tried backquotes, none of it worked, the parenthesis were always processed first.
0
Download
I suppose this is a project so I'm posting here, though it's a library, not a map. Flags are lists of properties you can check-mark, like the "flags" entry of a units in the data editor. The operators are missing from the editor, and are necessary to use bit flag presets, so I created a library of basic functions:
All these but "index of bit flag" internally use a concept called macros, so there's no overhead compared to scripting it directly1. I also included an example bit flag preset variable, and functions useful to work around the editor bug with assigning flag values. If you're using one specific preset a lot, you can set the "number of flags" in the For Each Flag functions to default to some function or global where you store the number of flags for your preset.
Note: The import/export library functions of the editor are broken (hint and grammar text erase when you use import), so follow the method detailed in this post: Library Import/Export Bug
If you have any questions or problems, just ask.
Update:
I've updated the functions using new discoveries of how Blizzard does their macros. I combined several of the functions. Set, clear, shift left, and shift right are now all in the "modify flags" function, for example. I've also categorized the functions with similar functions. All the 'for each' loops are now in the General category with other loops.
1 With macros, the function calls are replaced by the actual operations when compiled, and the functions vanish entirely - they aren't even defined. You can see this by compiling your map in the script test window. If we had a log<sub>2</sub>x function in galaxy (or any logarithm at all), could make "index of single flag" a macro too.
0
Action definitions with custom script option enabled are bugged.
Regardless of the grammar text or custom script in the action, all that shows in the UI is:
Workaround
Use the sub-functions option instead of the custom script option, and it works correctly.
0
@s3rius: Go
I think it's the power splat that shows up (power is the actor, and it's categorized as a splat). The unit in particular is a deployed warp prism, and if I add the no draw flag, the power grid also disappears. My attempts to use the power splat directly have been unsuccessful.
The invisible unit model is excellent, thank you for mentioning that! Do you know any way to selectively apply it to specific units? I attempted to make the actor itself have the invisible model and then attach the visible one to origin, overhead, and other points using AttachModelToUnit, but that didn't work.
The purpose of this whole endeavor is to allow multiple people to use the same unit, and since that's likely not possible, simulate it with the method described in my post above. It works fine for various other buildings I use this for, but this particular unit has a power grid I want to remain visible.
0
Good point. That's why I made the wait between checks have a slight random range to alleviate potential performance hits with many simultaneous accesses; same principal as collision avoidance in ethernet. The frequency and spread of the checks can be varied to balance performance with responsiveness.
The separate timer and critical section aren't even necessary for this situation, but I included them to give an example of synchronization. It'd be more efficient (and unit responses would look more realistic) for all the threads to simply wait a random 5-10 seconds between processing cycles.
I was asked a question in PM's, and with the sender's permission I'm reposting my response here.
Well, here's what I'd do off the top of my head. It might not be the most efficient method since my experience is with other things, not really any in-depth AI, but this is some basics that might help.
A global preset (data > new preset) like this:
In the AI action, create local variables like these:
Then in the "core AI" section indicated in the tutorial, add actions like these:
switch (Current Action)
You'll also want to put your stuff in there telling the unit what point it should be advancing to and such, check if its psi storm target is visible, maybe even loop through all NearbyUnits to check if a certain number of units are around that picked unit, to make sure Psi Storm would be effective there. There's a "center of unit group" function that could be useful for that. Depending on your map terrain, you might also need to be careful with picking the Target[Retreating] so your unit doesn't try to go up cliffs or somewhere else inaccessible. There might be a way to do some of this with orders directly, but after looking into that a bit it seemed difficult to set up, so I went with simple presets.
You can send your unit AI instructions from outside the function by using custom values on the unit (set unit custom value action). I'd create another preset to store the indexes of various things you might want to use to control the unit, like this:
Then set those custom values from outside the function (set custom unit value "Advance Point X" to somevalue) and read them from inside the function (set (X of point Target[Advancing]) = custom unit value "Advance Point X").
I don't really know where to find a general guide to AI, but you can probably locate a lot of info with google searches. Sorry I can't help you more, my knowledge is mostly with other things, not AI specifically.
Do you mind if I copy this into the thread for others with similar questions?
0
The specific combination of variables in the attached map below causes the game to freeze, then crash, immediately after the loading screen. If a single one of the variables are removed (or the variables are used on a different map!) the freeze does not occur. It's some combination of events here that's causing a game crash bug to occur.
There is nothing else in the trigger module, and the script generated by the trigger editor can be seen below. No custom script is used.
The names don't matter, I changed them to these generic names for demonstration purposes. Needless to say, this took hours to narrow down out of all the variables and triggers I had in my map. Easily the most bizzare bug I've seen so far!
Attachments
0
@UmbraLamina: Go
Good point UmbraLamina and thank you, that's something I forgot to mention. If there's a need for more than 1 type of lock in a thread, it's a good idea to research advanced topics in multithreading - can check the wiki articles and other resources for starters:
http://en.wikipedia.org/wiki/Multithreading
http://en.wikipedia.org/wiki/Deadlock
If a thread only requests 1 type of lock (like the examples in the tutorial), there's no worry of deadlocks, since circular waits like described above won't occur. Requesting and releasing the same lock several times in a thread is ok too.
0
I'd like to also get rid of some other error messages (like 'need more supply')... it's really unfortunate all validator errors appears to be hardcoded. I haven't found anything that might be able to change them in weeks now.
0
@xenrathe: Go
Ahh.
Well, what I have is 1 visible unit, and on top of its position, 1 invisible unit of the same type for each player. The visible one selects the appropriate invisible one. Ideally I'd like to do it with just one unit/actor/etc... so as to not spend two hours duplicating a half dozen units and trying to ensure all the actors are appropriately linked.