For the sake of extensibility and legibility,
events are not hard-coded into the
compiler, but rather are stored in an
external file in the main directory,
events.res. The file's original format spec
appears below.
To promote a more extensible, less
hard-coded-strings-flipping-everywhere event system, ENIGMA R4
introduced a file containing event names and info, in order of
execution.
Because of the way Game Maker stores events, names need paired up with
integer IDs and sometimes Sub-IDs. Because of the way ENIGMA stores
event code, IDs and sub-IDs need paired up with function names. This
format deals with all of that.
The basic layout of the format is
event_function_name: ID
Mode: MODE DESCRIPTOR
MODE-SPECIFIER: SPECIFIER
Super Check: EXPRESSION
Sub Check: EXPRESSION
In the above, ID is an integer, defined in Game Maker from 0-11 but open
to extension. This is how the event will be identified by the IDE, and
by ENIGMA initially.
Mode: Sets how the event is represented for iteration in ENIGMA.
Behavior is assigned according to MODE DESCRIPTOR.
MODE DESCRIPTOR can be one of the following non-numeric constants:
Mode |
Description |
|---|---|
Inline |
The event is added right into the list of events to be iterated. This is mostly for
|
Stacked |
The event appears once in the event list, and instances are expected to register
|
Special |
The event is given entirely different behavior based on the value of the second ID.
|
Spec-none |
This is for specialized events (by second ID) that don't get added to the event list at all. |
None |
This is for whole events that don't get added to the event list at all. |
MODE-SPECIFIER is a named attribute specific to Mode. Depending on
the value of mode, certain attributes may be
required:
| Mode | Parameter |
|---|---|
| Inline | Nothing needs to be given. |
| Stacked | The derived function names need to be given. |
| Special | A Case: attribute needs given, coupled with the second ID integer as SPECIFIER. |
| Spec-none | Same as special. |
| None | Nothing needs to be given. |
This format allows setting additional code attributes for the event,
such as checks and default code
snippets.
| Attribute | Description |
|---|---|
| Super Check | Specifies an EXPRESSION to be used to determine whether the event as a whole should be iterated (It is iterated if the expression is true). For example, if the event is Keyboard A, the list shouldn't be iterated at all if the 'A' key isn't held. Such conditions are given in the format defined by EXPRESSION. |
| Sub Check | Similar to super check, but executed by each instance each event and is therefore simply added to the beginning of each event code. Its conditions are also given in EXPRESSION format. The event is performed if EXPRESSION is true. |
| Default | Gives code that is used in place of user code for an event if none is specified. For instance, in GM, the draw event defaults to rendering the sprite of the current instance if no draw code is given. |
| Constant | Gives code that is always present at the beginning of the event, whether the user has specified code or not. In GM, the step event always propagates movement variables at the beginning. |
| Prefix | Specifies code to be prepended to user code, if any user code was specified. Otherwise, the code given here is ignored. Constant code is prepended in either case. |
| Suffix | Specifies code to be appended to user code, if any user code was specified. If the event returns before this code is reached, it will not be executed. This was added as a complement to prefix without a premeditated use case. |
| Instead | Code given here is used in place of the traditional event loop. This code is not inserted into any event, but instead into the code that handles event sequences. For example, the draw event specifies screen_redraw() instead of iterating manually (to allow for depth and views to be accounted for). |
This format is more complicated than it may originally sound. Its
behavior is based on the first non-white character in the string. If
followed by a block, {}, EXPRESSION is copied as-is and is assumed to
contain valid return statement(s). In the case of Super Check, the
EXPRESSION should always return true or false. In the case of Sub Check,
the event is performed if nothing is returned; no return statement is
reached.
Otherwise (if EXPRESSION is not given as a {block}), an if statement is
generated by simply parenthesizing the EXPRESSION.
In the case of Sub Event, the EXPRESSION is negated as well. This is
because the format requests a scenario in which the event should be
executed, while the if() will instead exit the event when the expression
is true. If the EXPRESSION given to a Sub Check has a negation symbol at
the beginning, the symbol is automatically stripped instead of double
negated.