Jump to content

Binding

From OpenBOR

Binding is OpenBOR's one-way synchronization system for attaching one entity to another. The binding entity can follow a target's position, drawing order, direction, animation, and indexed animation position while retaining its own model, scripts, collision data, state, and other entity properties.

Binding is essential for layered visual effects, weapon trails, carried objects, grappling sequences, synchronized helpers, multipart enemies, modular costumes, mounted characters, status graphics, composite entities, and any system where one independent entity must remain aligned with another in real time.

The relationship is always described from the binding entity's perspective:

  • The binding entity owns the bind properties.
  • The binding entity attaches itself to one target.
  • One entity can have only one bind target at a time.
  • Any number of entities may bind themselves to the same target.
  • The target does not gain ownership or native control of the binding entity.

Binding is separate from owner, parent, child, grabbing, link, and platform relationships. Setting a bind target does not establish any of those other relationships.

Core Concept

Every entity contains one bind-property object. The object exists for the entity's lifetime, even when binding is inactive. BIND_PROPERTY_TARGET activates the relationship by holding another entity pointer.

When the target is empty or null, OpenBOR performs no binding update. Configuration, offsets, animation selections, metadata, direction adjustment, and relative sort ID remain stored, allowing them to be reused when another target is assigned.

Destroying a target automatically clears every active entity bind pointing to it. Clearing the target manually cancels binding without removing either entity.

Self-targeting and cyclic binds should be avoided. Relative offsets and sort adjustments can accumulate or oscillate when an entity ultimately targets itself, while cycles do not provide a stable parent-child hierarchy.

Script Access

Use the entity property interface to retrieve an entity's bind pointer:

void bind = get_entity_property(
    entity,
    ENTITY_PROPERTY_BIND
);

Once retrieved, the same pointer is used with the bind-property functions:

void value = get_bind_property(bind, property);

set_bind_property(bind, property, value);

Changing a property does not immediately run the complete binding calculation. Normal binding resolution occurs near the end of the logical entity-update process. Call update_bind(entity) when the change must be applied at the current script location:

update_bind(entity);

Manual updates execute the same bind callbacks, matching, removal, direction, sorting, and positioning logic as the normal pass. Calling update_bind() does not suppress the normal later update, so a still-active bind may resolve twice during that logical tick.

Property List

Property Type Default Purpose
BIND_PROPERTY_ANIMATION_FRAME Integer 0 Indexed animation position used when BIND_CONFIG_ANIMATION_FRAME_DEFINED is active.
BIND_PROPERTY_ANIMATION_ID Integer 0 Animation ID used when BIND_CONFIG_ANIMATION_DEFINED is active.
BIND_PROPERTY_CONFIG Unsigned 64-bit integer BIND_CONFIG_NONE Bitmask selecting animation matching, axis sources, failure removal, and native-behavior overrides. See Configuration Flags.
BIND_PROPERTY_DIRECTION_ADJUST Integer DIRECTION_ADJUST_NONE Direction rule applied in relation to the target.
BIND_PROPERTY_META_DATA Pointer Empty Creator-managed metadata pointer. Native binding logic does not interpret it.
BIND_PROPERTY_META_TAG Integer 0 Creator-managed numeric tag. Native binding logic does not interpret it.
BIND_PROPERTY_OFFSET_X Integer 0 X offset from the target or absolute X coordinate, according to configuration.
BIND_PROPERTY_OFFSET_Y Integer 0 Y offset from the target or absolute Y coordinate, according to configuration.
BIND_PROPERTY_OFFSET_Z Integer 0 Z offset from the target or absolute Z coordinate, according to configuration.
BIND_PROPERTY_SORT_ID Integer 0 Drawing sort adjustment added to the target's current sort ID during each bind update.
BIND_PROPERTY_TARGET Entity pointer Empty Entity to which the property owner binds itself. Empty or null disables all native binding logic.

Several API constants retain the legacy word FRAME. Within OpenBOR's data model, these values refer to an indexed animation position rather than a separate frame object.

Activating and Cancelling Binding

Assigning the target activates the bind object:

void bind = get_entity_property(
    follower,
    ENTITY_PROPERTY_BIND
);

set_bind_property(
    bind,
    BIND_PROPERTY_TARGET,
    target
);

Cancel the relationship by clearing the target:

set_bind_property(
    bind,
    BIND_PROPERTY_TARGET,
    NULL()
);

Setting BIND_PROPERTY_CONFIG to BIND_CONFIG_NONE does not unbind the entity. Target, relative sort ID, direction adjustment, callbacks, and any other behavior independent of configuration remain active. Clear BIND_PROPERTY_TARGET when the relationship itself should end.

Configuration Flags

BIND_PROPERTY_CONFIG is a 64-bit bitmask. Combine independent behaviors with bitwise OR:

int config = BIND_CONFIG_AXIS_X_TARGET
    | BIND_CONFIG_AXIS_Y_TARGET
    | BIND_CONFIG_AXIS_Z_TARGET;

set_bind_property(
    bind,
    BIND_PROPERTY_CONFIG,
    config
);

Assign BIND_CONFIG_NONE directly to clear all flags.

Animation Matching

Flag Effect
BIND_CONFIG_ANIMATION_TARGET Match the target's current animation ID.
BIND_CONFIG_ANIMATION_DEFINED Match BIND_PROPERTY_ANIMATION_ID instead of the target's current animation.
BIND_CONFIG_ANIMATION_REMOVE Remove the binding entity when the requested animation is unavailable. Without this flag, an unavailable animation clears the bind target instead.
BIND_CONFIG_ANIMATION_FRAME_TARGET Match the target's current indexed animation position.
BIND_CONFIG_ANIMATION_FRAME_DEFINED Match BIND_PROPERTY_ANIMATION_FRAME instead of the target's current position.
BIND_CONFIG_ANIMATION_FRAME_REMOVE Remove the binding entity when a requested indexed position does not exist in its selected animation.

Defined selection takes precedence when both defined and target flags are present. BIND_CONFIG_ANIMATION_DEFINED wins over BIND_CONFIG_ANIMATION_TARGET, while BIND_CONFIG_ANIMATION_FRAME_DEFINED wins over BIND_CONFIG_ANIMATION_FRAME_TARGET.

Animation matching occurs before indexed-position matching. Target matching uses the target's numeric animation ID, so the binding model must provide a valid animation in the corresponding slot. Position matching then uses the binding entity's selected animation.

Pair removal flags with the matching behavior they protect. Typical visual helpers combine target matching with both removal flags, allowing the helper to remove itself cleanly when its model cannot represent the target's state.

Entering a matched animation or indexed position follows the normal animation-entry path. Animationscript and other entry behavior may consequently execute during binding resolution.

Axis Sources

Flag Result
BIND_CONFIG_AXIS_X_TARGET Set binding entity X to target X plus the configured X offset. Offset direction mirrors with target facing.
BIND_CONFIG_AXIS_X_LEVEL Set binding entity X directly to the configured X value.
BIND_CONFIG_AXIS_Y_TARGET Set binding entity Y to target Y plus the configured Y offset.
BIND_CONFIG_AXIS_Y_LEVEL Set binding entity Y directly to the configured Y value.
BIND_CONFIG_AXIS_Z_TARGET Set binding entity Z to target Z plus the configured Z offset.
BIND_CONFIG_AXIS_Z_LEVEL Set binding entity Z directly to the configured Z value.

Target mode takes precedence when both target and level flags are set for the same axis. Axes without either flag remain unchanged by binding.

Level-axis flags make the offset property an absolute level coordinate. They do not remove the requirement for a valid bind target. Binding resolution always returns immediately when BIND_PROPERTY_TARGET is empty.

Native-Behavior Overrides

Override flags remain effective only while a valid bind target exists.

Flag Suppressed native behavior
BIND_CONFIG_OVERRIDE_FALL_LAND Normal falling-state landing resolution when the entity reaches its base.
BIND_CONFIG_OVERRIDE_DROPFRAME Configured drop-position transition and its associated effect.
BIND_CONFIG_OVERRIDE_LANDFRAME Configured land-position transition and its associated effect.
BIND_CONFIG_OVERRIDE_SPECIAL_AI Special activation for enemy and NPC entities through the native energy-check path.
BIND_CONFIG_OVERRIDE_SPECIAL_PLAYER Special activation for player entities through the native energy-check path.

Override flags are especially useful for custom grapples, carries, throws, and slams. Native landing or special behavior can otherwise interrupt a scripted sequence even while position and animation are being synchronized.

Positioning Rules

X Offset and Facing

Target-relative X offset mirrors according to the target's direction:

  • Target faces right - binding X is target X + offset X.
  • Target faces left - binding X is target X - offset X.

Positive X therefore means forward from the target's facing, while negative X means behind it. Absolute level X does not mirror.

Target facing controls this offset even when the binding entity uses a different direction-adjustment rule.

Y and Z Offsets

Target-relative Y and Z offsets do not mirror:

  • Positive Y places the binding entity higher than the target.
  • Negative Y places it lower.
  • Positive Z places it at a greater world-depth coordinate, generally toward the camera.
  • Negative Z places it toward the background.

Binding does not perform collision correction for the final assignment. Selected axes are written after ordinary entity movement, so target-relative values can place the binding entity through walls, platforms, or other obstacles when that is what the configured relationship requires.

Direction Adjustment

BIND_PROPERTY_DIRECTION_ADJUST accepts the following constants:

Constant Result
DIRECTION_ADJUST_NONE Preserve the binding entity's current direction.
DIRECTION_ADJUST_SAME Match the target's direction.
DIRECTION_ADJUST_OPPOSITE Face opposite the target's direction.
DIRECTION_ADJUST_RIGHT Always face right.
DIRECTION_ADJUST_LEFT Always face left.
DIRECTION_ADJUST_TOWARD Face toward the target according to their current X positions.
DIRECTION_ADJUST_AWAY Face away from the target according to their current X positions.

Toward and away preserve the binding entity's current direction when both entities occupy the same X coordinate. Their comparison occurs before axis positioning for the current bind pass.

Drawing Sort

Every active bind update assigns:

binding entity sort ID = target sort ID + bind sort adjustment

Relative value -1 normally places the binding entity immediately behind its target when both share the same drawing Z. Value 1 normally places it immediately in front. Value 0 matches the target's sort ID.

World Z and drawing sort ID both participate in display order. Relative sort adjustment alone does not guarantee front or back placement when the entities occupy different Z positions. Binding Z to the target is the usual choice for tightly layered composite visuals.

Items with identical Z and sort values should not depend on incidental insertion order. Give layered components distinct relative sort values when their relationship must remain stable.

Runtime Timing

Normal binding resolves once during each logical entity-update cycle:

  1. OpenBOR performs the main update for eligible entities.
  2. Gravity and pending movement are resolved for every existing entity.
  3. Once all entity movement is complete, OpenBOR visits existing entities for binding.
  4. The target-side bind callback executes.
  5. The binding-entity callback executes.
  6. OpenBOR rechecks whether the bind still has a target.
  7. Animation and indexed-position matching are applied.
  8. Relative sort ID is applied.
  9. Direction adjustment is applied.
  10. Configured X, Y, and Z axes are applied.
  11. Removed entities are compacted from the active list.

Post-movement placement is an important part of binding behavior. The system is not a physical parent constraint evaluated during collision movement. The binding entity undergoes its ordinary update first, then selected properties are synchronized after movement finishes.

Binding updates are not gated by viewport visibility or the binding entity's frozen state. Frozen entities still receive bind placement and bind callbacks during an advancing logical cycle. Pausing the logical engine stops the normal update pass.

Freshly spawned entities are skipped by the main entity update during their spawn tick, though they can still participate in the later binding pass when a target was assigned during creation or Onspawnscript.

Binding Chains

Direct bindings observe target movement completed earlier in the same logical cycle. Binding itself is resolved in one active entity-list pass, not as a dependency tree.

For a chain where C binds to B and B binds to A, C sees B's newly bound result during the same cycle only when B happens to resolve first. Reverse ordering leaves C using B's pre-bind result until the next cycle. Entity allocation and removal may change that ordering.

Use one direct target for multiple components when exact same-cycle composition matters. Project-managed ordering or explicit update_bind() calls can coordinate intentional chains, though manual updates also execute callbacks and should be guarded against recursion.

Bind Update Scripts

Two optional model scripts execute before native matching and placement during every active bind update.

Model command Executes on Purpose
on_bind_update_other_to_self_script The current bind target. Inspect or modify an entity binding itself to self.
on_bind_update_self_to_other_script The binding entity. Inspect or modify self's relationship with its target.

Example model declarations:

on_bind_update_other_to_self_script data/scripts/bind_target_update.c
on_bind_update_self_to_other_script data/scripts/bind_follower_update.c

Both callbacks receive the same bind object, which belongs to the binding entity:

Callback self other bind
on_bind_update_other_to_self_script Bind target Entity binding itself to the target Binding entity's bind pointer
on_bind_update_self_to_other_script Binding entity Current bind target Binding entity's bind pointer

The target callback runs first. Changes to configuration, offsets, matching, sort ID, direction, metadata, or target can affect the same bind pass because OpenBOR reads the working properties afterward.

The binding-entity callback runs second. If the target callback redirected the bind, other reflects the new target. If the target callback cleared the target, the binding-entity callback still executes with an empty other, then native binding exits.

Return values are ignored. Clear BIND_PROPERTY_TARGET to cancel the native adjustment for the current pass.

Calling update_bind() from either bind callback re-enters the same callback sequence. Unguarded use can recurse indefinitely.

Quick Examples

Target-Relative Visual Component

This helper binds a visual component to a target, places it 24 units forward and 36 units above, matches facing, and draws it one sort step behind:

void attach_visual_component(void component, void target)
{
    void bind = get_entity_property(
        component,
        ENTITY_PROPERTY_BIND
    );

    int config = BIND_CONFIG_AXIS_X_TARGET
        | BIND_CONFIG_AXIS_Y_TARGET
        | BIND_CONFIG_AXIS_Z_TARGET;

    set_bind_property(bind, BIND_PROPERTY_OFFSET_X, 24);
    set_bind_property(bind, BIND_PROPERTY_OFFSET_Y, 36);
    set_bind_property(bind, BIND_PROPERTY_OFFSET_Z, 0);
    set_bind_property(bind, BIND_PROPERTY_SORT_ID, -1);
    set_bind_property(
        bind,
        BIND_PROPERTY_DIRECTION_ADJUST,
        DIRECTION_ADJUST_SAME
    );
    set_bind_property(bind, BIND_PROPERTY_CONFIG, config);
    set_bind_property(bind, BIND_PROPERTY_TARGET, target);

    update_bind(component);
}

The component remains an independent entity. Binding supplies synchronized placement, facing, and sort order without transferring ownership or collision behavior.

Animation-Synchronized Effect

This configuration follows the target's animation and indexed position, then removes the effect if its model lacks the required match:

int config = BIND_CONFIG_AXIS_X_TARGET
    | BIND_CONFIG_AXIS_Y_TARGET
    | BIND_CONFIG_AXIS_Z_TARGET
    | BIND_CONFIG_ANIMATION_TARGET
    | BIND_CONFIG_ANIMATION_FRAME_TARGET
    | BIND_CONFIG_ANIMATION_REMOVE
    | BIND_CONFIG_ANIMATION_FRAME_REMOVE;

This pattern suits trails, aura layers, alternate body parts, and other components built with animation tables corresponding to their targets.

Grapples and Slams

Binding is an essential component in constructing sequence-heavy grapple attacks such as piledrivers, backbreakers, carries, and throws. Grapples can be understood much like professional wrestling - the attacker initiates and directs the maneuver, while the victim performs most of the technical work.

Typically, the attacker places the victim into a dedicated reaction animation and binds it to the attacker. The victim's animation supplies the poses and adjusts its bind offsets as the maneuver progresses. Damage may be applied at selected indexed animation positions. Once the sequence finishes, the victim is unbound and usually receives final damage with a knockdown effect.

This victim-led arrangement allows each model to provide poses suited to its own proportions while the attacker only needs to select the victim and initiate the sequence. It also allows one attacker to coordinate multiple bound victims at once. Since each victim maintains its own bind and sequence, careful setup can produce awe-inspiring multi-part, multi-target grapples that fill the screen with synchronized motion and pain.

Binding provides several flags particularly useful for grapple construction:

  • BIND_CONFIG_OVERRIDE_FALL_LAND prevents native landing behavior from interrupting the sequence.
  • BIND_CONFIG_OVERRIDE_DROPFRAME suppresses the normal drop-position transition.
  • BIND_CONFIG_OVERRIDE_LANDFRAME suppresses the normal land-position transition.
  • BIND_CONFIG_OVERRIDE_SPECIAL_AI and BIND_CONFIG_OVERRIDE_SPECIAL_PLAYER can prevent native special activation while the victim remains bound.

The following abbreviated example binds a victim to an attacker and places the victim in its first follow animation. The victim's Animationscript can call the impact and finishing functions at the appropriate indexed animation positions.

void begin_slam(void attacker, void victim)
{
    void bind = get_entity_property(
        victim,
        ENTITY_PROPERTY_BIND
    );

    void config = BIND_CONFIG_AXIS_X_TARGET
        | BIND_CONFIG_AXIS_Y_TARGET
        | BIND_CONFIG_AXIS_Z_TARGET
        | BIND_CONFIG_OVERRIDE_FALL_LAND
        | BIND_CONFIG_OVERRIDE_DROPFRAME
        | BIND_CONFIG_OVERRIDE_LANDFRAME;

    set_bind_property(bind, BIND_PROPERTY_OFFSET_X, 0);
    set_bind_property(bind, BIND_PROPERTY_OFFSET_Y, 0);
    set_bind_property(bind, BIND_PROPERTY_OFFSET_Z, 0);
    set_bind_property(bind, BIND_PROPERTY_SORT_ID, -1);

    set_bind_property(
        bind,
        BIND_PROPERTY_DIRECTION_ADJUST,
        DIRECTION_ADJUST_SAME
    );

    set_bind_property(bind, BIND_PROPERTY_CONFIG, config);
    set_bind_property(bind, BIND_PROPERTY_TARGET, attacker);

    performattack(victim, ANI_FOLLOW1);
    update_bind(victim);
}

void slam_impact(void victim, void attacker)
{
    damageentity(
        victim,
        attacker,
        8,
        0,
        ATK_NORMAL
    );
}

void finish_slam(void victim, void attacker)
{
    void bind = get_entity_property(
        victim,
        ENTITY_PROPERTY_BIND
    );

    set_bind_property(
        bind,
        BIND_PROPERTY_TARGET,
        NULL()
    );

    damageentity(
        victim,
        attacker,
        40,
        1,
        ATK_NORMAL
    );
}

The exact follow animation, offsets, intermediate damage, and final launch behavior are project decisions. Binding supplies the synchronization and override tools without imposing a particular grapple system.

Binding and Other Relationships

Relationship Primary purpose Established by binding?
Bind target One-way position, animation, direction, and sorting synchronization. Yes
Owner Attribution for attacks, projectiles, effects, and related systems. No
Parent and child Spawn lineage, summon behavior, and model-defined subentity relationships. No
Grab and link Native grapple, carry, and paired-action behavior. No
Platform support Standing on and moving with platform geometry. No

Projects often combine these relationships deliberately. For example, a weapon trail may bind to its owner for placement while also retaining an owner pointer for damage attribution. Each relationship must be configured through its own interface.

Common Mistakes

  • Reversing the relationship and trying to make the target bind another entity to itself.
  • Setting configuration without assigning a valid target.
  • Setting BIND_CONFIG_NONE and expecting it to clear the target.
  • Expecting level-axis flags to work without a target pointer.
  • Assuming unconfigured axes will follow the target automatically.
  • Forgetting that target X offset mirrors with the target's facing.
  • Treating Y as screen position instead of world altitude.
  • Assuming relative sort ID overrides differences in world Z.
  • Matching target animation IDs when the binding model does not provide corresponding animation slots.
  • Using position-removal flags without enabling a defined or target position match.
  • Expecting binding to suppress native movement, collision, landing, or special behavior unless the applicable override is enabled.
  • Assuming binding establishes owner, parent, child, grab, link, or platform relationships.
  • Expecting a property change to reposition the entity immediately without update_bind().
  • Calling update_bind() from a bind callback without preventing recursion.
  • Depending on active entity-list order for exact same-cycle behavior across a bind chain.
  • Creating self-targets or cycles and expecting stable hierarchical placement.