Animationscript: Difference between revisions
No edit summary |
|||
| Line 377: | Line 377: | ||
[[Category:Openbor]] | [[Category:Openbor]] | ||
[[Category:Model]] | [[Category:Model]] | ||
[[Category:Script]] | [[Category:Script]] | ||
[[Category:Animation]] | |||
[[Category:Script Events]] | |||
Revision as of 18:54, 17 August 2026
animationscript defines OpenBOR's animation-update script. The engine executes it whenever an animating entity enters or is moved to an indexed animation frame, including normal advancement, loop transitions, animation starts, and explicit frame updates.
The command name is technically exact - the compiled script belongs to the model's animation system and may service every animation in that model. Conceptually, its runtime role is a frame-update hook. It provides the current entity, animation, and frame index at the precise point where the indexed animation state changes.
This placement makes Animationscript one of OpenBOR's most flexible action-building tools. Creators may launch effects, branch attacks, coordinate linked entities, modify velocity, manage animation phases, create cancels, spawn projectiles, apply state changes, or replace native frame behavior before the engine finishes processing the new index.
Frames and Animation Data
OpenBOR uses the term frame for each indexed step presented to creators, and the model frame command adds such a step to an animation. Internally, however, there is no standalone frame object containing a collection of properties.
Why No Frame Object?
OpenBOR deliberately eschews the object-oriented convention of conceptual frames as a discrete objects in favor of a data-oriented architecture. This is an engine-level optimization rather than a missing abstraction.
Each conceptual frame may comprise dozens of possible properties, while a single animation may contain dozens of frame positions and every loaded model may contain dozens of animations. Animation-frame data is sparse and highly heterogeneous, making a conventional fixed-layout frame representation potentially wasteful.
OpenBOR instead keeps frame-specific data as arrayed members of the owning animation, keyed by a shared frame-position index. This avoids allocating a complete record for every conceptual frame while retaining direct access to the properties that actually define each indexed position.
Each animation owns parallel property arrays. Sprite, delay, movement, offset, collision, sound, draw method, vulnerability, and other frame-specific data use the same zero-based index across their respective arrays. The frame local supplied to Animationscript is this shared frame-position index.
Animationscript is therefore best understood as code executed when an animation updates its current indexed position, rather than as a callback belonging to a separate frame object.
Syntax
animationscript {path}
# Default
# No external animation-script source
{path}- Path to an OpenBOR Script source file containing animation helper functions, constants, and optional lifecycle functions.- The command belongs in a model definition.
- The external source file does not define
main(). - OpenBOR generates the Animationscript
main()function while loading the model. - Model
@cmdand@scriptcontent is merged into the generated entry point. - The compiled script is shared by the model, while each entity supplies its own execution context and locals.
Models may omit the animationscript command when they only call built-in functions through @cmd or use animation-level @script. OpenBOR still generates and compiles the required animation script from that model content.
Example model header:
name example_character
type enemy
animationscript data/scripts/example_animation.c
External source file:
void set_animation_phase(int phase)
{
void self = getlocalvar("self");
setentityvar(self, "animation_phase", phase);
}
void clear_animation_phase()
{
void self = getlocalvar("self");
setentityvar(self, "animation_phase", 0);
}
The file supplies callable functions, but no main(). OpenBOR builds the entry point that calls these functions from the model's animation instructions.
Helper source may also be embedded directly:
animationscript @script
void set_animation_phase(int phase)
{
void self = getlocalvar("self");
setentityvar(self, "animation_phase", phase);
}
@end_script
Calling Functions with @cmd
@cmd converts a model instruction into a script function call tied to the immediately following frame command.
anim attack1
@cmd set_animation_phase 1
frame data/chars/example/attack_01.png
@cmd set_animation_phase 2
frame data/chars/example/attack_02.png
@cmd clear_animation_phase
frame data/chars/example/attack_03.png
OpenBOR generates the frame-index checks and function calls during model loading. In this example, the phase values become 1, 2, and 0 as the animation enters indexes 0, 1, and 2.
Several @cmd instructions may precede the same frame. Their calls execute in model-source order.
Arguments are compiled as script expressions. Values may include integers, decimals, quoted strings, constants, NULL(), getlocalvar("self"), or other expressions accepted by the script parser.
Inline @script
Model @script inserts code directly into the generated Animationscript entry point for the current animation.
anim walk
@script
void self = getlocalvar("self");
if(frame == 0)
{
setentityvar(self, "walk_cycle", 1);
}
@end_script
frame data/chars/example/walk_01.png
frame data/chars/example/walk_02.png
frame data/chars/example/walk_03.png
Unlike @cmd, placement of @script beside a particular frame does not bind it to that frame. Inserted code is evaluated on every animation update within the containing animation. Use the automatically generated frame variable when behavior should apply only to selected indexes.
The generated entry point already declares frame and animhandle. Inline code may use those names directly. Retrieve self or animnum with getlocalvar() when needed.
Functions cannot be declared inside a model @script block because the block is inserted inside generated main(). Place reusable function definitions in the external or header-level Animationscript source.
Generated Entry Point
During model loading, OpenBOR performs the following work:
- Reads the source supplied by
animationscript, when present. - Collects animation-level
@scriptblocks. - Converts each
@cmdinstruction into a function call guarded by concrete animation and frame indexes. - Generates
main()with localframeandanimhandlevariables. - Merges generated animation routing into the helper source.
- Compiles the completed script once for the model.
Creators should not supply their own main(). The engine-owned entry point is what connects model animation data, @cmd, @script, and runtime frame updates.
Generated source for animation commands is written to Logs/ScriptLog.txt. That file is useful when an @cmd call, argument, inline block, or generated line fails to compile.
Runtime Timing
When OpenBOR updates an entity's animation frame, the relevant order is:
- Validates the requested index against the current animation.
- Makes the entity the active execution subject.
- Assigns the requested index as the entity's current animation position.
- Calculates the next animation timestamp from the new index's delay and clears frame pause state.
- Populates
self,animnum,frame, andanimhandle. - Executes the current model's Animationscript.
- Executes the entity's default-model Animationscript when the current model differs from its default model.
- Stops processing the old animation update when script changed the animation or frame index.
- Otherwise applies remaining native on-entry effects for the index.
Native effects after Animationscript include configured movement, base adjustment, facing reversal, weapon changes, quake, sub-entity operations, child spawning, sounds, jump velocity, and legacy projectile launching.
The new frame index is already current when script begins. Frame-indexed collision, sprite, draw, delay, and other animation data can therefore be inspected through the current entity and animation. Remaining native on-entry operations have not yet executed.
Interrupting Native Frame Processing
OpenBOR records the animation and requested frame before running Animationscript. After script returns, the engine compares those values with the entity's current animation and frame.
Changing either one interrupts the remainder of the original frame update. Native movement, flip, weapon, quake, spawn, sound, jump, and projectile instructions belonging to the abandoned frame do not execute afterward.
This behavior supports clean branching and replacement:
| Pattern | Use of animationscript
|
|---|---|
| Conditional attack branch | Check input, hit state, meter, target position, or project variables, then enter another animation before the old frame launches its remaining native effects. |
| Dynamic action phase | Mark startup, active, recovery, invulnerable, armored, cancelable, or vulnerable phases as specific indexes begin. |
| Motion control | Adjust velocity or position before native frame movement and jump impulses are applied, or replace the frame to suppress them. |
| Synchronized choreography | Move, bind, animate, or release targets and helper entities at exact animation indexes for throws, team attacks, mounts, cut-ins, or transformations. |
| Custom effect routing | Spawn projectiles, particles, sounds, camera effects, trails, decals, or interface feedback from reusable helper functions. |
| Procedural animation behavior | Choose alternate timing, sprite state, direction, movement, or follow-up logic from runtime conditions rather than fixed model data alone. |
| State cleanup | Clear temporary flags, armor, invincibility, bindings, overlays, or resources at the exact animation update where their phase ends. |
| Debugging and telemetry | Record animation transitions and frame indexes, inspect unexpected branches, or expose current action phases to development tools. |
Frame-changing functions may immediately start another animation update. Scripts that repeatedly reset the same animation or redirect to a frame whose code redirects back can create recursive execution or an endless transition chain. Guard such branches with state or a condition that becomes false after the transition.
Execution Frequency
Animationscript responds to indexed animation updates, not display refresh or every entity update.
| Situation | Animationscript execution | Notes |
|---|---|---|
| Normal animation start | Yes | Entering a newly started animation normally updates index 0 immediately.
|
| Natural frame advance | Yes | Runs when the configured delay expires and animation processing advances to the next index. |
| Loop transition | Yes | Runs when the animation moves from its loop end to the configured loop start. |
| Frame held for several logic or display updates | No repeated execution | Delay controls how long the current index remains active; Animationscript does not poll throughout that hold. |
| Infinite-delay frame | Once on entry | No further execution occurs until another operation changes or updates the animation frame. |
| Stopped non-looping animation | No further execution | Reaching the end disables animation advancement unless another operation starts or updates animation state. |
updateframe()
|
Yes, while the entity is animating | Explicitly routes the requested index through native frame-update processing. |
| Native land-frame, drop-frame, bind-frame, or grab-frame adjustment | Yes, while animating | These systems explicitly call the same frame-update path. |
| Direct raw animation-position assignment | No generated update by itself | Directly changing a property is not equivalent to updateframe() and does not apply the full frame-entry path.
|
| Synchronized animation change retaining the current index | No immediate fresh update | Native synchronization may transfer the existing position without re-entering frame-update processing. |
| Entity frozen or paused without advancing | No repeated execution | The script resumes when animation processing reaches another frame update. |
Repeated visits to an index are separate updates. Looping back to frame 0, explicitly calling updateframe(), or later re-entering the same animation may execute its @cmd and @script code again.
Local Variables
| Local variable | Type | Value |
|---|---|---|
self
|
Entity pointer | Entity whose animation frame is being updated. |
animnum
|
Integer | Current logical animation identifier, such as a named ANI_* constant. The same logical identifier may refer to different animation objects on different models.
|
frame
|
Integer | Current zero-based index shared by the animation's frame-specific property arrays. |
animhandle
|
Integer | Unique runtime identifier of the concrete loaded animation object. OpenBOR uses this value to route generated @cmd and @script sections to the correct animation.
|
Use animnum for semantic comparisons against ANI_* constants. Use animhandle only when concrete animation identity matters. Runtime handles depend on loaded animation allocation and should not be hardcoded or stored as portable project data.
Assignments to event locals do not directly change the entity or animation. Use animation, entity, and frame-update interfaces for native changes.
The event does not provide attacker, damage, tag, blocked, or other combat-event locals. Read relevant entity or project state when animation behavior depends on prior combat context.
@cmd and @script Comparison
| Feature | @cmd
|
@script
|
|---|---|---|
| Scope | Immediately following frame command | Every frame update in the containing animation |
| Generated form | Function call guarded by animation handle and frame index | Inline code guarded by animation handle |
| Best use | Short, reusable, precisely timed function calls | Conditional logic evaluated throughout an animation |
| Function definitions | Calls existing functions | Cannot define functions inside the inserted block |
| Frame test | Generated automatically | Creator supplies a frame condition when needed
|
External helper functions keep complex logic reusable and testable, while @cmd provides compact timing in model data. Inline @script is useful when the decision itself needs to be evaluated at each animation update.
Return and Exit Behavior
Animationscript has no event acceptance or cancellation return value. Returning a value does not confirm a frame, while returning from generated or inline code only ends that script execution path.
Stopping script execution does not by itself stop native processing for the current frame. OpenBOR automatically interrupts the remaining old-frame operations when script changes the entity's animation or frame index. Other state changes affect later native instructions according to the rules of those individual systems.
Functions called through @cmd may return values for use by other script code, but the generated standalone call does not consume the returned value.
Model and Default-Model Execution
OpenBOR executes the Animationscript belonging to the entity's current model first. When model switching has made the current model different from the entity's original default model, OpenBOR also executes the default model's Animationscript afterward.
Both executions receive the same entity, logical animation ID, current frame index, and concrete animation handle. Generated animation-handle guards determine which model-specific @cmd and @script sections match the concrete animation.
This behavior is based on current and default model ownership, not on a special model name. Naming a model global_model does not automatically invoke it for every entity. Shared helpers may instead be included in participating animation-script sources.
Lifecycle functions such as oncreate() and ondestroy(), when present, follow script-instance creation and destruction. They do not run on every animation frame update.
Related Scripts
| Script | Runtime cadence | Primary use |
|---|---|---|
animationscript
|
When an animating entity enters or is moved through an indexed animation frame | Precisely timed action logic and animation-state transitions. |
| Updatescript | Entity update cadence | Continuous entity behavior that should not depend on animation advancement. |
| Thinkscript | Entity thinking cadence | AI decisions and periodic behavior selection. |
| Ondrawscript | Entity drawing cadence | Visual preparation and draw-time behavior. |
| Onpainscript | Native pain entry | Reaction logic when an entity successfully enters standing pain. |
| Onfallscript | Native fall entry | Reaction logic when an entity successfully enters fall. |