Jump to content

Ondoattackscript

From OpenBOR
Revision as of 16:39, 17 August 2026 by Dcurrent (talk | contribs) (Created page with "<code>ondoattackscript</code> is a model event that runs when an entity's attack becomes a candidate to hit another entity. OpenBOR invokes the recipient's script first and the conferring entity's script second, before native block, counter, and damage resolution. The event is an attack-interception hook rather than hit confirmation. Scripts may inspect the proposed attack, coordinate custom responses, or cancel native handling through the shared last-hit confirmation v...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

ondoattackscript is a model event that runs when an entity's attack becomes a candidate to hit another entity. OpenBOR invokes the recipient's script first and the conferring entity's script second, before native block, counter, and damage resolution.

The event is an attack-interception hook rather than hit confirmation. Scripts may inspect the proposed attack, coordinate custom responses, or cancel native handling through the shared last-hit confirmation value. Use Didhitscript when logic should run only after OpenBOR accepts a hit.

Syntax

ondoattackscript {path}

# Default
# No Ondoattack script
  • {path} - Path to an OpenBOR Script source file.
  • The command belongs in a model definition.
  • OpenBOR loads and compiles the script with the model.
  • The script's return value is ignored.

Example model definition:

name example_character
type enemy

ondoattackscript data/scripts/example_ondoattack.c

Event code may also be embedded directly in the model:

ondoattackscript @script
void main()
{
    void self       = getlocalvar("self");
    void other      = getlocalvar("other");
    int which       = getlocalvar("which");
    int attack_type = getlocalvar("attacktype");
}
@end_script

Event Scope

OpenBOR invokes ondoattackscript for candidate impacts that reach the attack-resolution stage. Relevant native paths include ordinary attack-box collisions, active item attack-box collisions, and configured damage on landing.

Preliminary rules are evaluated before the event. These include collision, target life state, invincibility, faction permission, next-hit timing, attack-ID duplication, ground-hit permission, juggle availability, and the presence of a take-damage handler. Rejected candidates do not invoke the event.

Passing the preliminary rules does not guarantee a hit. Native processing may still reject the candidate after both scripts run, or may resolve it as a block or counter. Consequently, this event can run without a later Didhit event.

Ordinary item pickup paths may invoke an item's collection script directly. ondoattackscript should not be treated as a universal item-collection callback.

self is always the entity whose model owns the currently executing script. For a projectile impact, the projectile is the conferring entity; OpenBOR does not automatically substitute its owner.

Execution Order

For an ordinary candidate impact, OpenBOR performs the relevant operations in this order:

  1. Confirms collision and preliminary attack eligibility.
  2. Initializes the shared last-hit context with confirmation enabled.
  3. Runs the recipient's ondoattackscript with which = EXCHANGE_RECIPIENT.
  4. Runs the conferring entity's ondoattackscript with which = EXCHANGE_CONFERRER.
  5. Continues only when the shared last-hit confirmation remains enabled.
  6. Applies remaining identity, ownership, projectile, block, counter, and take-damage rules.
  7. Runs later events, including Didblockscript or Didhitscript, when their conditions are met.

Both Ondoattack scripts operate on the same last-hit context. The recipient runs first, the conferrer runs second, and the value remaining after the second callback controls native continuation. Setting lasthitc to 0 in the recipient's script does not prevent the conferrer's script from running.

Exchange Roles

The which local identifies the current entity's role in the proposed exchange.

Constant Numeric value Current self Execution order
EXCHANGE_RECIPIENT 1 Recipient or defender First
EXCHANGE_CONFERRER 0 Attacker, projectile, or other entity conferring the attack Second

Comparing which with named constants is clearer and safer than relying on raw numeric values.

Local Variables

Local variable Type Value
self Entity pointer Entity whose Ondoattack script is currently running.
other Entity pointer Other participant in the exchange. Recipient scripts receive the conferrer; conferrer scripts receive the recipient.
damage Integer Raw attack.damage.force at the time of the event. This is not final HP loss.
drop Integer Raw attack.reaction.fall.force - the attack's knockdown force.
attacktype Integer Internal attack-type identifier. Compare it with named ATK_* constants from openborconstant().
noblock Integer Raw attack.block.penetrate value. The local retains its legacy name.
guardcost Integer Raw attack.block.cost value.
jugglecost Integer Attack's juggle-point cost.
pauseadd Integer Raw attack.reaction.pause.time in logical clock ticks.
tag Integer Creator-defined attack.tag metadata.
which Integer Current exchange role: EXCHANGE_RECIPIENT or EXCHANGE_CONFERRER.
attack_id Integer Current outgoing attack ID used by native duplicate-hit control. Both callbacks receive the same value.

attack_id is not an entity ID or collision-box index. Synthetic landing-damage events may supply 0. The local name includes the underscore; attackid is not the current event local.

Numeric attack locals are copied from the current attack when each callback begins. Assigning new values to these local variables does not write them back to native attack data. Use the last-hit interface when native context must be changed.

Cancelling Native Hit Handling

The shared OpenBOR variant lasthitc exposes the current last-hit confirmation flag. Collision setup normally initializes it to 1. Setting it to 0 during Ondoattack tells the engine to abandon native handling after both callbacks finish.

The following recipient-side example cancels native handling for freeze attacks:

void main()
{
    int which       = getlocalvar("which");
    int attack_type = getlocalvar("attacktype");

    if(which != openborconstant("EXCHANGE_RECIPIENT"))
    {
        return;
    }

    if(attack_type == openborconstant("ATK_FREEZE"))
    {
        changeopenborvariant("lasthitc", 0);
    }
}

Cancellation prevents the normal block, counter, damage, and Didhit processing for that candidate. Custom effects or responses may be performed before clearing the flag.

The conferrer's callback still runs after the example clears lasthitc. If that later callback sets the flag back to 1, native handling resumes. Projects that cancel from the recipient side should establish a clear convention for conferrer scripts.

Returning 0, 1, or another value from main() does not accept or cancel the impact. OpenBOR ignores the script return value for this event.

Shared Last-Hit Context

Ondoattack scripts may inspect the full candidate through OpenBOR's last-hit variants.

Variant Purpose
lasthitc Reads or changes candidate confirmation.
lasthit_attack Provides the current attack object for property access.
lasthit_attacker Provides the entity conferring the attack.
lasthit_target Provides the proposed recipient.
lasthitt Reads or changes the current attack type.
lasthitx, lasthity, lasthitz Provide the recorded impact coordinates.

Read these values with openborvariant(). Writable variants may be changed with changeopenborvariant().

Since the recipient callback runs first, native context changes it makes can be visible to the conferrer's callback. For example, changing lasthitt in the recipient callback changes the attack type used to populate the later conferrer's attacktype local. Treat such changes as shared state rather than private per-entity data.

Role-Specific Example

This example shows one file shared by several models. Recipient logic may reject a tagged attack, while conferrer logic records that the candidate reached Ondoattack processing.

void main()
{
    void self    = getlocalvar("self");
    void other   = getlocalvar("other");
    int which    = getlocalvar("which");
    int tag      = getlocalvar("tag");
    int attack_id = getlocalvar("attack_id");

    if(which == openborconstant("EXCHANGE_RECIPIENT"))
    {
        if(tag == 42)
        {
            changeopenborvariant("lasthitc", 0);
        }
        return;
    }

    if(which == openborconstant("EXCHANGE_CONFERRER"))
    {
        log("Candidate attack reached Ondoattack");
    }
}

Unused variables are retained to demonstrate the usual event setup. Real scripts may pass self, other, and attack_id into project-specific combat, immunity, parry, statistics, or debugging systems.

Damage on Landing

Configured landing damage also passes through Ondoattack processing. OpenBOR builds a temporary attack, chooses a living opponent as the conferrer when possible, and otherwise uses the landing entity itself. The recipient callback runs before the conferrer callback, following the same confirmation rules as an ordinary candidate impact.

Landing events use a synthetic attack context. Some values, including attack_id, may therefore be 0 or differ from ordinary attack-box collisions.

Global Model

Unlike Didhit and Onspawn, ondoattackscript is not automatically forwarded through a model named global_model. Only the scripts belonging to the two participating entities run. Shared project-wide behavior should be placed in a common script included by participating models or called from their individual Ondoattack scripts.

Event Entity Relative purpose
Ondoattackscript Recipient first, then conferrer Intercepts a candidate impact before native block, counter, and damage handling. May cancel native processing through lasthitc.
Takedamagescript Recipient Runs while native damage and reaction handling are being applied.
Didhitscript Conferrer Runs after OpenBOR accepts a normal hit, block, qualifying item event, or landing-damage event.
Didblockscript Defender Runs after a successful native block and applicable guard-cost deduction.

See Also