Just thought I'd share some custom functions I use excessively when I script my maps, because its faster than using the standard blizzard ones.. I'm not sure about how it would affect processing speed when running the game though, since theres a lot of callback redundancy (Any idea on this s3rius?) Anyway, here they are:
Feel free to add more, I'm sure theres plenty of annoying functions that require libNtve_gf blablablabla.. which slows down our coding speed. If you have recommendations on how any of these quick functions could be renamed, feel free to suggest them. If this goes well maybe, just maybe we could compile a library of it for everyone to save time.
I dont understand the point of having a library of functions ... that just pass parameters to existing functions... they dont appear to have any additional functionality
You've probably realized I'm a purist when it comes to code so here it goes.
You're breaking the naming convention, functions are PascalCase! ;)
The casting functions, since they can get very long when you have things like StringToFixed(Catalog ...) etc i can consider their naming as a special case.
Other than that i'd try to match natives naming convention, i.e UnitCreateFacing rather than newUnitFacePoint
constfixedRAD_TO_DEG=57.3065;//Used to turn a radiant into degreeconstfixedDEG_TO_RAD=0.01745;//Used to turn a degree into radiant.//Self-explanatoryfunctionDistanceBetweenXYtakesrealx1,realy1,realx2,realy2returnsrealreturnSquareRoot((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))endfunction//Returns x-coordinate of x1 shifted by dist towards anglefunctionOffsetXtakesrealx1,realdist,realanglereturnsrealreturnx1+dist*Cos(angle*bj_DEGTORAD)endfunction//Returns y-coordinate of y1 shifted by dist towards anglefunctionOffsetYtakesrealy1,realdist,realanglereturnsrealreturny1+dist*Sin(angle*bj_DEGTORAD)endfunction//Self-explanatoryfunctionAngleBetweenXYtakesrealx1,realy1,realx2,realy2returnsrealreturnbj_RADTODEG*(Atan2(y2-y1,x2-x1))endfunctionvoiddebug(strings){UIDisplayMessage(PlayerGroupAll(),c_messageAreaSubtitle,StringToText(s));}voiddebugPlayer(intp,strings){//Only display to player pUIDisplayMessage(PlayerGroupSingle(p),c_messageAreaSubtitle,StringToText(s));}//Runs a function by namevoidRunFunction(stringitemString){triggert=TriggerCreate(itemString);TriggerExecute(t,false,false);TriggerDestroy(t);}
The point is that these functions are tedious to write, because they're long and have more parameters than necessary. These wrappers allow for faster and easier coding.
Nope, the engine doesn't handle that by itself. The trigger would stay active for the rest of the game if not destroyed, only the reference to it (the local variable) would be cleaned up.
GUI script doesn't do this, because in GUI it's not possible at all to do that :) That's a Galaxy previledge.
Whoops :X haha. I actually started naming my functions this day after I started learning java. You should have seen my function/variable names before then, they seriously sucked. UnitCreateFacing would work, but it may be ambiguous as I recall there is another function that allows you to create units facing an angle, instead of a point.
Is there a reason why bj_DEGTORAD is being used despite there being some constants declared at the top?
Also, I used Cos before and inserted an angle in degrees, it seemed to work, so i'm curious as to why a conversion is needed here >_>
Overall, Awesome stuff : ) I'll be sure to share more if I come up with any extras. I actually never thought of the debug ones, and the run trigger one. I'm gonna add it to my quick functions list right away. Keep em coming and we might have a nice collection over here. Thanks for sharing! :D
Yea, the bj_DEGTORAD should be DEG_TO_RAD. I copied it from a text file which I started back in Wc3 where bj_xy where defined already.
That's why it says <function - - endfunction> too. Cos() accepts any value, but it shouldn't work properly with anything but an angle in radians. Nevermind, Cos uses degrees instead of radians. Potential error spotted ! x.x
Instead of PointAdd I think you can simply write
point p3= p1 + p2;
As far as I remember the arithmic operators are overloaded for points.
//Surprisingly useful :DtextNO_TEXT=StringToText("");//Gets the height of the current position in the jump parabola.//d = length of jump//h = maximum height of jump//x = point from where to get ZfixedParabolaGetZ(fixedx,fixedd,fixedh){return4*h*x*(d-x)/(d*d);}//Returns 1 if x is a power of 2.intpowerOfTwo(intx){if(x<0){return0;}return!((x-1)&x);}
Nope, the engine doesn't handle that by itself. The trigger would stay
active for the rest of the game if not destroyed, only the reference to
it (the local variable) would be cleaned up.
GUI script doesn't do this, because in GUI it's not possible at all to
do that :) That's a Galaxy previledge.
That makes me curious s3rius.... how does this affect your ability to run that function again after it is destroyed...?
In standard script/ gui the trigger is initialized the same ... run the same....
the fact your creating a variable that is reference to the trigger to run it ... and then destroying the trigger immediately after... what is the point of doing this... how does it differ from the standard way of doing things.....
Or what your saying .... is in gui my trigger would remain in memory? waiting to be used....
where in your script your putting it to memory when your setting the "t" = the trigger name and then running it?
the "trigger name" trigger would still need to be defined some where correct? Just not active? Isnt this similiar to turning a trigger on and off?
if that is the case... if your "trigger name" isnt in memory where is it then? From my understanding all script is loaded into memory regardless once the game is active..... whethor or not it has a definitive variable reference in memory at the time or not is kinda... pointless
Not that im trying to argue here .... just trying to understand the mechanics of it all. i have no idea where you get your information about this stuff
For that we have to delve a little deeper into Starcraft's mechanics.
Most variables in galaxy also exist in Sc2.
To distinguish:
Galaxy script is executed on a Virtual Machine inside Sc2. It is encapsulated, but it communicates with Starcraft and tells it what to do next.
Sc2 is the actual engine. It takes orders from galalxy and executes them.
When you create a trigger (or a unit group, or an actor, or or or) then you don't only create it inside galaxy, but also inside Starcraft itself.
The trigger variable inside galaxy doesn't actually do much. It only points to the real trigger (which is the one inside Sc2). So when I disable a trigger in galaxy it tells Sc2 to disable the real trigger. These kind of variables are called Handles (because they hold onto the real trigger).
It's important to know that the handle sits inside galaxy and the real trigger inside Starcraft.
When a trigger is created something like this is inside galaxy:
This would create a trigger with the "Any play types chat message" event. The variable someTrigger is the handle. With it I can modify the actual trigger. Once a player types "test" the trigger would display some debug message (not important right now).
What happens here is that I run the same code as above 5 times in a row. The handle (= the trigger variable) is overwritten every time. So in galaxy I still only have 1 trigger. BUT - in Sc2 the (real) trigger doesn't get removed (because I haven't ordered it's destruction).
So when I now type "test" it'll show the debug message 5 times, because I made 5 triggers! And they're all still there, even though they're basically invisible to me through galaxy (because I "lost" the handle by overwriting it).
That means:
Even when a trigger variable is overwritten or removed the actual trigger stays until it's manually destroyed.
That's why I call TriggerDestroy(t). If I wouldn't do that then every time I called a function I'd actually create another trigger that'd stay.
You're right that the entire galaxy script is loaded into memory at once, but all the handles create more objects inside of Sc2 which takes up additional memory and processing power. (This memory is used outside of galaxy, so it doesn't actually add onto the 2MB limit. But it still is used up. Only the handle is inside the galaxy memory.)
Basically there are two ways to deal with this:
1) I create a unique trigger handle for every function that I want to call like this. That's how GUI handles Actions with the "New Thread" option enabled.
But that's pretty lame because even if I don't actually run the function it'll still take up memory (the handle eats up the galaxy memory - so the 2MB limit applies). So when I have A LOT of these function they'll use up memory which might not even be used at all.
2) I create a trigger dynamically when I need it and destroy it afterwards. This way I don't waste a single byte of memory on triggers which might not even get created.
As a drawback I have to create a new trigger everytime I run a function, which can be considered slow. BUT the actual trigger is created inside Sc2 and Sc2's engine is FAST. Much faster than galaxy itself. So the creation of the new trigger is nothing to speak of.
I decided for the second option, because it's faster to code, easier to organize and all-in-all just more my style.
Well thanx alot for that information S3rius... I guess this leads itself into how you could dynamically change the "event" on a given trigger. And update the actuall trigger Inside of SC2 engine for it.....
more questions
Is the event detection on a trigger.... handled by the sc2 engine... or the script engine?
You say destroying the trigger saves script memory.... but doesnt the "pre-existing text/script" language need to be loaded somewhere for you to even re-create the said trigger? I mean you cant pull it out of thin error ... it needs to be consuming some kind of memory. I was under the impression the the script limit. Was more of a "text file size" limit rather then a "only this much memory can be being used kinda thing". Maybe Im mistaken on that point.
So you could technically Load a ton of functions from a library at run time for some complex calculations.... and then destroy them all and load the complonents for the game itself. If you were running close to the 2mb limit.
I would try and make my own example of such a thing but i cant find a good example of a full blown trigger in script ugh
1: The Sc2 engine. Galaxy only specifies which events should be detected.
2:
A trigger basically consists of two things. It's events and a function. When the event fires, then the function is executed. (In GUI the function is everything inside the Actions, Local Variables and Conditions part of the trigger.)
This is how a minimalistic triggers looks in galaxy.
The two last lines create the trigger and tell it to run someFunction everytime it's event fires.
someFunction is a function inside galaxy, thus it takes up galaxy memory.
someTrigger is a handle inside galaxy, thus takes up galaxy memory.
The actual trigger is an object inside Sc2, thus takes up Sc2's memory.
The trigger events is also inside Sc2, thus takes up Sc2's memory.
With method 1 (like GUI handles New Threads):
someFunction always exists. It'll always take up memory.
someTrigger is a global variable, It'll always take up memory.
The actual trigger is created and never destroyed, It'll always take up memory.
Trigger events don't have to exist, since we're calling the trigger via TriggerExecute(..).
With method 2 (dynamic creation):
someFunction always exists. It'll always take up memory.
someTrigger is a local variable, so it'll take up memory only when the the function it is inside is run.
The actual trigger is dynamically created/destroyed, so it'll also only take up memory when the function is run.
Trigger events don't have to exist, since we're calling the trigger via TriggerExecute(..).
Which means the ton of functions (of that library you're talking about) HAVE to exist in the script, like someFunction. They'll always exist and always eat memory. Where I'm saving memory is with the someTrigger handle (and also with parameters - GUI turns all parameters into unique global variables, whereas I am recycling globals, but that's something different and doesn't happen in this example).
Also, just to clarify: You can't use this to substitute real triggers, because this method makes having trigger events a bad idea. It is used to call functions by a string name, or to call them as a new thread. Both very, very useful.
The amount of memory you save isn't that much, unless you really make use of it.
For example - you might remember Resident Overmind (which I made during Sc2 beta). It had a bunch of different items you could pick up. The item system made use of this trick, so I saved myself 1 trigger per item in the game. In addition it was much more comfortable to work with.
ah .... to me a trigger isnt a trigger unless.... an event "triggers it" so in my book... i dont call functions triggers.... to me a trigger always has an "event" attached to it.
but your saying this doesnt work well with events.....
anyways I hate to Hijack the topic any further
Rollback Post to RevisionRollBack
Skype
KageNinpo = SN
My Libraries
DialogLeaderboard & TeamSort
My Projects
SPACEWAR Tribute
Infinite TD
It DOES work with triggers. And it works absolutely fine. But since you're losing the trigger handle (because it was a local variable) that means you cannot disable/enable/destroy/add events anymore. The trigger will be active until the end of the map and you (almost) can't stop it anymore :)
But a trigger is useless unless it's either called manually or called via events. If it doesn't have events then it'll just sit around doing nothing. But if it has events then you lose control over it.
Couldnt you use a global variable.... so you dont lose track of it....
Couldnt you use an "array" of trigger handles?
Couldnt you say.... not have any triggers with events..... then dynamically creat all your triggers with events in this manner using the "trigger handle array" from this point
say you had a periodic trigger starting at running every 60 seconds
every 3 minutes of the game you want the period on the trigger to decrease
so you then do a
Turn off (triggerHandle[1])
Destroy (triggerHandle[1])
Set triggerHandle[1] = nothing
Reinitiallize it to the same triggerHandle global index? triggerHandle[1]
using a global variable "X" as the variable period for the event.
triggerHandle[1]=CreatePeriodicTrigger(periodofX)
sorry i dont know script langage to really implement it in code samples =)
You could use a global variable. That's how it is done. But in this case your trigger doesn't differ from a normal trigger. And, of course, you eat the memory again :3
You could use an array of triggers, but that doesn't change anything, too.
You can create all your triggers dynamically. But as long as you keep the handle variable it doesn't really differ from the normal implementation of triggers.
You could use a global variable. That's how it is done. But in this case
your trigger doesn't differ from a normal trigger. And, of course, you
eat the memory again :3
You could use an array of triggers, but that doesn't change anything,
too.
You can create all your triggers dynamically. But as long as you keep
the handle variable it doesn't really differ from the normal
implementation of triggers.
Ah well the main difference for me is I could use a variable in the event.... I dont know of a way I can do that in GUI
Just thought I'd share some custom functions I use excessively when I script my maps, because its faster than using the standard blizzard ones.. I'm not sure about how it would affect processing speed when running the game though, since theres a lot of callback redundancy (Any idea on this s3rius?) Anyway, here they are:
Feel free to add more, I'm sure theres plenty of annoying functions that require libNtve_gf blablablabla.. which slows down our coding speed. If you have recommendations on how any of these quick functions could be renamed, feel free to suggest them. If this goes well maybe, just maybe we could compile a library of it for everyone to save time.
I dont understand the point of having a library of functions ... that just pass parameters to existing functions... they dont appear to have any additional functionality
except possibly the .... text color/ style ones
You've probably realized I'm a purist when it comes to code so here it goes. You're breaking the naming convention, functions are PascalCase! ;)
The casting functions, since they can get very long when you have things like StringToFixed(Catalog ...) etc i can consider their naming as a special case. Other than that i'd try to match natives naming convention, i.e UnitCreateFacing rather than newUnitFacePoint
Some of mine - included into every project :]
@SouLCarveRR: Go
The point is that these functions are tedious to write, because they're long and have more parameters than necessary. These wrappers allow for faster and easier coding.
@s3rius: Go
I thought doing this stuff in script was quick?
I can add all those fucntions in gui in about 1 second...
why do you destroy your trigger after executing it?
Doesnt the engine handle that itself, after the trigger finishes running?
Does the GUI generated script do that as well? Or is that just something you perfer to do?
@SouLCarveRR: Go
Nope, the engine doesn't handle that by itself. The trigger would stay active for the rest of the game if not destroyed, only the reference to it (the local variable) would be cleaned up.
GUI script doesn't do this, because in GUI it's not possible at all to do that :) That's a Galaxy previledge.
Here are some of mine:
@s3rius: Go
You. Are. Awesome.
I had a thread about this, no one could figure out a way. Thanks, I'll be using this one! :)
@caspersc: Go
Whoops :X haha. I actually started naming my functions this day after I started learning java. You should have seen my function/variable names before then, they seriously sucked. UnitCreateFacing would work, but it may be ambiguous as I recall there is another function that allows you to create units facing an angle, instead of a point.
@s3rius: Go
Is there a reason why bj_DEGTORAD is being used despite there being some constants declared at the top? Also, I used Cos before and inserted an angle in degrees, it seemed to work, so i'm curious as to why a conversion is needed here >_>
@MTops: Go
Overall, Awesome stuff : ) I'll be sure to share more if I come up with any extras. I actually never thought of the debug ones, and the run trigger one. I'm gonna add it to my quick functions list right away. Keep em coming and we might have a nice collection over here. Thanks for sharing! :D
@FuzzYD: Go
Yea, the bj_DEGTORAD should be DEG_TO_RAD. I copied it from a text file which I started back in Wc3 where bj_xy where defined already.
That's why it says <function - - endfunction> too.
Cos() accepts any value, but it shouldn't work properly with anything but an angle in radians.Nevermind, Cos uses degrees instead of radians. Potential error spotted ! x.x@MTops: Go
Instead of PointAdd I think you can simply write
point p3= p1 + p2;
As far as I remember the arithmic operators are overloaded for points.
That makes me curious s3rius.... how does this affect your ability to run that function again after it is destroyed...?
In standard script/ gui the trigger is initialized the same ... run the same....
the fact your creating a variable that is reference to the trigger to run it ... and then destroying the trigger immediately after... what is the point of doing this... how does it differ from the standard way of doing things.....
Or what your saying .... is in gui my trigger would remain in memory? waiting to be used....
where in your script your putting it to memory when your setting the "t" = the trigger name and then running it?
the "trigger name" trigger would still need to be defined some where correct? Just not active? Isnt this similiar to turning a trigger on and off?
if that is the case... if your "trigger name" isnt in memory where is it then? From my understanding all script is loaded into memory regardless once the game is active..... whethor or not it has a definitive variable reference in memory at the time or not is kinda... pointless
Not that im trying to argue here .... just trying to understand the mechanics of it all. i have no idea where you get your information about this stuff
@SouLCarveRR: Go
For that we have to delve a little deeper into Starcraft's mechanics.
Most variables in galaxy also exist in Sc2.
To distinguish:
Galaxy script is executed on a Virtual Machine inside Sc2. It is encapsulated, but it communicates with Starcraft and tells it what to do next.
Sc2 is the actual engine. It takes orders from galalxy and executes them.
When you create a trigger (or a unit group, or an actor, or or or) then you don't only create it inside galaxy, but also inside Starcraft itself.
The trigger variable inside galaxy doesn't actually do much. It only points to the real trigger (which is the one inside Sc2). So when I disable a trigger in galaxy it tells Sc2 to disable the real trigger. These kind of variables are called Handles (because they hold onto the real trigger).
It's important to know that the handle sits inside galaxy and the real trigger inside Starcraft.
When a trigger is created something like this is inside galaxy:
This would create a trigger with the "Any play types chat message" event. The variable someTrigger is the handle. With it I can modify the actual trigger. Once a player types "test" the trigger would display some debug message (not important right now).
However, when I write this:
What happens here is that I run the same code as above 5 times in a row. The handle (= the trigger variable) is overwritten every time. So in galaxy I still only have 1 trigger. BUT - in Sc2 the (real) trigger doesn't get removed (because I haven't ordered it's destruction).
So when I now type "test" it'll show the debug message 5 times, because I made 5 triggers! And they're all still there, even though they're basically invisible to me through galaxy (because I "lost" the handle by overwriting it).
That means:
Even when a trigger variable is overwritten or removed the actual trigger stays until it's manually destroyed.
That's why I call TriggerDestroy(t). If I wouldn't do that then every time I called a function I'd actually create another trigger that'd stay.
You're right that the entire galaxy script is loaded into memory at once, but all the handles create more objects inside of Sc2 which takes up additional memory and processing power. (This memory is used outside of galaxy, so it doesn't actually add onto the 2MB limit. But it still is used up. Only the handle is inside the galaxy memory.)
Basically there are two ways to deal with this:
1) I create a unique trigger handle for every function that I want to call like this. That's how GUI handles Actions with the "New Thread" option enabled.
But that's pretty lame because even if I don't actually run the function it'll still take up memory (the handle eats up the galaxy memory - so the 2MB limit applies). So when I have A LOT of these function they'll use up memory which might not even be used at all.
2) I create a trigger dynamically when I need it and destroy it afterwards. This way I don't waste a single byte of memory on triggers which might not even get created.
As a drawback I have to create a new trigger everytime I run a function, which can be considered slow. BUT the actual trigger is created inside Sc2 and Sc2's engine is FAST. Much faster than galaxy itself. So the creation of the new trigger is nothing to speak of.
I decided for the second option, because it's faster to code, easier to organize and all-in-all just more my style.
@s3rius: Go
Well thanx alot for that information S3rius... I guess this leads itself into how you could dynamically change the "event" on a given trigger. And update the actuall trigger Inside of SC2 engine for it.....
more questions
I would try and make my own example of such a thing but i cant find a good example of a full blown trigger in script ugh
1: The Sc2 engine. Galaxy only specifies which events should be detected.
2:
A trigger basically consists of two things. It's events and a function. When the event fires, then the function is executed. (In GUI the function is everything inside the Actions, Local Variables and Conditions part of the trigger.)
This is how a minimalistic triggers looks in galaxy.
The two last lines create the trigger and tell it to run someFunction everytime it's event fires.
someFunction is a function inside galaxy, thus it takes up galaxy memory.
someTrigger is a handle inside galaxy, thus takes up galaxy memory.
The actual trigger is an object inside Sc2, thus takes up Sc2's memory.
The trigger events is also inside Sc2, thus takes up Sc2's memory.
With method 1 (like GUI handles New Threads):
someFunction always exists. It'll always take up memory.
someTrigger is a global variable, It'll always take up memory.
The actual trigger is created and never destroyed, It'll always take up memory.
Trigger events don't have to exist, since we're calling the trigger via TriggerExecute(..).
With method 2 (dynamic creation):
someFunction always exists. It'll always take up memory.
someTrigger is a local variable, so it'll take up memory only when the the function it is inside is run.
The actual trigger is dynamically created/destroyed, so it'll also only take up memory when the function is run.
Trigger events don't have to exist, since we're calling the trigger via TriggerExecute(..).
Which means the ton of functions (of that library you're talking about) HAVE to exist in the script, like someFunction. They'll always exist and always eat memory. Where I'm saving memory is with the someTrigger handle (and also with parameters - GUI turns all parameters into unique global variables, whereas I am recycling globals, but that's something different and doesn't happen in this example).
Also, just to clarify: You can't use this to substitute real triggers, because this method makes having trigger events a bad idea. It is used to call functions by a string name, or to call them as a new thread. Both very, very useful.
The amount of memory you save isn't that much, unless you really make use of it.
For example - you might remember Resident Overmind (which I made during Sc2 beta). It had a bunch of different items you could pick up. The item system made use of this trick, so I saved myself 1 trigger per item in the game. In addition it was much more comfortable to work with.
@s3rius: Go
ah .... to me a trigger isnt a trigger unless.... an event "triggers it" so in my book... i dont call functions triggers.... to me a trigger always has an "event" attached to it.
but your saying this doesnt work well with events.....
anyways I hate to Hijack the topic any further
I love the discussions :D
It DOES work with triggers. And it works absolutely fine. But since you're losing the trigger handle (because it was a local variable) that means you cannot disable/enable/destroy/add events anymore. The trigger will be active until the end of the map and you (almost) can't stop it anymore :)
But a trigger is useless unless it's either called manually or called via events. If it doesn't have events then it'll just sit around doing nothing. But if it has events then you lose control over it.
@s3rius: Go
Couldnt you use a global variable.... so you dont lose track of it....
Couldnt you use an "array" of trigger handles?
Couldnt you say.... not have any triggers with events..... then dynamically creat all your triggers with events in this manner using the "trigger handle array" from this point
using a global variable "X" as the variable period for the event.
sorry i dont know script langage to really implement it in code samples =)
You could use a global variable. That's how it is done. But in this case your trigger doesn't differ from a normal trigger. And, of course, you eat the memory again :3
You could use an array of triggers, but that doesn't change anything, too.
You can create all your triggers dynamically. But as long as you keep the handle variable it doesn't really differ from the normal implementation of triggers.
Ah well the main difference for me is I could use a variable in the event.... I dont know of a way I can do that in GUI
@s3rius: Go
I see you listing functions that are already present in the native galaxy library:
And you are absolutely correct about the + operator being overloaded on points. Thanks for that.