Ok so this is gonna be my first attempt to learn scripting. First section is going to be theory on the functions I need to create. As I learn scripting I will update with actual code.
Theories
I myself like to use key listeners that call other functions to handle the heavy lifting I will be sticking with that theme
Every player will have thier own function for every keyboard Input
Initial scripts to get up and moving
Not quite sure atm on what is required to start running scripts... ( gonna go back and look at a bunch of s3rius's examples....
Player Inputs
Global array for player inputs
PlayerInputs[0-15,0-9] (type: boolean) (the point of this is to track keys being held down)
"True" indicates that the key is in a "down" state and not "up"
first Index is for players
second Index is for boolean indicating the specific key states for a player
0 = "w"
1 = "s"
2 = "a"
3 = "d"
4 = "space bar" (possible jump)
5 = "c" (possible crouch key)
6 = "f" (possible flash light key)
8 = "mouse key 1"
9 = "mouse key 2"
GLOBAL ARRAY FOR TRIGGER REFERENCES
PlayerKeyTrigs[0-15,0-9,0-1] (type: not sure on type) ( 2 trigs for each key per player)
Global Key Input Buffer Value ( could save this to the bank for a player so they can adjust it)
KeyBuffer (type: Real) = .15
Global Mouse Input Buffer Value ( could save this to the bank for a player so they can adjust it)
MouseBuffer (type: Real) = .15
These inputs will be listed for just player 1 but will need to be reproduced for every other player)
c_playerAny is a constant variable which is automatically created by Sc2. It's value is -1.
Basically here you add which player should trigger the event. If you input 1 then only player 1 will trigger it. c_playerAny ( or -1) will allow every player to trigger the event.
If you look at the GUI representation of the AnyUnitEntersChatMessage event you'll see that you can specify to look for exact string match or partial string match. This is what the 'true' is for. True means exact match, False means partial match.
c_playerAny is a constant variable which is automatically created by Sc2. It's value is -1. Basically here you add which player should trigger the event. If you input 1 then only player 1 will trigger it. c_playerAny ( or -1) will allow every player to trigger the event.
If you look at the GUI representation of the AnyUnitEntersChatMessage event you'll see that you can specify to look for exact string match or partial string match. This is what the 'true' is for. True means exact match, False means partial match.
Did I ever tell you that I love you s3rius.....
I figured thats what the "true" did ... but wasnt sure....
so i can use "-1" interchangably with c_playerAny.... this actually saves space on the script limit right?
I'm not so sure about that. Probably not.
Constants should be replaced by their actual numbers after complilation (not visible for the user) so I don't think constants will save any space. Or to put it the other way round: Constants don't use up more space than their value.
I'm not so sure about that. Probably not. Constants should be replaced by their actual numbers after complilation (not visible for the user) so I don't think constants will save any space. Or to put it the other way round: Constants don't use up more space than their value.
so what your saying is the "script" is actually compiled .... meaning its not really "script" as I would refer to .... php, asp(aka vb script), javascript
Heh Im pretty sure all this has been covered in other topics.... but ... basically this topic here Im gonna try and go over any questions I have learning galaxy script.... I can program in about 10+ other programing langauges.... so most my questions are in regards to how specific things are done in this....
Well, it's not exactly the same.
Usually when you compile a script (of any programming language) you basically turn it into a different langauge (object code) that can be executed by your computer. The actual script that you are writing is just an interface for you to make it easier.
Here it's about the same, I think. Galaxy code gets turned into a Sc2-friendly language. I would have to know more about it's internal mechanics to say something more concrete..
This isn't precise but let's for example convert 5 * 6 to a binary object code.
Let's say we have a simple opcode
OPCODE_MULTIPLY = 0x01
so it might look like
0x01 0x05 0x06 or
00000001000000000000000000000000000001010000000000000000000000000000110
the first 8 bits (byte) is 0x01, or OPCODE_MULTIPLY, means we're multiplying two numbers. the next 32 bits are an integer, 5, and the next 32 bits are another integer, 6.
SC2 can read this much faster than raw Galaxy which is compiled to something like that.
This is a fairly over-simplistic example, and lacks any method of storing the resulting equation and whatnot, but it should give a cool idea of how things are compiled.
Ok so I took my first crack at actually implementing script last night ran into some issues..
The only way i found to view... GUI created triggers in script was to ..... forcably cause a script error in a custom scipt... this would then bring up the script error window and then I could view "Gui" created stuff as script ( is there an easier way to view this)
Created a trigger in script and it did not work
it had an event which should have fired it off after 20 seconds elapsed
should have out putted the message hello world
dont have the exact code but it was basically as followed
this isnt exactly the code I had, Im at work atm.... I was able to run the map but the event did not occur.... what am I missing here....
The whole
_Init
and
_Func
this is how the scipt for the GUI triggers appear
with out them the script would generate errrors
I cant seem to find any other topics that actually discuss the requirements to get custom functions to run... I see plent examples of functions.... but no discussion on actual samples of functioning code
so yeah
triggerNewTrig
Creates a Trigger Variable in SC2
NewTrig=createTrigger("NewTrig")
Not sure the point of this exactly all I know is it creates a "Trigger" named "NewTrig" that is referenced to the trigger variable "NewTrig" I have no idea if the "NewTrig" is also a reference to the actual function I have declared later on in script
Basically tells SC2 to run the Trigger variable reference (NewTrig) when 20 seconds elapses. Now Im pretty sure the (NewTrig) being refered to, to execute here, is a reference the the actuall trigger variable "NewTrig" and not the scripted function
This is my declaration of the NewTrig function...... GUI triggers put a _Func appended to the triggers name... not sure if im spose to do this. Gui triggers generally are "bool's" with a returned value... but I used Void... is that ok?
code doesnt generate any errors
NewTrig_Init()
I believe this command here loads the declared "NewTrig_Func" into memory...... not really sure but GUI triggers appear to do this as well.
Instead of jumping straight into galaxy to code, I suggest you learn programming in general first. For example, learning to program first in Java and Cplusplus will help you immensely when creating more complicated maps.
Why dont u create a trigger with GUI and use the ctrl + F11 to view it.
Your NewTrig_Func has no parameter. maybe not important
your createTrigger function call should be in another function ( init
bla) And u shoult call that init function in global init function.
The script validator of SC2 is a bitch.
umm well im not sure about the init_bla..... im assuming I need a specific command and my custom script to get the ball rolling... not sure what it is
havent found a decent "hello world" script example in the forums yet.
Ill be sure to create a "hello world" script example and add it to this topic when i get it to work...
spent most of tonight creating a GUI for the SC2 obfuscation program
Rollback Post to RevisionRollBack
Skype
KageNinpo = SN
My Libraries
DialogLeaderboard & TeamSort
My Projects
SPACEWAR Tribute
Infinite TD
It seems the trigger itself is missing. Every trigger you create in GUI, when compiled into script, will create a global trigger variable with a really shitty name, such as:
TriggerAddEvent(NewTrig_Func,User Press Spacebar), / / Your Event
In order for this to work, a block of custom script with your trigger needs to be inserted in the following format.
boolNewTrig_Func(booltestConds,boolrunActions){//Variables*Declareyourlocalvariables.FromwhatIunderstand,theyareautomaticallycleaneduponcethetriggerthreadcompletesitsexecution.//Conditionsif(testConds){*Insertyourconditionshere,youcanactuallydowithoutthetestCondsifconditionifyoudon't need it. Its basically used whenever you attempt to run a trigger checking conditions.}//Actions*CallFunction();returntrue;}
You then create your CallFunction as a function to be called:
voidCallFunction(){*PrintHelloWorld}
Also, when you code in custom script, you will notice that there is a line at the bottom of the custom script for your script initialization. If you have a function void InitScript(){} inside your custom script and wish to use it as the initialization function, just type InitScript into that line and the compiler will automatically arrange it such that InitScript will be called at game initialization. Your trigger initialization and trigger add event typically fit into this function.
PS: I know theres probably some syntax errors here, I wrote this in a jiffy. But Hopefully this will help you get a better idea of how GUI is compiled into galaxy. Oh, and welcome aboard to the world of scripting :) Just let me know if it'd make it clearer if I code this and attach it. I don't have access to the API at the moment though, so I'll have to upload it in notepad and hope someone can fix any syntax errors if there are any.
The above will print "Hello World!" to the "debug area" (basically to the left of the screen, just above the minimap) three real seconds after the map starts.
Yes, that is a complete and functional MapScript.galaxy. It's not necessary to put your trigger "Actions" in a separate function call - if anything, keeping the entire trigger content in the same function helps with performance a tiny bit.
As for getting your custom script to run, the easiest way is to simply create a new "Custom Script" element in your trigger list view (RightClick -> New -> New Custom Script, when you right-click the panel that shows your list of triggers in the trigger editor). When you select this new element, you'll see a large window for typing your script, and at the very bottom a tiny little box called "Initialization Function (Optional)". Whatever you type in this box will be the function name of the function you want to run in this Custom Script block at map init.
So, if I make a Custom Script block with a "fooBar" function and I enter "fooBar" in the Init Function box at the bottom, my resulting MapScript.galaxy might look like this:
include"TriggerLibs/NativeLib"triggerfoo;voidInitLibs(){libNtve_InitLib();}voidfooBar(){Wait(5,c_timeReal);UIDisplayMessage(PlayerGroupAll(),c_messageAreaDebug,StringToText("I'm a test!"));}boolbar(booltestConds,boolrunActions){if(!runActions){returnfalse;}UIDisplayMessage(PlayerGroupAll(),c_messageAreaDebug,StringToText("Hello World!"));returntrue;}voidInitTriggers(){foo=TriggerCreate("bar");TriggerAddEventTimeElapsed(foo,3,c_timeReal);}voidInitCustomScript(){fooBar();}voidInitMap(){InitLibs();InitTriggers();InitCustomScript();}
Basically, you can use this Custom Script block itself to put all your code, one block could call functions and use globals from another Block (as long as it's positioned lower than the others in the trigger list, because that determines their position in the generated code and galaxy requires forward-definition), or this one block could have:
include"fileToInclude"
as its only statement, as long as you also import a file named "fileToInclude.galaxy" in your map through the import editor and it's located at the root "folder" of the map. This way you can work almost exclusively in external files. If you really want only external files, you can also import and override MapScript.galaxy with your own code (like I did to test the above examples), but that's a finnicky and tricky process and you'll bash your head on a wall trying to do it unless you know and perform the proper rituals to appease the gods of the Editor beforehand.
This way you can work almost exclusively in external files. If you really want only external files, you can also import and override MapScript.galaxy with your own code (like I did to test the above examples), but that's a finnicky and tricky process and you'll bash your head on a wall trying to do it unless you know and perform the proper rituals to appease the gods of the Editor beforehand.
Hahahahaha!
Working exclusively in external files is good imo because you can work on your project without SC2, I find that useful because then I can carry my project around on a USB. I remember MotiveMe had a tutorial thread about this... maybe you can search it up SoulCarver, if you're interested. Oh and apologies for the misunderstanding, you didn't seem like you knew about constants so I thought you were new to coding.
Actually, the two methods I stated above I've learned from Motive directly while I was attempting to help the Cortex project. I agree that working in external files is pretty good. At the moment I'm very partial to Andromeda, and developing in Andromeda has the huge advantage that I haven't even opened the map I'm currently working on in the SC2 editor in days, yet have been working on it constantly - the code of the map itself basically consists of a single include statement in a custom Action definition, which the Andromeda compiler detects when compiling the map. The rest of my code is 100% external, and the compiler does all the importing and other tidbits of data-mongering on its own (on top of compiling Andromeda code to Galaxy code, obviously). Looking forward to 0.2.0, too. Just wish I had Moonlite to go along with all this.
As for SoulCarver's difficulties (e.g. seeming like he doesn't know about constants), I'm assuming it's more because he isn't too familiar yet with the structural concepts and terminology associated with galaxy script. It's very easy to fully understand and use adequately the concept of "number or value that has a name and that doesn't change" without necessarily knowing that that's called a "constant" in mathematical or coding jargon, to take a generic primitive example.
Edit: I changed the names of all things a bit to make it more obvious what goes where.
That's a functional Hello-world program.
What you have done wrong:
0) You forgot a few semi-colons ( ; ) behind all the statements. Also, you wrote createTrigger. It's TriggerCreate.
1) If you want a function to be hooked to a trigger (like NewTrig in this case) it MUST take two booleans and return a boolean. That's a must. The names of it doesn't matter actually.
2) You cannot put chunks of code outside functions. Stuff like TriggerAddEventTimeElapsed needs to be inside a function. So we need a second function (NewTrig_Init) to construct out trigger. Again, the name of the function doesn't matter. GUI always suffixes them with _Init, so let's go with that.
3) Now you need a way to run the NewTrig_Init function. Because if that one isn't called then the trigger never gets created.
That's where initializers come in. When you look at the bottom of the trigger editor (only when you have a custom script selected) then you'll see a label for an Initializer function.
This function will be run automatically when the map starts. In our case we need NewTrig_Init to be run, so we write it into this label. I think you must not write the (). They'll be appended automatically.
The Initializer line could, in theory, replace the Run-At-Map-Start event. But you shouldn't do that. Always use a trigger for that. Because Initializers have a few limitations. For example they react allergic to Wait commands.
Not sure the point of this exactly all I know is it creates a "Trigger" named "NewTrig" that is referenced to the trigger variable "NewTrig" I have no idea if the "NewTrig" is also a reference to the actual function I have declared later on in script
No idea what you mean with that. NewTrig is a trigger. And the trigger is ordered to execute a function called "NewTrig" when the trigger fires.
Basically tells SC2 to run the Trigger variable reference (NewTrig) when 20 seconds elapses. Now Im pretty sure the (NewTrig) being refered to, to execute here, is a reference the the actuall trigger variable "NewTrig" and not the scripted function
Yes, in general you can't put function names as parameters. That works for more elevated languages like C+ +.
This is my declaration of the NewTrig function...... GUI triggers put a _Func appended to the triggers name... not sure if im spose to do this. Gui triggers generally are "bool's" with a returned value... but I used Void... is that ok?
code doesnt generate any errors
You could also name the function BLAGH if you wanted to. Names don't matter. The bools are needed like stated above. Leaving them out doesn't create errors, but it stops the trigger from working.
Ok so this is gonna be my first attempt to learn scripting. First section is going to be theory on the functions I need to create. As I learn scripting I will update with actual code.
Theories
Initial scripts to get up and moving
Player Inputs
These inputs will be listed for just player 1 but will need to be reproduced for every other player)
Forward
Backward
Left
Right
Space
Stuff Ive Learned
Custom Script "HelloWorld" Event Sample Thanx to FuzzyD
c_playerAny is a constant variable which is automatically created by Sc2. It's value is -1. Basically here you add which player should trigger the event. If you input 1 then only player 1 will trigger it. c_playerAny ( or -1) will allow every player to trigger the event.
If you look at the GUI representation of the AnyUnitEntersChatMessage event you'll see that you can specify to look for exact string match or partial string match. This is what the 'true' is for. True means exact match, False means partial match.
Did I ever tell you that I love you s3rius.....
I figured thats what the "true" did ... but wasnt sure....
so i can use "-1" interchangably with c_playerAny.... this actually saves space on the script limit right?
I'm not so sure about that. Probably not. Constants should be replaced by their actual numbers after complilation (not visible for the user) so I don't think constants will save any space. Or to put it the other way round: Constants don't use up more space than their value.
so what your saying is the "script" is actually compiled .... meaning its not really "script" as I would refer to .... php, asp(aka vb script), javascript
Heh Im pretty sure all this has been covered in other topics.... but ... basically this topic here Im gonna try and go over any questions I have learning galaxy script.... I can program in about 10+ other programing langauges.... so most my questions are in regards to how specific things are done in this....
Well, it's not exactly the same. Usually when you compile a script (of any programming language) you basically turn it into a different langauge (object code) that can be executed by your computer. The actual script that you are writing is just an interface for you to make it easier.
Here it's about the same, I think. Galaxy code gets turned into a Sc2-friendly language. I would have to know more about it's internal mechanics to say something more concrete..
@s3rius: Go
This isn't precise but let's for example convert 5 * 6 to a binary object code.
Let's say we have a simple opcode
OPCODE_MULTIPLY = 0x01
so it might look like
0x01 0x05 0x06 or
00000001000000000000000000000000000001010000000000000000000000000000110
the first 8 bits (byte) is 0x01, or OPCODE_MULTIPLY, means we're multiplying two numbers. the next 32 bits are an integer, 5, and the next 32 bits are another integer, 6.
SC2 can read this much faster than raw Galaxy which is compiled to something like that.
This is a fairly over-simplistic example, and lacks any method of storing the resulting equation and whatnot, but it should give a cool idea of how things are compiled.
I update the event api of the wiki. Something was wrong...
@avogatro: Go
wow thanx avogatro .... those definitions up there are much more helpfull now
Ok so I took my first crack at actually implementing script last night ran into some issues..
dont have the exact code but it was basically as followed
Added this to a custom script
this isnt exactly the code I had, Im at work atm.... I was able to run the map but the event did not occur.... what am I missing here....
The whole
_Init
and
_Func
this is how the scipt for the GUI triggers appear
with out them the script would generate errrors
I cant seem to find any other topics that actually discuss the requirements to get custom functions to run... I see plent examples of functions.... but no discussion on actual samples of functioning code
so yeah
Creates a Trigger Variable in SC2
Not sure the point of this exactly all I know is it creates a "Trigger" named "NewTrig" that is referenced to the trigger variable "NewTrig" I have no idea if the "NewTrig" is also a reference to the actual function I have declared later on in script
Basically tells SC2 to run the Trigger variable reference (NewTrig) when 20 seconds elapses. Now Im pretty sure the (NewTrig) being refered to, to execute here, is a reference the the actuall trigger variable "NewTrig" and not the scripted function
This is my declaration of the NewTrig function...... GUI triggers put a _Func appended to the triggers name... not sure if im spose to do this. Gui triggers generally are "bool's" with a returned value... but I used Void... is that ok?
code doesnt generate any errors
I believe this command here loads the declared "NewTrig_Func" into memory...... not really sure but GUI triggers appear to do this as well.
Why dont u create a trigger with GUI and use the ctrl + F11 to view it.
Instead of jumping straight into galaxy to code, I suggest you learn programming in general first. For example, learning to program first in Java and Cplusplus will help you immensely when creating more complicated maps.
@Vermore: Go
Umm thanx ... i have that base already covered
umm well im not sure about the init_bla..... im assuming I need a specific command and my custom script to get the ball rolling... not sure what it is
havent found a decent "hello world" script example in the forums yet.
Ill be sure to create a "hello world" script example and add it to this topic when i get it to work...
spent most of tonight creating a GUI for the SC2 obfuscation program
It seems the trigger itself is missing. Every trigger you create in GUI, when compiled into script, will create a global trigger variable with a really shitty name, such as:
In order for this to work, a block of custom script with your trigger needs to be inserted in the following format.
You then create your CallFunction as a function to be called:
Also, when you code in custom script, you will notice that there is a line at the bottom of the custom script for your script initialization. If you have a function void InitScript(){} inside your custom script and wish to use it as the initialization function, just type InitScript into that line and the compiler will automatically arrange it such that InitScript will be called at game initialization. Your trigger initialization and trigger add event typically fit into this function.
PS: I know theres probably some syntax errors here, I wrote this in a jiffy. But Hopefully this will help you get a better idea of how GUI is compiled into galaxy. Oh, and welcome aboard to the world of scripting :) Just let me know if it'd make it clearer if I code this and attach it. I don't have access to the API at the moment though, so I'll have to upload it in notepad and hope someone can fix any syntax errors if there are any.
Here's a very barebones Galaxy "Hello World" script:
The above will print "Hello World!" to the "debug area" (basically to the left of the screen, just above the minimap) three real seconds after the map starts.
Yes, that is a complete and functional MapScript.galaxy. It's not necessary to put your trigger "Actions" in a separate function call - if anything, keeping the entire trigger content in the same function helps with performance a tiny bit.
As for getting your custom script to run, the easiest way is to simply create a new "Custom Script" element in your trigger list view (RightClick -> New -> New Custom Script, when you right-click the panel that shows your list of triggers in the trigger editor). When you select this new element, you'll see a large window for typing your script, and at the very bottom a tiny little box called "Initialization Function (Optional)". Whatever you type in this box will be the function name of the function you want to run in this Custom Script block at map init.
So, if I make a Custom Script block with a "fooBar" function and I enter "fooBar" in the Init Function box at the bottom, my resulting MapScript.galaxy might look like this:
Basically, you can use this Custom Script block itself to put all your code, one block could call functions and use globals from another Block (as long as it's positioned lower than the others in the trigger list, because that determines their position in the generated code and galaxy requires forward-definition), or this one block could have:
as its only statement, as long as you also import a file named "fileToInclude.galaxy" in your map through the import editor and it's located at the root "folder" of the map. This way you can work almost exclusively in external files. If you really want only external files, you can also import and override MapScript.galaxy with your own code (like I did to test the above examples), but that's a finnicky and tricky process and you'll bash your head on a wall trying to do it unless you know and perform the proper rituals to appease the gods of the Editor beforehand.
Hahahahaha! Working exclusively in external files is good imo because you can work on your project without SC2, I find that useful because then I can carry my project around on a USB. I remember MotiveMe had a tutorial thread about this... maybe you can search it up SoulCarver, if you're interested. Oh and apologies for the misunderstanding, you didn't seem like you knew about constants so I thought you were new to coding.
@Vermore: Go
Actually, the two methods I stated above I've learned from Motive directly while I was attempting to help the Cortex project. I agree that working in external files is pretty good. At the moment I'm very partial to Andromeda, and developing in Andromeda has the huge advantage that I haven't even opened the map I'm currently working on in the SC2 editor in days, yet have been working on it constantly - the code of the map itself basically consists of a single include statement in a custom Action definition, which the Andromeda compiler detects when compiling the map. The rest of my code is 100% external, and the compiler does all the importing and other tidbits of data-mongering on its own (on top of compiling Andromeda code to Galaxy code, obviously). Looking forward to 0.2.0, too. Just wish I had Moonlite to go along with all this.
As for SoulCarver's difficulties (e.g. seeming like he doesn't know about constants), I'm assuming it's more because he isn't too familiar yet with the structural concepts and terminology associated with galaxy script. It's very easy to fully understand and use adequately the concept of "number or value that has a name and that doesn't change" without necessarily knowing that that's called a "constant" in mathematical or coding jargon, to take a generic primitive example.
Edit: I changed the names of all things a bit to make it more obvious what goes where.
That's a functional Hello-world program.
What you have done wrong:
0) You forgot a few semi-colons ( ; ) behind all the statements. Also, you wrote createTrigger. It's TriggerCreate.
1) If you want a function to be hooked to a trigger (like NewTrig in this case) it MUST take two booleans and return a boolean. That's a must. The names of it doesn't matter actually.
2) You cannot put chunks of code outside functions. Stuff like TriggerAddEventTimeElapsed needs to be inside a function. So we need a second function (NewTrig_Init) to construct out trigger. Again, the name of the function doesn't matter. GUI always suffixes them with _Init, so let's go with that.
3) Now you need a way to run the NewTrig_Init function. Because if that one isn't called then the trigger never gets created.
That's where initializers come in. When you look at the bottom of the trigger editor (only when you have a custom script selected) then you'll see a label for an Initializer function.
This function will be run automatically when the map starts. In our case we need NewTrig_Init to be run, so we write it into this label. I think you must not write the (). They'll be appended automatically.
The Initializer line could, in theory, replace the Run-At-Map-Start event. But you shouldn't do that. Always use a trigger for that. Because Initializers have a few limitations. For example they react allergic to Wait commands.
No idea what you mean with that. NewTrig is a trigger. And the trigger is ordered to execute a function called "NewTrig" when the trigger fires.
Yes, in general you can't put function names as parameters. That works for more elevated languages like C+ +.
You could also name the function BLAGH if you wanted to. Names don't matter. The bools are needed like stated above. Leaving them out doesn't create errors, but it stops the trigger from working.