Here's the updated function :) It should now handle all negative numbers and other anomalies correctly
conststringnum="0123456789";//Strips the blank space paddings from either end of a stringstringStrip(strings){intbegin=1;intend=StringLength(s);//Return if no blank spacesif(StringFind(s," ",false)==-1){returns;}//Find startwhile(StringSub(s,begin,begin)==" "){begin+=1;}//Find endwhile(StringSub(s,end,end)==" "){end-=1;}returnStringSub(s,begin,end);}//Checks if the the first non-space character is a numberboolStrIsNum(strings,boolisFixed){inti=1;intlen=StringLength(num);intpos;stringx=Strip(s);stringsub;//Check if isNaNif(x==""||x=="."||x=="-."||x==".-"){returnfalse;}//Check if negativepos=StringFind(x,"-",false);if(pos==1){x=StringReplaceWord(x,"-","",1,false);}elseif(pos!=-1){returnfalse;}//Check if intwhile(i<=len){x=StringReplaceWord(x,StringSub(num,i,i),"",c_stringReplaceAll,false);i+=1;}//Check if floating pointif(isFixed){x=StringReplaceWord(x,".","",1,false);}//If string length 0 after replacing all numbers, it's a numberreturnStringLength(x)==0;}intStr2Int(strings){if(StrIsNum(s,false)){returnStringToInt(s);}return0;}fixedStr2Fix(strings){if(StrIsNum(s,true)){returnStringToFixed(s);}return0;}
Attached my test file as well. Feel free to critique if you feel the function could be further optimized (Esp the strip)
Lol, thanks for the feedback. I'll weed those out when I'm free :) (Probably on the weekend)
However, I believe ".123" is a valid float number. The majority of programming languages recognize it as so (Not sure about Galaxy though). Does it throw errors with StringToFixed?
Note to self "-.", ".-", " -1" may cause complications as well. Have to be very careful with the replacement of blank spaces as "1 0" actually throws an error. Much further testing required. @_@
For floating point numbers you should avoid replacing all "." since this would allow stuff like "12.34.25", instead id suggest just to replace the first .
I noticed this last night when I was trying to sleep lol. Fixed it above. As for negative numbers (which I forgot), with some modifications, I believe it can be built to handle negative numbers (Check if the first character is a '-') Will give it a try when I'm able.
No error, but When I tried another script I was working on, it spammed my debugger with the (value: ) could not be assigned nonsense. Trying to figure out here what exactly the condition is for the error to appear.
Edit:
I found the condition. The debugger will only spam if the StringToInt function is called from a trigger thread. Doesn't matter how many stacks deep. If you're running from the main thread (InitMain), nothing will happen.
Edit #2:
Here's the solution I've come up with, partially inspired by your solution above :)
conststringnum="0123456789";//Checks if the the first non-space character is a numberboolStrIsNum(strings,boolisFixed){stringx=s;intlen=StringLength(num);inti=1;while(i<=len){x=StringReplaceWord(x,StringSub(num,i,i),"",c_stringReplaceAll,false);i+=1;}//Check if floating pointif(isFixed){x=StringReplaceWord(x,".","",1,false);}//If string length 0 after replacing all numbers, it's a numberreturnStringLength(x)==0;}intStr2Int(strings){if(StrIsNum(s,false)){returnStringToInt(s);}return0;}fixedStr2Fix(strings){if(StrIsNum(s,true)){returnStringToFixed(s);}return0;}
I'm not sure how it'll perform with super long strings though.
Could I take a look at your test map please? I don't understand why I'm not getting the error, although you still get it. I'd like to do a comparison between our methods
Did they ninja-fix the StringToInt problem? I was trying to find a better algorithm for your post, but I can't seem to replicate the problem. I faced it too before, but now it's not spitting errors (I'm not complaining).
Note: cout is just a debugger function which prints to screen. i2s is a shortcut for IntToString.
The output I got when I run this was: 0, 0, 1, 1, 0
Edit:
The StringToInt function appears to behave in a manner that it will check for the first non-whitespace character in the string. If it's an integer, it will still cast, else it will return 0. Here's what I came up with to check this condition. Although it won't really matter if they fixed it
The 1.5 patch has brought upon us many useful new features. One of which is the new Data category "User types". I believe these act as an excellent alternative to declaring big records/arrays in script.
This guide is intended as an simple and straightforward guide to User types and it's potential uses. This tutorial aims to make clear how to create custom User Types, and read them with triggers. Once you are able to read them, using them to perform other functions should be pretty straightforward.
This guide however, does not intend cover field modifications or saving to banks. I personally believe these two functions should be pretty straightforward once you've learned how to use the user data functions (Field reading in particular)
Should you prefer a more comprehensive guide on the user of User type's which teaches similar concepts to that covered in this guide, zeldarules28 has done an excellent job right here.
Why User types?
They are comparable to SQL tables (databases), whereby each instance is comparable to the record in the table
You have the freedom to decide what your fields are and how they are initialized
Their instances can be modified in game (If their flag is set)
User types can be directly saved to banks (Save User Type Trigger),
whereby only modified records/fields are saved to optimize bank usage.
Localized initialization of script variables makes it much easier to modify values when balancing your map
Known caveats
New instances cannot be added in game, only pre-declared instances may be added.
Does not allow boolean fields (So we use int 0 and 1 as replacement)
We currently do not have much information on any technical limitations User Types may have.
Reading from User Types may be slower than reading from local variables in Triggers/Script (In theory)
Some potential uses
Save data tables
Hero data tables
Tower defense wave data tables
Dialog item display data tables
Item data tables
There are many other ways User types can be used, these are just a few of them. Play around and innovate for best results.
Additional notes
I do not support the use of XML for the creation of user types here as I feel the GUI simplifies the process very nicely
Thats great! But how to we use them?
For my example, I will be spawning a few units for TD waves.
First we create them with DATA:
1a) Open up your data editor (Hotkey: F7)
1b) Click on Detail view (Hotkey: Ctrl + 2) as it is the easiest to work with (IMHO)
This is an optional step
2) Open up a User Types tab
3) Create your User Type
Right click > Create new User Type. Give it a name that will help you identify it easily. I've chosen 'data_wave'. Do not check 'Defines default values' as this will prevent you from adding new instances. Click Okay!
4) Define your fields
Right click @ fields and add new field. For those of you who are familiar with SQL table creation through a GUI, this process is similar.
Specify the following fields
Id: Self-explanatory, give it an Id that will make it easy for you to identify
Type: The variable type
Value count: The array size (I left it as 1)
Editor column: This is important, it must be a non-zero unique number or you will not be able to see it in the instances table.
Modifiable flag: Flag this if you want to be able to modify this field with script. Not doing so will cause data to ignore attempts by the script to mod these values.
At this point we will consider every other option to have little novelty, thus we will leave them at their default values.
With a few extra fields added:
5a) Optional step: Define default values.
Double click on the defaults (or modify), and specify the value of all your fields. This is not necessary but it helps greatly if you plan to have many instances with identical vales. The screenshots below depict this process.
5b) Add your instances:
Just click the add button. Modifying fields is as simple as double clicking and setting them as seen earlier in the previous step (5a). I've added 3 instances for this example. Remember to specify an Id of your choice. I prefer using integers as it makes it easier to iterate them later with script.
6) Optional step: Give your user type a description, This description will appear when you callback the user type name in the trigger editor.
Then we read/use them with TRIGGERS/SCRIPT:
I'm assuming here you opened up a new map for the tutorial. The steps below refer to the screenshot above.
1) Open up your trigger editor, delete the melee initialization, we won't be needing it.
2) Create a new trigger with an event of your choice. I chose "When spacebar is pressed"
3) Create a few buffer local variables. These should match those in your User Type.
Notes:
The use of local variables here is to buffer our data and improve script readability.
One of the limitations discovered with the User Type functions here is that they did not allow instance ID's to be called directly via a number (i_Wave), thus I was forced to use custom script to set it. (Please refer to the example if this is not clear.)
4) Perform your actions:
I've chosen to iterate through the User Types and spawn the monsters whenever the event fires. This process is done by simply buffering the fields of the current instance into the buffer local variables and using them to perform actions. I've also added a condition which causes actions to be skipped if they are no longer any instances to read.
5) Run the script!
You can find my example attached. Just press spacebar and it will spawn the units.
Conclusion:
This is not the conclusion you are looking for. Happy Mapping!
FAQ's
Any plans for a modification or banking tutorial? None at this point of time, as I do not have enough experience with banks.
Modifying fields is very straightforward though, Just use "xxxxx"
Feel free to ask any questions. I'll update this section if anything trivial comes up.
I recall there is a limitation with banks. They don't commit while they are in 'write' mode, and once you close 'write' mode and reopen them for rewriting, any new data that is written doesn't get properly saved, sometimes resulting in blank values in the bank. This was discovered through a series of quick tests about half a year ago. It could be fixed by now.
My workaround to this, was to use instance Id's that are 0 indexed integers in the form of a string, and iterate the instances by the id, rather than the index. I then add an extra name field to serve as the true identifier
Edit: I believe the 0 index is reserved for the default instance
I suggest trying out user types data. Since the data is one time use, just read them into local variables with your function that's displaying your upgrades. Once the function completes its run, the locals will clear and you won't have a useless global sitting in your memory
0
@Kueken531: Go
THIS, is freaking awesome. I am now compelled to learn how to play with actors as well :D
On a sidenote: The music on the first post video is very.. unique o_o
Edit: Somehow, I feel like this opens up the door to implementing QWOP in the sc2 engine
0
@Mozared: Go
Ditto. Referring to SC2Ranks here
0
@Bibendus: Go
I'm experiencing the same problem :/
0
@Mille25: Go
Here's the updated function :) It should now handle all negative numbers and other anomalies correctly
Attached my test file as well. Feel free to critique if you feel the function could be further optimized (Esp the strip)
0
@Mille25: Go
Lol, thanks for the feedback. I'll weed those out when I'm free :) (Probably on the weekend)
However, I believe ".123" is a valid float number. The majority of programming languages recognize it as so (Not sure about Galaxy though). Does it throw errors with StringToFixed?
Note to self "-.", ".-", " -1" may cause complications as well. Have to be very careful with the replacement of blank spaces as "1 0" actually throws an error. Much further testing required. @_@
0
You're welcome
I suppose I could run some time tests for this one to evaluate it's performance. Do you think a 1000 char string would suffice?
I noticed this last night when I was trying to sleep lol. Fixed it above. As for negative numbers (which I forgot), with some modifications, I believe it can be built to handle negative numbers (Check if the first character is a '-') Will give it a try when I'm able.
0
@Mille25: Go
Hm.. I tried your script, and here's my output
No error, but When I tried another script I was working on, it spammed my debugger with the (value: ) could not be assigned nonsense. Trying to figure out here what exactly the condition is for the error to appear.
Edit: I found the condition. The debugger will only spam if the StringToInt function is called from a trigger thread. Doesn't matter how many stacks deep. If you're running from the main thread (InitMain), nothing will happen.
Edit #2:
Here's the solution I've come up with, partially inspired by your solution above :)
I'm not sure how it'll perform with super long strings though.
0
Could I take a look at your test map please? I don't understand why I'm not getting the error, although you still get it. I'd like to do a comparison between our methods
0
Did they ninja-fix the StringToInt problem? I was trying to find a better algorithm for your post, but I can't seem to replicate the problem. I faced it too before, but now it's not spitting errors (I'm not complaining).
Here's my script:
Note: cout is just a debugger function which prints to screen. i2s is a shortcut for IntToString.
The output I got when I run this was: 0, 0, 1, 1, 0
Edit:
The StringToInt function appears to behave in a manner that it will check for the first non-whitespace character in the string. If it's an integer, it will still cast, else it will return 0. Here's what I came up with to check this condition. Although it won't really matter if they fixed it
0
Introduction
The 1.5 patch has brought upon us many useful new features. One of which is the new Data category "User types". I believe these act as an excellent alternative to declaring big records/arrays in script.
This guide is intended as an simple and straightforward guide to User types and it's potential uses. This tutorial aims to make clear how to create custom User Types, and read them with triggers. Once you are able to read them, using them to perform other functions should be pretty straightforward.
This guide however, does not intend cover field modifications or saving to banks. I personally believe these two functions should be pretty straightforward once you've learned how to use the user data functions (Field reading in particular)
Should you prefer a more comprehensive guide on the user of User type's which teaches similar concepts to that covered in this guide, zeldarules28 has done an excellent job right here.
Why User types?
Known caveats
Some potential uses
There are many other ways User types can be used, these are just a few of them. Play around and innovate for best results.
Additional notes
Thats great! But how to we use them?
For my example, I will be spawning a few units for TD waves.
First we create them with DATA:
1a) Open up your data editor (Hotkey: F7)
1b) Click on Detail view (Hotkey: Ctrl + 2) as it is the easiest to work with (IMHO)
2) Open up a User Types tab
3) Create your User Type Right click > Create new User Type. Give it a name that will help you identify it easily. I've chosen 'data_wave'. Do not check 'Defines default values' as this will prevent you from adding new instances. Click Okay!
4) Define your fields Right click @ fields and add new field. For those of you who are familiar with SQL table creation through a GUI, this process is similar.
Specify the following fields
At this point we will consider every other option to have little novelty, thus we will leave them at their default values.
With a few extra fields added:
5a) Optional step: Define default values. Double click on the defaults (or modify), and specify the value of all your fields. This is not necessary but it helps greatly if you plan to have many instances with identical vales. The screenshots below depict this process.
5b) Add your instances: Just click the add button. Modifying fields is as simple as double clicking and setting them as seen earlier in the previous step (5a). I've added 3 instances for this example. Remember to specify an Id of your choice. I prefer using integers as it makes it easier to iterate them later with script.
6) Optional step: Give your user type a description, This description will appear when you callback the user type name in the trigger editor.
Then we read/use them with TRIGGERS/SCRIPT:
1) Open up your trigger editor, delete the melee initialization, we won't be needing it.
2) Create a new trigger with an event of your choice. I chose "When spacebar is pressed"
3) Create a few buffer local variables. These should match those in your User Type.
Notes:
4) Perform your actions:
I've chosen to iterate through the User Types and spawn the monsters whenever the event fires. This process is done by simply buffering the fields of the current instance into the buffer local variables and using them to perform actions. I've also added a condition which causes actions to be skipped if they are no longer any instances to read.
5) Run the script!
You can find my example attached. Just press spacebar and it will spawn the units.
Conclusion:
This is not the conclusion you are looking for. Happy Mapping!
FAQ's
None at this point of time, as I do not have enough experience with banks. Modifying fields is very straightforward though, Just use "xxxxx"
Feel free to ask any questions. I'll update this section if anything trivial comes up.
0
I recall there is a limitation with banks. They don't commit while they are in 'write' mode, and once you close 'write' mode and reopen them for rewriting, any new data that is written doesn't get properly saved, sometimes resulting in blank values in the bank. This was discovered through a series of quick tests about half a year ago. It could be fixed by now.
0
@DieHappy1234: Go
http://www.sc2mapster.com/forums/development/data/40511-new-data-types-in-patch-1-5/?post=20
0
@Tommerbob: Go
Awesome sauce. Thanks for the feedback :)
0
@alderis: Go
You're welcome :)
My workaround to this, was to use instance Id's that are 0 indexed integers in the form of a string, and iterate the instances by the id, rather than the index. I then add an extra name field to serve as the true identifier
Edit: I believe the 0 index is reserved for the default instance
0
I suggest trying out user types data. Since the data is one time use, just read them into local variables with your function that's displaying your upgrades. Once the function completes its run, the locals will clear and you won't have a useless global sitting in your memory