I've come up with a more final - and far more powerful - implementation. It uses option 2 in regards to file naming, and allows for... not quite "anything you can imagine", but it's quite flexible. Multiple animations are supported, which can have different (and customizable) conditions. For example, you could have a trap with the normal main animation, a secondary animation that stops (or even disappears - or loops back to frame zero, then stops or disappears) when the trap is in use, another secondary animation that only plays while the trap is in use but continues until reaching frame 0 when the trap finishes... it's probably far more powerful than it needs to be, but it works well.
Currently, it supports telling the animation, based on the supported conditions, to pause, stop (differentiated by that stop also returns to frame 0), return to frame 0 then pause, play, or display the same frame as the primary animation (can be useful eg. for pickup skills). It can also show or hide the animation again based on these conditions - if the animation is told to hide, it remains visible until paused, allowing this to be combined with the "return to frame 0 then pause" feature.
I've decided to keep whatever animation would already currently exist, being defined as the "primary" one. The logic here - the primary one is the one that actually relates directly to physics. To use a trap as an example - how many frames the idling animation has is irrelevant to physics, but how many frames the active animation has is not. Therefore, it should be the primary one. Of course, backwards compatibility is another good reason for this.
The supported conditions, currently, are:
- Primary animation is on frame zero. This is supported on object types where frame zero is significant, eg. traps (including single-use), teleporters.
- Primary animation is on frame one. This is supported on object types where frame one is significant, eg. single-use traps, locked exits.
- Busy. This is supported on traps, teleporters and receivers. A teleporter or receiver will register as busy whenever the pair, as a whole, is in use.
- Triggered. This is supported on all object types that can, but don't always, animate (so it includes eg. entrances, locked exits, etc). The object will register as triggered while the primary animation is animating. Teleporters and receivers are NOT linked for the purpose of this one.
- Disabled. This is supported on traps (including single use, but a used single-use trap does not register as disabled - only a disarmed one does), teleporters and receivers (where it would register if no paired teleporter / receiver exists).
This is quite powerful, and can theoretically get very complex, but the vast majority of real-world use cases would simply need to copy / paste less than 10 lines from a default object that has similar secondary animation behaviour.
This does mean, secondary animation
metainfo files from the earlier experimental, won't work as-is (though they're generally very easy to convert).
Image files, on the other hand, can most certainly be used as-is under the new system - I didn't have to make a single change to any images I made for the earlier system.
This is obsolete, and is preserved here solely for those who are reading the topic at a later date. See a later post in this topic for up-to-date information.Define the primary animation the same way as it currently is. If you wish to nine-slice it, use the keywords CUT_LEFT, CUT_TOP, CUT_RIGHT and CUT_BOTTOM with integer values to indicate the border size on each side. Aside from these ones, only fields that were supported prior to this feature, can be used in this way.
Alternatively, you can define the primary animation inside a $PRIMARY_ANIMATION section. If doing this, the section works the same way as a general $ANIMATION section (for secondary animations). However, this is not backwards compatible. You can somewhat subvert this by defining the primary animation in
both ways - if you do this, the new version will disregard anything outside $PRIMARY_ANIMATION, while the old version will ignore anything
inside it. When defining the primary animation this way, you can use most of the new features supported on secondary animations too, although not all of them work on the primary animation.
You can then define secondary animations inside $ANIMATION sections. The following lines can be used with a secondary animaton:
FRAMES - Indicates the number of frames in the animation.
NAME - Indicates the filename suffix. If this field is "idle", on an object called "trap", the animation will be loaded from "trap_idle.png". If this is empty, on an object called "trap", it will load from "trap.png" (not "trap_.png") - generally, the empty name would be used for the primary animation (but doesn't have to be).
COLOR - Indicates a color name, taken from the current theme, to recolor the animation using. If this is blank, the animation is not recolored.
EDITOR_FALLBACK - This animation will be displayed (together with the primary animation) in the editor, when using the "primary + one secondary rendered by editor" fallback. This cannot be used on the primary animation (always displayed in editor), and if used on multiple secondary animations, priority goes to the animation listed later in the file. If not specified on any animation, the first animation in the file is used.
HORIZONTAL_STRIP - Doesn't need a value. If present, the animation strip will be loaded as a horizontal strip.
Z_INDEX - Indicates the order to draw the animations in. Lower numbers get drawn first. If not specified, it defaults to 0, except on the primary animation, where it defaults to 1.
INITIAL_FRAME * - Indicates the frame number the animation should start on. Set this to -1 to start on a random frame. Doesn't work on primary animation for object types where specific frames are significant to physics, but does on those where it isn't.
OFFSET_X - The animation will be offset horizontally by this amount from the object's position.
OFFSET_Y - Same, but vertical.
CUT_TOP - The size of the top edge when nine-slicing.
CUT_RIGHT - Same, for right edge.
CUT_BOTTOM - Same, for bottom edge.
CUT_LEFT - Same, for left edge.
STOP - If no trigger condition otherwise is fulfilled, the animation will stop (revert to frame 0 and stop animating). Doesn't work on primary animation.
PAUSE - If no trigger condition otherwise is fulfilled, the animation will pause (stop animating, but stay on the current frame). Doesn't work on primary animation.
LOOP_TO_ZERO - If no trigger condition otherwise is fulfilled, the animation will continue until reaching frame 0, then pause. Doesn't work on primary animation.
MATCH_PRIMARY_FRAME - If no trigger condition otherwise is fulfilled, the animation will sit on whatever frame the primary animation is on. Doesn't work on primary animation.
HIDE - If no trigger condition otherwise is fulfilled, the animation will be invisible when not animating (matching the primary animation's frame counts as animating). Doesn't work on primary animation.
* The older keywords PREVIEW_FRAME and RANDOM_START_FRAME still work when defining the primary animation in the main segment, but don't work in $PRIMARY_ANIMATION or $ANIMATION segments.Inside the $ANIMATION segment (this does
not work for the primary animation, even when using a $PRIMARY_ANIMATION segment), you can define trigger conditions which specify when the animation will animate and/or be visible. These are defined inside a $TRIGGER segment, which can contain the following lines.
FRAME_ZERO - Value should be "true" or "false". The trigger will be fulfilled if, on an object that supports it (any where frame zero is significant to physics), the primary animation is on frame zero (or not on frame zero, if "false"). If the keyword is absent altogether, being on frame zero has no effect either way.
FRAME_ONE - Same; condition is that primary animation is on frame one, supported on any object where frame one is significant to physics. Pickup skills instead interpret this as "not frame zero".
BUSY - Same; condition is that object is busy. Supported on traps (including single-use traps), teleporters and receivers.
TRIGGERED - Same; condition is that object is in triggered state. Supported on all objects that have triggered animations (not that simply switch between two frames, eg. splitters).
DISABLED - Same; condition is that object is disabled. Supported on traps (including single-use traps), teleporters and receivers. Note that a single-use trap that has been used, does [b]not[/b] count as disabled - only [i]disarmed[/i] traps do.
HIDE - If present, when conditions are fulfilled [b]and[/b] animation is paused or stopped, the animation will be hidden altogether.
STATE - Defines what animation behaviour the animation should have when the conditions are fulfilled. Options are "PLAY", "PAUSE", "STOP", "LOOP_TO_ZERO" or "MATCH_PRIMARY_FRAME".
A condition on an object that doesn't support the condition, always registers as false.
In regards to the editor's fallback: If you want the fallback for an object to be "don't display
any secondary animation", insert the line "EDITOR_FALLBACK_NONE" somewhere in the main segment.
NOTE: Editor fallback indicators don't work in the current exp build, but they've been implemented in the source. As a side effect of these changes, objects with recoloring masks (which are now implemented as recolored secondary animations) are now slightly more efficient. Previously, these were reloaded any time a new level was loaded, unless the new level used the same theme as the previously loaded level. Now, the "keep existing copy" test is based on the specific color rather than the theme (so two different themes with the same color = no reload), and the unmasked image is kept in memory with the image just being re-masked rather than the entire object reloaded from disk.
On top of that, I added another nice feature for resizable objects - you can now have a "nine-slice" type resize, which recognizes corners and edges. I'm not sure of the normal term for this or how to describe it, so here's an image - notice the lack of the usual roughness updrafts have when resized vertically?
(The squasher trap does indeed lack a secondary animation at this point. The other trap, however, has one - it's just not noticable in a screenshot. The wheel
always rotates, unless the trap has been deactivated.)
I have uploaded a new experimental build that includes both these features. Another thing to check out - try using clear physics mode in the new experimental build.
