Onpainscript
onpainscript is OpenBOR's pain-reaction hook. It runs after the engine successfully selects and starts a pain or grabbed animation, stops the entity's movement, clears conflicting action states, and establishes the native pain response.
This placement lets creators inspect the requested attack type and immediately extend or replace the selected reaction. Typical uses include armor responses, custom hit stun, contextual flinches, retaliation, stagger systems, hit voices, reaction effects, AI state changes, and grabbed-state behavior.
Onpain is not a general damage callback. Hits that cause no pain, resolve as blocks, knock the entity down, kill it, or never enter the native pain selector do not invoke the event. Use Takedamagescript for post-HP logic and Onfallscript for fall or knockdown reactions.
Syntax
onpainscript {path}
# Default
# No Onpain 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
onpainscript data/scripts/example_onpain.c
Event code may also be embedded directly in the model:
onpainscript @script
void main()
{
void self = getlocalvar("self");
int attack_type = getlocalvar("attacktype");
int reset = getlocalvar("reset");
}
@end_script
Event Timing
For an ordinary accepted hit that produces a standing pain reaction, OpenBOR performs the relevant operations in this order:
- Resolves Ondoattack, block, counter, damage, Takedamage, lethal handling, and native death checks.
- Determines that the surviving recipient should enter pain rather than fall, remain frozen, or ignore the reaction.
- Selects guard-break, attack-type pain, back-pain, generic pain, grabbed, or idle fallback animation as applicable.
- Starts or retains the selected animation according to the reset flag.
- Stops velocity and clears idling, falling, rising, ducking, projectile, drop, attacking, getting, charging, jumping, and blocking states.
- Marks the entity as being in hit pain, except when the selected request represents the grabbed state.
- Removes frozen state when applicable.
- Runs
onpainscript. - Returns to the calling damage or grab path.
For ordinary damage, Onpain runs after Takedamage and any Ondeath processing, but before the attacker's Didhitscript. Damage and earlier hit effects have already occurred.
The selected animation is active when Onpain begins. Scripts may inspect it, add effects, or replace the native reaction with creator-defined behavior. Normal standing damage performs no later pain-animation selection after the callback returns.
Grab callers may still perform positioning or frame adjustments after Onpain returns. Grab-specific overrides should account for the surrounding grab system.
Native Pain Selection
OpenBOR uses the following general selection order before invoking Onpain:
- Select
ANI_GUARDBREAKwhen guard points are configured and depleted, then restore the native guard-point pool. - Select
ANI_GRABBEDwhen the requested type is-1. - Otherwise select the front or back pain animation associated with the requested attack type.
- Fall back through normal back-pain, requested-type pain, normal pain, and idle animations when needed.
- Abort without invoking Onpain when no valid fallback exists.
The attacktype local contains the requested type passed into the selector, not the animation identifier ultimately chosen. Missing type-specific animation data may therefore produce a generic pain animation while the original type remains available to script.
Practical Uses
| Pattern | Use of onpainscript
|
|---|---|
| Armor or poise response | Detect an armor state after damage, replace the ordinary flinch with an armored response, and add sparks, sound, meter loss, or temporary resistance feedback. |
| Contextual hit stun | Choose a reaction duration or custom animation from attack type, health, combo state, attacker category saved by an earlier event, or entity-specific rules. |
| Reactive counter or burst | Consume a defensive resource and replace pain with a counter, escape, shockwave, or invulnerable recovery when project conditions permit. |
| Type-specific feedback | Add burn, freeze, shock, heavy-hit, weapon, or other creator-defined presentation after the native reaction has been established. |
| AI state transition | Notify behavior logic that a true pain reaction occurred, then change aggression, retreat, target selection, phase state, or tactical priorities. |
| Grabbed-state behavior | Detect attacktype = -1 and coordinate project-specific held, captured, mounted, restrained, or synchronized interaction logic.
|
| Accessibility and combat readability | Add configurable flashes, sounds, indicators, vibration logic, or other feedback only when the entity visibly enters pain. |
Armor Response
The following compact example replaces ordinary pain while a creator-defined armor state is active. Project helper play_armor_response() may select an armor animation, adjust action state, and create the desired effects.
void main()
{
void self = getlocalvar("self");
int attack_type = getlocalvar("attacktype");
int armor_active = getentityvar(self, "armor_active");
if(attack_type >= 0 && armor_active == 1)
{
play_armor_response(self, attack_type);
}
}
The damage remains applied because Onpain occurs after HP processing. Replacing the pain response changes presentation and action state rather than cancelling the hit.
Local Variables
| Local variable | Type | Value |
|---|---|---|
self
|
Entity pointer | Entity that successfully entered the native pain or grabbed selector. |
attacktype
|
Integer | Requested attack-type identifier used to choose pain. Normal damage supplies the recipient's recorded last damage type. Grab handling supplies -1.
|
reset
|
Integer | Animation reset request supplied to the pain selector. 1 allows the selected animation to restart even when already active; 0 retains an already active matching animation.
|
The reset local describes the request passed into animation selection. It does not report whether an animation actually restarted, because the selector may choose a fallback or retain an existing animation.
Onpain does not provide attacker, damage, drop, tag, blocked, or attack_id. Projects needing that context may save it to entity variables during Ondoattack or Takedamage before reaction selection reaches Onpain.
Assignments to event locals do not alter native state. Use entity and animation functions or property interfaces when the reaction itself must change.
Event Scope
| Path | Onpain event | Notes |
|---|---|---|
| Accepted standing hit that passes pain eligibility | Yes | Runs after the pain animation and native pain state are established. |
| Hit ignored by pain threshold or defense | No | HP damage may still occur without a visible pain reaction. |
| Attack with no-pain behavior | No | Native damage handling deliberately skips pain selection. |
| Recipient with pain disabled | No | PAIN_CONFIG_PAIN_DISABLE prevents ordinary pain selection.
|
| Frozen recipient in the ordinary damage path | No | Normal pain selection is skipped while frozen. |
| Knockdown, fall, or lethal fall reaction | No | These paths use fall handling and Onfallscript. |
| Successful native block or block pain | No | Block reactions use blocking events and the separate block-pain selector. |
| Grabbed animation request | Yes | Uses attacktype = -1 and commonly reset = 0. Repeated grab maintenance may invoke Onpain again.
|
| Biker pain handling | Yes | The specialized biker damage path explicitly enters the native pain selector. |
| Direct animation change to a pain animation | No | Onpain belongs to the pain selector, not to the animation identifier itself. |
Onpain may therefore run without a new HP change during grab maintenance, and damage may occur without Onpain when the recipient does not visibly enter pain.
Changing the Reaction
The native pain animation and state are already active when the callback begins. Scripts may replace them with another animation, begin an attack, return the entity to idle, change movement, or transfer control to a larger creator-defined state machine.
Replacing only the animation may leave native pain action logic active. Project helpers should set the complete action state required by the replacement. Functions such as executeanimation(), performattack(), and setidle() establish broader native states in addition to changing animation.
The script return value is ignored. Returning 0 does not cancel pain, and returning 1 does not confirm it.
Changing lasthitc during Onpain is too late to cancel the hit. Use Ondoattackscript when the collision and all native consequences should be rejected.
Attack Type and Grab State
For ordinary damage, compare nonnegative attacktype values with named ATK_* constants from openborconstant(). The value identifies the requested reaction type even when OpenBOR selected a fallback pain animation.
The special value -1 requests ANI_GRABBED. It is not an ATK_* constant and should be tested before ordinary attack-type comparisons.
Global Model
onpainscript is not automatically forwarded through a model named global_model. Only the script belonging to the entity entering pain runs. Shared project-wide behavior should be placed in a common script included by participating models or called from their individual Onpain scripts.
Related Events
| Event | Entity | Relative purpose |
|---|---|---|
| Ondoattackscript | Recipient first, then conferrer | Runs before native hit resolution and may cancel all native consequences through lasthitc.
|
| Takedamagescript | Damage recipient | Runs after HP processing regardless of whether a standing pain animation will follow. |
| Onpainscript | Entity entering pain or grabbed selection | Runs after a valid pain animation and native pain state are established. |
| Onfallscript | Entity entering fall | Runs after a valid fall animation and fall state are established. |
| Didblockscript | Defender | Runs after a successful native block rather than ordinary pain. |
| Didhitscript | Conferrer | Runs after accepted recipient take-damage handling, including Onpain when applicable. |