Edit Plans |
Plans can be used to perform very specific tasks within the context of a particular layer in a particular map. When provided with coordinates in the map editor, a plan can even implement rules for a specific location on a layer. That doesn't necessarily mean, however, that a plan can't be used for global purposes. Since a project can have an "overlay" map defined (a map which is always active in the foreground regardless of which map is the primary focus at the moment) plans can be added to this map, and will always be applied as long as the overlay map is active. One kind of plan that might fit well in that context is a plan that increments a global animation counter (that is linked to all animated tiles).
Two different aspects of plans are edited in two contexts:
To open the edit plans window, you can:
There are two levels to understanding the process of editing plans. This page will describe the user interface itself - generally how plans are edited in this window. However, the more interesting detailed aspects of editing plans are in the individual rule functions that a plan can use. For more information about details of the individual rule functions that a plan can use, see:
The root page of the coding reference summarizes the process of using the individual rule functions. The remainder of the reference contains detailed descriptions of individual functions.
A plan name must be unique among all plans on the same layer. Names must begin with a letter and contain only letters, digits and spaces.
In most cases, a plan should not care when it is executed in relation to other plans, so this setting can be ignored. However, if such a case does arise, this value can be set to control the sequence in which plans are processed. Plans with higher numbers will execute after plans with lower numbers.
A toolbar appears above the hierarchical list of rules to manage the creating, deleting and moving of rules in the list. The same commands appear in the "Plan" menu.
This displays a list of rules associated with the current plan in a hierarchical view. When a rule represents a condition or a loop that affects a number of nested rules, the nested rules are indented under that rule and can be collapsed into it. Note that a condition (a rule of type "If") can also include an "Else" rule, which defines a series of rules to apply when the "If" condition was false. Since the else also depends on the same condition described in the "If" rule, it (and the statements applying to it) is included as a nested rule along with the rest of the rules nested in the condition. That may be difficult for programmers used to writing indented code to get used to because often times code is written with the "Else" being un-indented to the same level as the "If". But when displaying the rules in a hierarchy it truly is part of the same condition, and therefore is nested within the condition. (The code generated by the rules when the project is compiled *is* indented as a programmer would expect, however.)
The name of a rule is used to uniquely identify the rule within the plan. Therefore the name must be unique among all rules within the same plan. A rule name is not constrained by the same limitations as most names because it does ot represent the name of an object that gets converted into source code. The name of a rule simply becomes a comment in the generated code when the project is compiled. The name of a rule can contain any characters that can be typed into a single line. Some good guildelines or considerations for naming rules will help to quickly understand rules when looking at them in the rule list:
Of course you are free to devise your own guidelines as well, but these guidelines are used in the included samples and following them will make your rules consistent with any imported samples.
This will exclude the rule from being included in the generated project. It will be treated as if it does not exist when compiling and running the project. One reason to do this is to easily turn on and turn off debugging rules. There may be a rule to give the player some object or teleport the player to a certain location to make testing easier. Of course such a rule should be turned off (suspended) when compiling the final project. Another reason to do this may be when creating rules to serve as a template that might be used in other projects. If there is a rule that specifically applies to supporting the use of ladders, but the project doesn't use ladders, the rule can be suspended and then only turned on when using the template to create a project that implements ladders.
Note: It is strongly recommended when suspending a rule that contains nested rules, all the nested rules also be suspended. Unexpected behavior may occur if a rule is suspended without suspending all of the rules nested within it. See the "Toggle Suspend for This and Child Rules" command above.
There are 8 fundamental classes of rules that can be defined using the first dropdown list. If the descriptions of these types seem overwhelming or confusing, skip them for now and just try out some examples (look at some existing sample rules in other projects). These should be relatively self explanatory, but you can refer to these descriptions for detailed information about how they behave and why they exist. Before proceeding, let's establish some terminology. A "Rule Type" is one of these 8 types selected in the first dropdown list. And the term "Rule Function" (described in more detail below) will be used to refer to a specific function selected in the second dropdown list.
Do | This simplest of rule types indicates that some action will be performed rather than defining a condition or loop. Note that rule functions that are normally associated with "If" type rules can also be used with "Do", and any action that they perform will be executed, but the result will be ignored instead of used to define a condition. |
If | This defines the beginning of a condition. Rules that come after an "If" rule will be nested within it until one of the rules uses the "End If" checkbox to end the condition. The set of rule functions available with an "If" type rule is limited. Only functions that return a true or false value can be used with "If". (In the source code, the function must return "bool".) When the rule returns success/true, the conditions nested in the "If" conditions will also apply, otherwise they are skipped. (There are exceptions, see "Else" below.) |
And | This rule type can only be used immediately after an "If", "ElseIf", "While", "And" or "Or" type rule, to extend the condition. The rules contained inside the condition will only be applied if all the rules combined with "And" return success/true. The same list of rule functions will be available for this rule type as are available for the "If" rule type. |
Or | This rule type can only be used immediately after an "If", "ElseIf", "While", "And" or "Or" type rule, to extend the condition. The rules contained inside the condition will be applied if any one of the rules combined with "Or" return success/true. The same list of rule functions will be available for this rule type as are available for the "If" rule type. |
ElseIf | This rule type can only be used within a block of rules started by "If" or another "ElseIf". It begins a new condition block nested yet another level below that of the current rule. The condition is only checked when the initial condition failed (returned false), and the statements nested under this rule are only applied if the initial condition failed and the condition specified in this rule succeeds (returns true). Because the statements are nested another level, you must remember to include at least two End If rules, one to finish the nested condition and one to finish the initial condition. If there are rules between the end of the inner condition and the end of the outer condition, they will be executed when the outer condition's expression is false regardless of the result of the inner condition. |
Else | This rule type can only be used within a block of rules started by an "If". It causes the rules within the block after this one to be applied only if the condition specified with "If" failed. This is actually more like an "Else Do" than a plain "Else" because it also includes the ability to perform a function within the same rule. |
End | Normally when you create a rule, in order to make it the last rule in a nested block of statements (the last rule that depends on an "If" condition, for example) you can check the "End If/End While" box. However, there is no way to indicate that a statement should be the last statement of two nested conditions (for example, the end of an "If" block as well as another "If" block containing that). That's the purpose of the "End" rule type. It's the only rule type that doesn't perfom any action in itself (there's no rule function associated with it). It just ends a block of nested statements that was started by an "If", "ElseIf" or "While". |
While | This begins a block of statements that will execute repeatedly ("loop") as long as a rule function returns success/true. This can be used in conjunction with "And" and "Or" rule types to form complex conditions that must be met to continue the loop. The same list of rule functions will be available for this rule type as are available for the "If" rule type. It cannot be used in conjunction with ElseIf or Else rules. In other words, you can nest a "While" inside and "If" or an "ElseIf" block, and you can nest an "Else" or "ElseIf" rule inside an "If" block contained within a "While", but you cannot directly include an "Else" or "ElseIf" rule within a "While" block. Be careful with this rule type because it could easily result in endless loops that will make the game freeze if used incorrectly. It can also make the game run slowly. |
This checkbox can be used with the "If", "ElseIf", "While", "And" or "Or" rule type to invert the result of the rule. For example, you can check the "Not" box on a rule that reads "If - IsInputPressed" and then the rules contained in this block will only apply when the specified key is not pressed.
The second dropdown list on this form represents the rule function associated with the rule. Here you can select one of the many functions available to define plan behavior, including functions defined yourself by editing files in the "Source Code" folder of the project. For more details about defining your own rule functions, see the coding reference. A number of pre-defined functions exist to perform simple comparisons, calculations and copying of values:
- | Subtract the "left operand" in the second parameter from the "right operand" in the first parameter and put the result in the variable provided in "Output to". |
!= | Compare the values of the first two parameters and return true/success if they are different, or false/failure if they are equal. |
+ | Compute the sum of the first two parameters and output the result to the variable provided in "Output to" |
< | Compare the values of the first two parameters and return true/success if "left operand" is less than "right operand", or false/failure otherwise. |
<= | Compare the values of the first two parameters and return true/success if "left operand" is less than or equal to "right operand", or false/failure otherwise. |
= | Copy the value provided in the first parameter to the variable provided in "Output to" |
== | Compare the values of the first two parameters and return true/success if they are equal, or false/failure if they are different. |
> | Compare the values of the first two parameters and return true/success if "left operand" is greater than "right operand", or false/failure otherwise. |
>= | Compare the values of the first two parameters and return true/success if "left operand" is greater than or equal to "right operand", or false/failure otherwise. |
When defining an "If", "While", "And", "Or", "ElseIf", or "While" type rule, the list of functions displays only rules that return a true or false value (sometimes thought of as success or failure). These rule functions are referred to as "boolean" functions. When defining a "Do" type rule, all rule functions are available for use, and if a boolean function is used, the function will perform its usual work (if any) but the result will simply be ignored. This might be useful because some functions actually do something that affects the game and then return a value indicating some true or false value.
After selecting a function, some or all of the parameter fields below will open up for input. Each function has its own set of parameters, and depending on how many parameters it uses and what types of parameters they are, the boxes below will become available and present different options in the dropdown lists. The box immediately below the rule function box will also display a brief description of what the function is and how to use it. Furthermore, if the function can output a number, the "Output to" box will open up and allow you to select a counter, plan parameter or sprite parameter in which to store the result.
If there is an error compiling the project or processing the function name (it's possible to type an arbitrary name into the function field in case you want to call an undocumented function) then the description field will contain a generic error message and all the parameters will be available for input, but without names. This is to allow a function to be specified even if the environment doesn't know that it's valid.
After a function is selected, a brief description of the function is displayed in the box below. Don't forget that this box can scroll and there may be more information than is initially displayed. Usually a description will also include information about the meaning of the parameters and output value if any.
Many rule functions can accept parameters that specify details about how they should operate or what they should affect. In most cases a helpful list of suggested values is provided in the dropdown list for each parameter based on the type of the parameter, but any value can be manually typed because not all possible values can be predicted. For example if you want to call a function to display a message, you obviously won't be able to select the message from the dropdown list, you'll have to type it in. That brings up another important topic. When providing text for a parameter (also known as a "string") you must enclose the text in quotes. This (indirectly) allows you to include special formatting characters in the text. These are inserted with "escape codes". Here are the most important escape codes with which you should be familiar when entering a string into a parameter value:
Code | Result | Example parameter | Example result |
---|---|---|---|
\r\n | Inserts a line break | "Display me on\r\nTwo Lines" | Display me on Two Lines |
\" | Embeds a double-quote in the text | "He said his name was \"Little John\"" | He said his name was "Little John" |
Many other parameter types are available when defining rules for plans. Below is a list, but it is by no means comprehensive because the list is customizable. It can be expanded by adding your own enumerations in the game project's source code folder:
Type Name / Summary | Description/Source | Example |
---|---|---|
Keypress | Preset list of static values, each value representing a key on the keyboard | Key.A |
Color Channel | Preset list of color channels that can be affected (Red, Green, Blue or Alpha). | PlanBase.ColorChannel.Blue |
Relative Position | Preset list of pre-defined corner or centered positions within a rectangle. | RelativePosition.BottomCenter |
Sprite | Can refer to any sprite instance. The dropdown list will contain a list of sprites on the plan's layer. | m_ParentLayer.m_Platform_1 |
Sprite of type <X> | Some custom rules added for a specific project may refer to a specific type of sprite. In this case, the dropdown list will only display sprite instances for a particular sprite definition. | m_ParentLayer.m_Platform_1 |
Sprite Collection | Displays a list of sprite categories defined in the project. | ParentLayer.m_SpriteCategories.Enemies |
Point | Displays a list of the first coordinates of each plan in the layer; only plans with exactly 1 coordinate are listed. A point representing the mouse position is also listed. | m_ParentLayer.m_Door_1[0] |
Plan | Displays a list of all the plans on the same map. | m_ParentLayer.m_Door_1 |
Counter | Displays a list of counters in the project. | Counter.Lives |
Bar drawing style | Displays a preset list of ways that a bar can be drawn. | PlanBase.DrawStyle.RepeatRightToCounter |
Color | Displays a preset list of colors. | System.Drawing.KnownColor.Crimson |
Sprite InputBits | Displays a preset list of inputs that can affect a sprite. | SpriteBase.InputBits.Button1 |
Map | Displays a list of maps defined in the project. (They are referred to by type instead of specific map instances because it's conceivable that you could have multiple copies of the same map loaded.) | typeof(Level_1_Map) |
Sprite Definition | Displays a list of Sprite Definitions. This differs from the other sprite parameter types because they require a specific sprite instance on the layer whereas this lists Sprite Definitions which are independent of the maps. | typeof(Sprites.Explosion) |
Sprite State | Displays a list of all states in a particular sprite (if no previously specified parameters have specified a sprite, this won't display a list). | (int)Sprites.Player.State.Left |
Integer | Displays a list of all counters, all parameters of any sprite that has been specified in another parameter, and miscellaneous other shared integer variables (CurrentView, for example, represents the currently active view number in projects where there are multiple views, and is included in this list). Some rules may want to alter a parameter value that is passed in (receive the parameter "by reference" so it can be changed). In these cases the values in the list are preceded by "ref" indicating that the variable that is provided may have a different value afterwards (failing to pass a variable by reference where a reference is required will result in an error.) Counters cannot be provided to a parameter requiring a reference to an integer, but another version of the rule function may be available that accepts a counter, or the value can subsequently be copied into the counter with an "=" rule. | Counter.Lives.CurrentValue |
Tileset | Displays a list of Tilesets defined within the project. | Tileset.FireText |
Some functions output integer values. For those that do, this field is enabled to allow you to specify where to put the result. If you don't need to put it any place permanent, but just want to use it in a subsequent rule (if nothing else interferes) you can use a temporary variable that is provided by default named SharedTemp1. If necessary, you can add more such shared variables by adding them after "SharedTemp1" in PlanBase.cs in the SourceCode folder. Variables declared with "static" are shared among all plans while variables declared without "static" are specific to the current plan and can be set with a particular initial value in the map editor. Any counter value and many other values listed after "Integer" type parameters above are also available.
Whereas parameters are all required, the "Output to" box can be left blank if you don't care about storing or using the result of a rule function.
If you want to mark this rule as the last rule in a block that was started with an "If", "ElseIf", or "While" type rule, check this box. Note that if you need to end two (or more) blocks at once, you will need to also add an "End" type rule after this. The "End" type rule will allow you to add another rule that has no function or parameters, and just checks the "End If / End While" box.
Take care to match every "If", "ElseIf" and "While" with one and only one matching rule that has the "End If / End While" box checked. The code generator will automatically close the remainder of your blocks if you have some unfinished blocks at the end of your plan, but other failures to match the beginnings of blocks with an end could result in unwanted behavior. One occasion when this can be particularly tricky is when deleting a rule that begins or ends a block. Be careful to find the corresponding rule at the other end of the block and delete or adjust it appropriately too.