Staredit Network > Forums > SC1 UMS Theory and Ideas > Topic: Using Scripts to Generate Triggers
Using Scripts to Generate Triggers
Nov 21 2012, 4:03 pm
By: Moose  

Nov 21 2012, 4:03 pm Moose Post #1

We live in a society.

I've been using these methods for mass triggering as early as 2009 (I used it for 47, Temple Siege, and Theatre of War), before fancy things like Oreo Triggers and FARLAP. I suppose Oreo Triggers might be more generalized and is a scripting language in itself, but what I do here is use a script to generate text triggers directly without as much of an external framework. The application is specific to the map that I use the triggers in, but nonetheless helpful and more flexible to me as a mapper. Maybe it will inspire someone else.

I'll be posting a more complicated example later, but here is a basic one used for my beacon triggers in my Civilization map. You can see the output of the script here. I realize that PHP is probably not the most efficient language (and hell, my code probably isn't maximally efficient) for something like this, but it is what I know how to use, I have access to SEN's server to run scripts here, and getting direct output in my browser is nice.

This method is also flexible: if I ever need to change the triggers for all the beacons at once, I just modify the script accordingly and paste the output over the old triggers. For example, I might decide that I want a certain government type to grant a special bonus for Banks, or that I want a death counter to count the number of beacons for a corruption mechanic or something. Then I just modify the triggers as needed and they're all generated for me.

What must be done:
- The map needs Protoss Beacons placed with a sequence of properly named locations. The sequence for my map was R1, R2, R3, ..., Rmax, where the max is the highest beacon number used in my map.
- Each beacon must change owners properly depending on who has buildings near them.
- Each beacon must give a specified amount of income when it's time to process income. In this map, it's when the Mineral Field (Type 1) deaths are 1. The amount of income is 100, though I could easily change that and run the script again for any amount I like.
- If the beacon has a "Bank", or Terran Academy next to it, it should give extra minerals. The amount of income from a Bank is 50, but again I can easily change that and run the script again for any amount I like.

The code:
Code
<?php

header("content-type:text/plain");

///////////
// The map already has locations R1, R2, R3, ... R(max)
// We want to make text triggers for each of them, incrementing the location number each time.
///////////

    // Start at R1 and end at R157
$rnum = 1;
$rmax = 157;

while ($rnum <= $rmax)
{
    $output .= <<<EOF

Trigger("Civs"){
Conditions:
    Bring("Current Player", "Buildings", "R{$rnum}", At least, 1);
    Bring("Player 8", "Buildings", "R{$rnum}", At most, 0);
    Bring("Player 8", "Protoss Beacon", "R{$rnum}", At least, 1);

Actions:
    Give Units to Player("Player 8", "Current Player", "Protoss Beacon", 1, "R{$rnum}");
    Preserve Trigger();
}

//-----------------------------------------------------------------//

Trigger("Civs"){
Conditions:
    Bring("Civs", "Buildings", "R{$rnum}", At most, 0);
    Bring("Player 10", "Protoss Beacon", "R{$rnum}", At most, 0);
    Bring("Current Player", "Protoss Beacon", "R{$rnum}", At Least, 1);

Actions:
    Give Units to Player("All Players", "Player 8", "Protoss Beacon", 1, "R{$rnum}");
    Preserve Trigger();
}

//-----------------------------------------------------------------//

Trigger("Civs"){
Conditions:
    Deaths("Current Player", "Mineral Field (Type 1)", At least, 1);
    Bring("Current Player", "Protoss Beacon", "R{$rnum}", At least, 1);

Actions:
    Set Resources("Current Player", Add, 100, ore);
    Preserve Trigger();
}

//-----------------------------------------------------------------//

Trigger("Civs"){
Conditions:
    Deaths("Current Player", "Mineral Field (Type 1)", At least, 1);
    Bring("Current Player", "Protoss Beacon", "R{$rnum}", At least, 1);
    Bring("Current Player", "Terran Academy", "R{$rnum}", At least, 1);

Actions:
    Set Resources("Current Player", Add, 50, ore);
    Preserve Trigger();
}

//-----------------------------------------------------------------//
EOF;

$rnum++;

}

echo $output;

?>


Post has been edited 4 time(s), last time on Nov 21 2012, 9:03 pm by Mini Moose 2707.




Nov 21 2012, 8:36 pm iCCup.xboi209 Post #2



So your idea is to make php codes to mass generate triggers for Starcraft? I'd rather go with javascript because it's client-sided and much easier(in my opinion, don't flame me for not learning php).



None.

Nov 21 2012, 8:43 pm Moose Post #3

We live in a society.

The idea is to make code that generates mass text triggers directly, which does not have to necessarily be PHP code - using the word "scripts" and not "PHP scripts" in the title was intentional and precise. My reasons for using PHP are mentioned in the article itself... I have a server (SEN's) to use, I am familiar with PHP from coding on SEN, etc.

This could have been done in any programming language that can manipulate and output strings. A script such as this very well could have been written in ten programming languages if I happened to know them. If Javascript is your proficient language of choice and this inspires you, go for it! Out of 60 or 70 lines of code (without comments or fluff) come over 200 triggers with 7500 lines quickly, without mistakes and with tons of flexibility and ease of modifcation. I just wanted to illustrate the power of the option and show an application using what I already had working.

EDIT: As an example of the flexibility, I want each beacon to add to a death counter to give me a territory count for each player and I want each beacon with a Bank (Academy) to add to a death counter to count territories with Marketplaces. Adjusted the output string as such:
Code
    $output .= <<<EOF

Trigger("Civs"){
Conditions:
    Bring("Current Player", "Buildings", "R{$rnum}", At least, 1);
    Bring("Player 8", "Buildings", "R{$rnum}", At most, 0);
    Bring("Player 8", "Protoss Beacon", "R{$rnum}", At least, 1);

Actions:
    Give Units to Player("Player 8", "Current Player", "Protoss Beacon", 1, "R{$rnum}");
    Preserve Trigger();
}

//-----------------------------------------------------------------//

Trigger("Civs"){
Conditions:
    Bring("Civs", "Buildings", "R{$rnum}", At most, 0);
    Bring("Player 10", "Protoss Beacon", "R{$rnum}", At most, 0);
    Bring("Current Player", "Protoss Beacon", "R{$rnum}", At Least, 1);

Actions:
    Give Units to Player("All Players", "Player 8", "Protoss Beacon", 1, "R{$rnum}");
    Preserve Trigger();
}

//-----------------------------------------------------------------//

Trigger("Civs"){
Conditions:
    Deaths("Current Player", "Mineral Field (Type 1)", At least, 1);
    Bring("Current Player", "Protoss Beacon", "R{$rnum}", At least, 1);

Actions:
    Set Resources("Current Player", Add, 100, ore);
    Set Deaths("Current Player", "Vespene Sac (Zerg Type 1)", add, 1);
    Preserve Trigger();
}

//-----------------------------------------------------------------//

Trigger("Civs"){
Conditions:
    Deaths("Current Player", "Mineral Field (Type 1)", At least, 1);
    Bring("Current Player", "Protoss Beacon", "R{$rnum}", At least, 1);
    Bring("Current Player", "Terran Academy", "R{$rnum}", At least, 1);

Actions:
    Set Resources("Current Player", Add, 50, ore);
    Set Deaths("Current Player", "Mineral Field (Type 2)", add, 1);
    Preserve Trigger();
}

//-----------------------------------------------------------------//
EOF;

Uploaded the script, ran it again, copied the output and pasted over the old triggers, done. A minute's worth of work at most to change all the triggers for all the beacons with no mistakes.

Post has been edited 2 time(s), last time on Nov 21 2012, 9:43 pm by Mini Moose 2707.




Nov 22 2012, 4:35 am jjf28 Post #4

Cartography Artisan

Programming triggers ftw!

This is a little program I cooked up while trying to cut down trigger count. Currently it's setup to translate my 'Interloping Quaternary Division Algorithm' to triggers - don't know how I could have realistically set this up otherwise!

Stub of a program, only setup the conditions and actions I've used so far (which are sufficient for doing math and gridding); Source


^ Still scares me a bit! ^^



TheNitesWhoSay - Clan Aura - github

Reached the top of StarCraft theory crafting 2:12 AM CST, August 2nd, 2014.

Nov 22 2012, 7:00 am Kaias Post #5



Quote from Mini Moose 2707
I realize that PHP is probably not the most efficient language (and hell, my code probably isn't maximally efficient) for something like this, but it is what I know how to use, I have access to SEN's server to run scripts here, and getting direct output in my browser is nice.
Oreo triggers is in PHP for the same reasons, and because it started out in the same way as what you're doing here. It was a quick and dirty way to get the job done in a scripting language I knew well.

Just out of curiousity, I tried remaking your script in oreo triggers:


I made some assumptions about what you were doing. All of the normal conditions/actions exist, of course, I just decided to use the UnitGroup class for added readability and modularity instead of normal Brings/Gives. The "Anywhere" location parameter for each UnitGroup is arbitrary since it's never being used (we're always specifying the location as $loc).

Post has been edited 2 time(s), last time on Nov 22 2012, 7:22 am by Kaias.



None.

Nov 22 2012, 7:45 am The Starport Post #6



One thing I'd started to find is there's only so much abstraction you can apply before you realize the real bottleneck with triggers almost always comes down to some low level silliness that defies abstraction.



None.

Nov 22 2012, 8:08 am Kaias Post #7



Quote from name:Tuxlar
One thing I'd started to find is there's only so much abstraction you can apply before you realize the real bottleneck with triggers almost always comes down to some low level silliness that defies abstraction.
Most of the benefit comes from maintainable, more modular code. That and removing the error-prone tediousness of manual trigger duplication.
When I was working on Nightfall, I had virtually every player for every unit used as a different deathcounter. I kept a document to keep track of every player/unit pair and then renamed each unit based on which of its deathcounters I was using at the moment. Now I don't need to keep track of anything.

Post has been edited 1 time(s), last time on Nov 22 2012, 8:14 am by Kaias.



None.

Nov 22 2012, 8:42 am The Starport Post #8



Yeah yeah. I dunno about other map makers, but most of the time I spent with my maps came down to debugging stupid crap or tweaking something in some small handful of triggers somewhere until it did what I wanted.

My point is not to spend too much time building abstractificatored triggers in the place of comprehending them in their naked, low-level form (in the contexts where this is important, I mean). I sorta ended up doing that, and found that it just slowed me down, ironically.

Post has been edited 2 time(s), last time on Nov 22 2012, 10:03 am by Tuxlar.



None.

Nov 22 2012, 3:38 pm Sacrieur Post #9

Still Napping

Well, what OT needs is libraries. You know, a function that will automatically find the IID of a unit, among other things, like find the HP.



None.

Nov 22 2012, 4:32 pm Moose Post #10

We live in a society.

Quote from Kaias
Oreo triggers is in PHP for the same reasons, and because it started out in the same way as what you're doing here. It was a quick and dirty way to get the job done in a scripting language I knew well.

Just out of curiousity, I tried remaking your script in oreo triggers:
Nice. I admit that I never really got into Oreo Triggers, (when it was released, I did mention that I've been using PHP to do this stuff already) but I can see the advantages and I'm glad it can do these things as well.

Quote from name:Tuxlar
One thing I'd started to find is there's only so much abstraction you can apply before you realize the real bottleneck with triggers almost always comes down to some low level silliness that defies abstraction.
Quote from name:Tuxlar
Yeah yeah. I dunno about other map makers, but most of the time I spent with my maps came down to debugging stupid crap or tweaking something in some small handful of triggers somewhere until it did what I wanted.

My point is not to spend too much time building abstractificatored triggers in the place of comprehending them in their naked, low-level form (in the contexts where this is important, I mean). I sorta ended up doing that, and found that it just slowed me down, ironically.
Abstraction, like most things, has a proper time and place. There are some single triggers or groups of triggers with specific purposes where abstraction would be more than its worth because you would make the triggers directly. I wouldn't write a script to output triggers with no variables, because the script would be serving as a superfluous middleman. My original intention was to supplement the existing text triggers in SCMD2. The only real benefit I could gain from abstracting all of my triggers would be to directly output all triggers and copy/paste the entire thing instead of locating particular pieces inside the trigger text. (... Actually, that might be worth looking into. :P)

Then again, what is the level of abstraction in my example? All of the text that will be output in the triggers is very readable, in the familiar SCMD2 text trigger style, there's just a variable and external of that, a control structure to make it go 157 times and increment the variable each time. (If this is abstract, you'll hate the second example I have planned :awesome:)

That being said, if I am doing something like in my example: outputting 157 sets of triggers where only a number in the location name changes, why would I not work with something abstract? The task is very simple but horribly tedious and very prone to human error; it's the perfect job to give to a machine. The script not only took less time to make than doing it myself, but it will save me more time and effort each and every time I decide that the triggers should change in either small or large ways.

Then again, you could've been commenting on the level of abstraction in Oreo Triggers the entire time. :P




Nov 22 2012, 5:07 pm Kaias Post #11



Quote from Sacrieur
Well, what OT needs is libraries. You know, a function that will automatically find the IID of a unit, among other things, like find the HP.


I have a lot of math functions for deathcounters, and EUD functions for any unit specified index. Most of this stuff just isn't documented, unfortunately.

Edit: @Minimoose
I think your level of abstraction is exactly the level he's comfortable with.

Post has been edited 1 time(s), last time on Nov 22 2012, 5:31 pm by Kaias.



None.

Nov 22 2012, 6:28 pm iCCup.xboi209 Post #12



I just developed a javascript equivalent of the php code in your first post:
Code
var Anum = 1;
var Amax = 158;
while (Anum < Amax) {
   document.write("<code>\
Trigger(\"Civs\"){<br>\
Conditions:<br>\
   Bring(\"Current Player\", \"Buildings\", " + Anum + ", At least, 1);<br>\
   Bring(\"Player 8\", \"Buildings\", " + Anum + ", At most, 0);<br>\
   Bring(\"Player 8\", \"Protoss Beacon\", " + Anum + ", At least, 1);<br>\
<br>\
Actions:<br>\
   Give Units to Player(\"Player 8\", \"Current Player\", \"Protoss Beacon\", 1, " + Anum + ");<br>\
   Preserve Trigger();<br>\
}<br>\
<br>\
//-----------------------------------------------------------------//<br>\
<br>\
Trigger(\"Civs\"){<br>\
Conditions:<br>\
   Bring(\"Civs\", \"Buildings\", " + Anum + ", At most, 0);<br>\
   Bring(\"Player 10\", \"Protoss Beacon\", " + Anum + ", At most, 0);<br>\
   Bring(\"Current Player\", \"Protoss Beacon\", " + Anum + ", At Least, 1);<br>\
<br>\
Actions:<br>\
   Give Units to Player(\"All Players\", \"Player 8\", \"Protoss Beacon\", 1, " + Anum + ");<br>\
   Preserve Trigger();<br>\
}<br>\
<br>\
//-----------------------------------------------------------------//<br>\
\
Trigger(\"Civs\"){<br>\
Conditions:<br>\
   Deaths(\"Current Player\", \"Mineral Field (Type 1)\", At least, 1);<br>\
   Bring(\"Current Player\", \"Protoss Beacon\", " + Anum + ", At least, 1);<br>\
<br>\
Actions:<br>\
   Set Resources(\"Current Player\", Add, 100, ore);<br>\
   Set Deaths(\"Current Player\", \"Vespene Sac (Zerg Type 1)\", add, 1);<br>\
   Preserve Trigger();<br>\
}<br>\
<br>\
//-----------------------------------------------------------------//<br>\
<br>\
Trigger(\"Civs\"){<br>\
Conditions:<br>\
   Deaths(\"Current Player\", \"Mineral Field (Type 1)\", At least, 1);<br>\
   Bring(\"Current Player\", \"Protoss Beacon\", " + Anum + ", At least, 1);<br>\
   Bring(\"Current Player\", \"Terran Academy\", " + Anum + ", At least, 1);<br>\
<br>\
Actions:<br>\
   Set Resources(\"Current Player\", Add, 50, ore);<br>\
   Set Deaths(\"Current Player\", \"Mineral Field (Type 2)\", add, 1);<br>\
   Preserve Trigger();<br>\
}<br>\
<br>\
//-----------------------------------------------------------------//<br>\
</code>");
   Anum++;
}

And here's what's generated: http://xboi209.netne.net/triggers/triggers.html



None.

Nov 23 2012, 3:47 am Moose Post #13

We live in a society.

Nice, so now we're up to three ways of doing it. Though I do have to say I like mine because I can use heredoc syntax to have the string nice and clean without needing any escape characters (such as on quotation marks) or anything. It keeps things a lot cleaner, IMO. I can also set the header type so that I don't have to worry about HTML formatting the linebreaks. (Though you could have omitted it as well and viewed the source of the html output to get proper formatting) Many other languages support heredoc, but unfortunately Javascript is not one of them.




Nov 30 2012, 4:36 pm The Starport Post #14



Well, there's always XML: http://stackoverflow.com/a/9405416/469855

Edit: Even better http://stackoverflow.com/a/6247331/469855

Post has been edited 1 time(s), last time on Nov 30 2012, 4:46 pm by Tuxlar.



None.

Options
  Back to forum
Please log in to reply to this topic or to report it.
Members in this topic: None.
[09:24 pm]
Moose -- denis
[05:00 pm]
lil-Inferno -- benis
[10:41 am]
v9bettel -- Nice
[01:39 am]
Ultraviolet -- no u elky skeleton guy, I'll use em better
[10:50 pm]
Vrael -- Ultraviolet
Ultraviolet shouted: How about you all send me your minerals instead of washing them into the gambling void? I'm saving up for a new name color and/or glow
hey cut it out I'm getting all the minerals
[10:11 pm]
Ultraviolet -- :P
[10:11 pm]
Ultraviolet -- How about you all send me your minerals instead of washing them into the gambling void? I'm saving up for a new name color and/or glow
[2024-4-17. : 11:50 pm]
O)FaRTy1billion[MM] -- nice, now i have more than enough
[2024-4-17. : 11:49 pm]
O)FaRTy1billion[MM] -- if i don't gamble them away first
[2024-4-17. : 11:49 pm]
O)FaRTy1billion[MM] -- o, due to a donation i now have enough minerals to send you minerals
Please log in to shout.


Members Online: Moose