|
|
|
#1 |
|
Administrator
|
Basic Triggering Techniques I
This tutorial is meant to be a guide for people who have little or no experience in working with triggers. The concepts will be extremely basic, but hopefully thorough and written in a language that will help people new to working with triggers gain the fundamentals they need to know to create simple triggers and build their way up to more advanced trigger functions. The tutorial will use a series of simple examples of real-game events and actions to show how to develop triggers you can use to make maps.
Let's start with some basic terminology and some basic things about the editor. Section 1: Triggers - Events, Conditions, & Actions Trigger: A trigger is a function or series of functions that are programmed to happen in a map. Triggers have 3 parts: Events, Conditions, and Actions. All triggers have these three components; although not all triggers require Events or Conditions (any trigger that is going to do something in the map must have at least one action, however). Events: Events are things that happen - simple as that. Triggers don't have to have events that occur within the actual trigger, but they must have some sort of event, or else nothing would ever occur. Triggers can also have more than one event (something people don't always think of). In other words, two different things could cause the same thing to happen in your map. Think: cause and effect. If you never have a cause, you will never have any effect. Ever. Period. If you don't have some kind of event, nothing happens, no matter how many actions you put in. Examples of events:
Conditions: Conditions are just that, things that must be true or met in order for the trigger to actually happen. Conditions are used to discriminate a general event from the specific event you are interested in. Like events, triggers can have more than one condition. Multiple conditions are always joined by an AND operator, unless you specifically make a condition that tells the trigger to use an OR operator. If you aren't familiar with logical operators, this will be covered at length in a bit. What you need to know about conditions is this: if the condition(s) are not met, the actions will never happen. Examples of conditions:
Actions: Actions are what happens when the event occurs AND the conditions are met. If and event occurs but the conditions are not met, nothing happens. If an event happens, the conditions listed for that event are met, and then the triggers actions will start. Something that seems very obvious, but may not be to some newer map-makers is that Events and Conditions have no order to them. How they are listed does not matter. If you have 5 events, any one of them will work. If you have 9 conditions, all 9 must be met. In both cases, order is not important. Actions, however, are always consecutive. The first one listed happens, then the next, then the next, then the next, until the actions are all done. Every time a trigger starts, the actions will play consecutively until they are all worked through. There are some more advanced techniques for skipping actions or forcing the actions to take a small break before continuing, but the actions, once started, will eventually try to go all the way through. Examples of actions:
Ok, so those are the parts of a trigger. If you open the trigger module, you will find that those are the three fields for each trigger. Let's talk a little bit about Event Responses. Event Responses: Event Responses are basically specific things that are referred to by the trigger when an event happens. They can be any type of variable that the event refers to. Before you get confused by this terminology, it is actually very simple, so let's go over some examples. Code:
Event: A unit dies Condition: Unit of the type (dying unit) = Grunt Action: Defeat Player 1 (Red) In this case, the Event Response is (dying unit). It refers to the unit that dies in the event. If your event was Map Initialization and your Condition was the same as the one listed here, nothing would happen. If your event were A unit is attacked and your condition is the same as the one listed here, nothing happens. Even if when the unit is attacked, that unit dies. Also, obviously, if your dying unit isn't a Grunt, the actions won't happen either. Event responses MUST match the event listed. This is probably one of the most common mistakes that people who are new to map-making in WarcraftIII make. If your trigger isn't working like you expected it to, the event responses are usually the first thing you should check. If you want to track a unit dying, you need a unit dies event. If you want to track a unit being attack, you use unit is attacked as an event and (attacking unit) or (attacked unit) as your event responses. As you can see from the last example, some events have more than one event response. In this case, you can track the unit being attacked and/or the unit that is attacking. The specific response that matches an event usually says something in the subtext about what event it goes with. One note, there are many different event responses in the editor and often you can substitute triggering unit for another that is more specific. Triggering unit will generally work with any event that mentions a unit, because that unit is the triggering unit - but you need to be careful with this and make sure you are referencing the correct unit, because as was discussed above, some events can have multiple event responses; triggering unit in A Unit is Attacked refers only to the unit being attacked - to reference the attacking unit, you need to use the event response attacking unit. Now let's modify this very simple trigger so that it is a bit more practical and we can discuss some issues with specific vs. generic unit events, logical operators and conditions, if/then/else actions, and events that happen outside of the trigger. In our silly example, any Grunt-type unit that dies causes Player 1 (Red) to be defeated. In multiplayer games, this isn't so good, unless there is only one Grunt-type unit in the entire map and you happen to know that it must be owned by Red (or somehow other players are responsible for keeping Red in the game). So, let's modify our trigger very slightly to make it so when a Grunt-type unit owned by Red dies, Red is defeated. Still a silly trigger, but something a bit more usable. To do so, we add another condition: Code:
Event: [Generic Unit Event] A unit dies Condition: [Unit-type comparison] Unit of the type (dying unit) = Grunt Condition: [Player comparison] Owner of (dying unit) = Player 1 (Red) Action: [Game] Defeat Player 1 (Red) If you are having trouble getting a trigger to do what you expect it to and you've already checked that the event and event responses are set correctly, you should consider looking at your conditions and make sure tthat there isn't some conflict between two conditions or how they are joined. For example, a unit can't be owned by both Red and Blue, so maybe you meant to have a condition that checks Red or Blue. Conflicting or incorrect conditions are usually the culprit if you know the event is working but none of the actions seem to be happening. Generic vs. Specific Units: Now, I have used the terms generic and specific unit events a couple times without really going over them. I will do that now. A generic unit event is an event that can make a trigger run when any unit on the map does it. A unit dies, for example, isn't talking about a specific unit. It could be any unit. Sometimes you want this, sometimes you don't. A specific unit event would be Grunt #012 dies. It would only happen when a specific grunt that is already in place on the map dies. That unit only - no other units can make the event/trigger occur in this case. Generic and Specific unit events are fairly similar, practically any event that is a Specific Unit Event can be done by using Generic Unit Events, but there are some tricky events that only work for Specific units. There are some clever tools to allow you to get around this restriction, but for the most part, generic units are used for any unit that is spawned after the map starts (and those in the map already placed) but specific units are basically only those that you can select specifically while you are working in the editor. When you can use specific events, it is generally better to use them. In other words, if your trigger really on involves the actions of one specific unit in your map that is already placed, it is in your best interested to use specific unit events. Why force the computer to check conditions every time some unit dies when what you are interested in is one particular unit that dies? The same thing goes for events that are limited by the player. If you only care about Red's units that die, use the event that goes off when a specific player's units die, rather than the generic event - there is no reason to make the computer check conditions if it isn't necessary. Section 2: Special Actions - If/Then & Run Trigger Now, generally speaking, your events, conditions, and actions are separated into their individual areas, however actions are a bit more fluid. You can use, for example, a condition within an action to let the trigger figure out what to do depending on a specific condition. You can also use a special action that forces another trigger to run - so it basically acts like an event and as a result you can have triggers with no events that are simply run by other triggers. If/Then/Else: This is an action that only runs when certain conditions are true. You would use an if/then/else action when it make more sense to bundle a series of actions together and only have some of them run under certain conditions. As an example, we will continue with our dying grunt triggers from above, but now we want one action to happen when a grunt dies and another to happen when all of the grunts owned by that player are dead. Because both scenarios have the same event, it makes sense to bundle them together and just check for the specific case of no more living units (let's just assume there are 5 grunts) - and under those conditions we will defeat player 1. How would that look as a trigger? Like this: Code:
Grunt Dies
Events
Unit - A unit owned by Player 1 (Red) Dies
Conditions
(Unit-type of (Dying unit)) Equal to Grunt
Actions
Game - Display to (All players) the text: A grunt has died!
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Number of living Grunt units owned by Player 1 (Red)) Equal to 0
Then - Actions
Game - Defeat Player 1 (Red) with the message: Defeat!
Else - Actions
In our example above, we want to defeat Red when all of the Grunt-type units are dead. As you can see, when a unit owned by Red dies, it first checks to make sure that the conditions are met, if so, it prints a message to the screen for all players that says "A grunt has died!" This message will be printed to the screen for every grunt unit that is owned by Red dies, but when all of the grunts are dead, the if/then conditions are met and only then is Red defeated. Run Trigger: One last thing on this topic, before we move on to more advanced issues: running an trigger without an event in that trigger. I mentioned it before - all triggers must have some sort of Event, but not all triggers need to have an event in the actual trigger itself. How is that possible? Well, one of the actions you can select is Trigger - Run Trigger (Checking Conditions). This is an action that (when the trigger tells it to do so) runs another trigger that you have selected. In our example, let's say we wanted to use Run Trigger to make our current trigger run another trigger. Why we might want to do this may become more obvious to you later, but for now, we will use a trivial example and rather than Defeat Red in this trigger, we will put Defeat Red in another trigger (let's pretend Red has more than one way of losing and we want to keep the action separated because there is some other complexities that are involved with Red losing (like you want to give all of his gold to another player before he leaves, but you don't want to have to keep making the same actions over and over elsewhere in your other triggers). So, to do this, it is quite simple, we cut and paste or Defeat Player 1 (Red) action into a new trigger that we will call Red Loses. Code:
Events: Conditions: Actions: Defeat Player 1 (Red) Code:
Grunt Dies
Events
Unit - A unit owned by Player 1 (Red) Dies
Conditions
(Unit-type of (Dying unit)) Equal to Grunt
Actions
Game - Display to (All players) the text: A grunt has died!
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Number of living Grunt units owned by Player 1 (Red)) Equal to 0
Then - Actions
Run Trigger (Red Loses) checking conditions
Else - Actions
Congratulations, you now know the most basic parts of triggering. Basic things like Actions, Events, Conditions, and Event Responses should no longer seem like some sort of nebulous jargon. They are simple, really. Making a trigger work for you - and do what you want it to is not really that hard, but sort of like painting a wall isn't very hard, there are good and bad ways to do things and just because you can paint with your fingers doesn't mean that is the most effective way to get the paint on the wall. Making a good trigger that does what you want when you want it is not always easy. Making it clean and efficient and making it work well with your other triggers to get the job done is often more like art than science. But, in the long run (and especially when you are first starting out) getting it to work is the most important part - making it pretty and clean and efficient can come with practice. You need to know what tool for what job and probably the most daunting part about the WE is that it isn't always easy to find the thing you were looking for. Next section we will cover a very important and amazingly useful tool for beginners and even experts: debugging. Why cover it now? Well, I want to spare you the agony of wasting countless hours trying to figure out why your trigger won't work when you think it should. Triggers can be extremely frustrating when things go wrong and if you learn to debug as you learn to program, you are going to be a much happier map-maker. Section 3: Debugging Triggers First off, let's discuss what is involved with debugging. Debugging is a term that basically means to find problems with your triggers and attempt to resolve them. Debugging is an essential part of map-making, which is why I have included it in with the basic triggering section of these tutorials. Debugging For most debugging, you will only really require one extra step and only one action (although I will cover some other cases). Primarily when you debug, you are revisiting the logic of your triggers and attempting to find the place where you got off track. Sometimes it is not something obvious and in order to make actions more obvious, the simplest tool to use is the Game - Display Text action. Code:
Game - Display to (All players) the text: Hey! Why would you care to do this? Well let's pretend we have a series of events similar to the triggers we have been working with, in this instance we are using the one with the Run Trigger action as part of an If/Then/Else, but for some reason the trigger isn't working quite the way we were expecting it to and you are uncertain that the Run Trigger action is actually occurring. In this case, we could insert the simple Game - Display Text action above into the 'Red Loses' trigger and when Red should lose, if we don't see our message displayed, we know that the trigger is not being run, meaning that something is wrong with the mechanics of our design. Now, I know this seems dumb and most of the people reading this might not see this as being particularly useful, but sometimes the easiest way to debug a trigger (or series of triggers), especially if they are complex, is to use a simple Game - Display Text action such as this one and gradually move the action down through your trigger, starting with making sure the event is happening, and then that the conditions are correct, and then testing each of the actions involved until something that should run does not. The more complex the trigger, the more difficult it is to spot any errors in the trigger chain and even masterful trigger gurus sometimes are forced to resorting to this approach. As I mentioned earlier in this tutorial, if your trigger fails, speaking from experience of my own triggering AND years of helping people with triggering problems, that generally the problem is related to one of two things: the trigger response (in other words, the programmer forgot to change (triggering unit) into something else, like say (Last Created Unit) or the conditions are set wrong. Another common problem is that the expected event and the actual event are mismatched. By this I mean that the programmer needed to choose 'Starts the Effect of an Ability' and instead they chose 'Begins Casting' or some other similarly close but incorrect event for the actual event. The good part about all of these issues is that they are almost always possible to spot by using a simple Game - Display Text debug approach. In the case of a mismatched event, the trigger will never actually run, because the event you are expecting to happen never happens, and as a result, you never see the 'Hey!' message show up on the screen no matter where it is placed in your series of actions. This problem occurs quite often with WE programming, primarily because Blizzard's notes and events don't always work the same for all events/event responses and they also don't always work the way you think that they should. Fortunately, you can use Game - Display Text in this simple fashion to isolate events that are not triggering and then simply try a number of events (it is usually fairly obvious once you realize that the trigger is not firing when it should) until one makes your 'Hey!' message appear when the event occurs. For incorrect event responses, where you have an event response that is mismatched with your event, a simple Game - Display Text may or may not work, depending on the event. In some cases, you may want to consider a slightly more useful approach of using the Game - Display Text action, which is to have the action convert some part of the trigger into a string and then display this string on the screen. (If you aren't familiar with the term 'string', strings just mean text (as opposed to integers, real numbers, unit types, or any number of other variables that you may encounter in the editor). You can use the Game - Display Text action to convert many of these variable types into text and then have it display these on the screen. This is an extremely useful method of debugging if you happen to have actions in your trigger that relate to one of these convertible variables. Common things that can be converted to text and shown on screen include:
To use any of these, instead of filling in the text in the text field where the message would normally go, you click on the drop down next to function. You can also display actual variables for any variables that are the same types as these but selecting the variable you want to display from the drop down next to variable in the action. Often when there are problems that can't be solved by simple Game - Display Text debugging, this is the best approach to finding the issue. If you have a trigger that is not working, sometimes the issue is related to the fact that some variable you thought you had assigned earlier in the programming sequence is actually not assigned to anything or perhaps mistakenly assigned to something else. Most of the time when you have an event response that seems to not be working in your trigger, this is the best approach for debugging the problem. In some cases, you can't use either of these approaches (often because your trigger is not failing because of events failing or one of the event responses failing). Sometimes the easiest way to determine if your triggers are working correctly is to use another tool. Often when I am editing triggered spells, I find it easier to use Create Special Effect to help me find the bugs, because points are not something you can convert into text and sometimes the sequence is more obvious when you use special effects. Both Create Special Effect actions (on a unit or a point) can be very useful, in part because you can create special effects on units as part of a trigger to see if a unit is being affected by an ability or if your trigger is targeting the right unit. I tend to use the ! effect on the overhead of units, but in reality you can insert any sort of special effect action on a unit to see if it is the correct unit (for example, you have assigned a variable and you want to test to see which unit is assigned to that variable - you can make a simple trigger that will create the effect on a unit when you type '-test' or whatever and it will show you the unit in question.) You can do the same thing with creating effects on points. One thing that is good to know about points is that if no point is assigned, the game will default to the center of the map. This means if you goofed somewhere, it is often a good idea to check out the center of the map when your event occurs and see whether or not you effect is occurring there as opposed to the point you expected it to be created. Debugging can be very time consuming, particularly if you are not a careful trigger person, who tests their triggers in stages to see if they have everything working before moving on to the next stage. I would highly recommend attempting to use this approach if you have the patience, because you will save yourself a lot of heartache later on if you debug after every several steps of your trigger and make sure that you haven't missed an event response somewhere along the way while the trigger is still small and finding the error is a simple task. There are very few examples that I can think of where you cannot use one of these three techniques to find bugs in your triggers. At the very least, you should be able to use these techniques to isolate which part of the trigger is failing and then when/if you need to seek help, you can make your guru's life a lot easier by having already narrowed it down from the simple stuff to something far more vexing. Some things simply take experience with the trigger editor to figure out and when it comes to those sorts of problems, you have to hope that you know someone who has been programming long enough to be able to get you out of the jam you are in or (failing that) you can always try to make your trigger in a different way. Sometimes the work-around approaches can actually spawn new or more interesting triggers. Whatever else, try not to become too frustrated with your triggers. |
|
|
| Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
| Thread Tools | |
| Display Modes | Rate This Thread |
|
|