Global Update Hook Examples

Pack-level hooks run around every active entity update. They are powerful because they can change universal combat rules, but they are also expensive and easy to over-apply. Keep them small, guard by context, and return quickly for entities that do not need the rule.

Configure Global Hooks

Add hooks to config.json with the same script shape used by animation scripts:

{
  "preEntityUpdateScripts": [
    {
      "packName": "My Pack",
      "scriptName": "Global entities pre-update"
    }
  ],
  "postEntityUpdateScripts": [
    {
      "packName": "My Pack",
      "scriptName": "Global entities post-update"
    }
  ]
}

Pre-entity hooks run before the entity controller. Returning false from a pre hook cancels that entity update for the frame. Post-entity hooks run after the entity controller and are best for cleanup or reactions to what just happened.

Pre-Update: Thrown Bodies Break Containers

Use a pre hook when you need to adjust vulnerability before normal collision and physics run.

return function()
    local character = game.this_character

    if character == nil then
        return true
    end

    -- Object mode 10 and 6 are the example knocked/thrown modes.
    -- Use the modes that mean airborne damage state in your data.
    if character.object_mode == 10 or character.object_mode == 6 then
        -- Prevent normal hits from interrupting this thrown-body rule before the
        -- post hook decides whether the body can be juggled.
        character.is_vulnerable = false

        if character.check_body_breaking_containers() then
            -- If the body breaks a container, bounce it away. is_being_thrown
            -- identifies active throw releases; those already own X velocity.
            if not character.is_being_thrown then
                character.velocity_x = -character.velocity_x / 3
            end

            character.auxiliar_velocity_x = -character.auxiliar_velocity_x / 3
            character.impulse_y = -120
        end
    end

    return true
end

Post-Update: Juggle And Multi-Hit Limiter

This post hook creates a global juggle rule. It lets knocked-down characters be hit in the air, applies diminishing damage, changes the hit reaction, and stops the rule after a limit.

return function()
    local character = game.this_character

    if character == nil then
        return true
    end

    -- Let hit pause finish. During hit pause, the entity should not be re-tested
    -- for another global juggle hit every frame.
    if character.hit_pause_timer ~= 0 then
        return true
    end

    local juggle_limit = 15
    local divider_limit = 8
    local increment = 1

    if character.is_player then
        -- Players reach the limit faster than enemies in this example.
        increment = 3
    end

    if character.object_mode == 10 or character.object_mode == 6 then
        if character.is_pressing_against_walls(true) then
            character.is_facing_right = not character.is_facing_right

            if not character.is_being_thrown then
                character.velocity_x = -character.velocity_x / 2
            end

            character.auxiliar_velocity_x = (character.auxiliar_velocity_x * 3) / 4
            character.impulse_y = character.impulse_y - 10
            character.hit_pause_timer = 6
        end

        -- current_animation_id 12 is treated as non-juggleable in this example.
        character.is_vulnerable =
            character.current_animation_id ~= 12 and
            character.custom_value_5 < juggle_limit

        if not character.is_vulnerable then
            character.is_knocked_down = false
            return true
        end

        character.is_knocked_down = true

        -- Later hits do less damage. Guard the first two hits so division does not
        -- over-reduce the opening juggle hits.
        if character.custom_value_5 > 1 then
            character.damage_taken = character.damage_taken / character.custom_value_5
        end

        if character.check_being_hit() then
            character.set_animation(10)
            character.custom_value_5 = character.custom_value_5 + increment

            if character.custom_value_5 < divider_limit then
                character.impulse_y = character.impulse_y / character.custom_value_5
            else
                -- After the divider limit, force the body downward so the juggle
                -- naturally ends.
                character.impulse_y =
                    (character.custom_value_5 - divider_limit) * 20
            end
        end
    else
        -- Reset the per-character juggle counter outside knocked/thrown modes.
        character.custom_value_5 = 0
    end

    return true
end

Post-Update: Air Recovery Escape

This hook lets players recover out of a knockdown on the first airborne hit-reaction frame by holding up plus jump.

return function()
    local character = game.this_character

    if character == nil or not character.is_player then
        return true
    end

    local can_air_recover =
        character.object_mode == 10 and
        character.current_animation_id == 11 and
        character.current_animation_frame == 0 and
        character.is_holding_up and
        character.is_holding_button_c

    if can_air_recover then
        -- Clear the global juggle counter and mark the character as recovered.
        character.custom_value_5 = 0
        character.is_knocked_down = false

        -- safe_land returns the player to a valid grounded state if the engine
        -- considers the character close enough to land safely.
        character.safe_land()
    end

    return true
end

Global Hit Aura With Per-Target Cooldown

Use a post hook for effects that should damage targets near a special owner or spawned field. The example below assumes another script sets custom_value_7 on characters inside the aura.

return function()
    local character = game.this_character

    if character == nil or not character.is_enemy then
        return true
    end

    -- custom_value_8 is this target's local cooldown. Without it, a global aura
    -- would hit every frame and drain health instantly.
    if character.custom_value_8 > 0 then
        character.custom_value_8 = character.custom_value_8 - 1
        return true
    end

    if character.custom_value_7 == 1 then
        character.damage_taken = 2
        character.is_being_hit = true

        -- check_being_hit applies the normal hit reaction fields and links.
        character.check_being_hit()

        character.custom_value_8 = 12
    end

    return true
end

Hook Performance Checklist

  • Guard with game.this_character, game.this_player, game.this_enemy, or game.this_item immediately.
  • Use object modes and animation IDs to avoid running logic on unrelated states.
  • Prefer custom_value_* cooldowns over scanning every entity every frame.
  • Avoid require inside hot hook bodies unless you intentionally load shared helper modules once.
  • Keep projectiles and effects in animation scripts when the rule only affects that one move.