Anubis: Sending and Receiving Events

From Baldur's Gate 3 Modding

Overview

Events are a powerful tool in Anubis scripting that allow you to trigger custom behaviour when certain conditions are met. Whether you're sending a simple notification to an entity or handling more complex scenarios with parameters, events play a crucial role in scripting dynamic behaviours. This guide will walk you through how to send, receive, and handle both simple and parameterised events in Anubis.

Sending a Simple Event

To send a basic event in Anubis, you use the same function as you would in Osiris, but with the added flexibility that Anubis provides.

Syntax for Sending a Simple Event

SetEntityEvent(entity, eventName)

This is identical to how you would send a similar event in Osiris. For example, to tell an entity (in this case, the guard me) to raise the alarm:

SetEntityEvent(me, "RaiseAlarm")

Receiving a Simple Event

In Anubis, receiving events is straightforward. You define an event handler using the events.EntityEvent function, which listens for events targeting a specific entity.

events.EntityEvent = function(e)
    if e.TargetEntity == me and e.Event == "RaiseAlarm" then
      SetFlag(electedForAlarm, me)
    end
end

In this example:

  • The event handler listens for the RaiseAlarm event.
  • If the event is sent to the current entity (me), the handler sets a flag (electedForAlarm), which might unlock further behaviours.

Sending a Custom Event with Parameters

You can use Anubis to send events with custom parameters to both Anubis and Osiris using the function:

SetEntityEvent(entity, "RaiseAlarm", parameters)

However, when working with both Anubis and Osiris, it's important to understand the differences in how you send events to these frameworks. While the SetEntityEvent function is used in both cases, the behaviour and limitations differ between the two.

Limitations in Osiris:

  • The entity must be either a character or an item.
  • The parameters must be either empty or contain exactly one element, and that element must be a character or item entity.

For example, this would be valid to send an event to Osiris:

SetEntityEvent(characterEntity, "RaiseAlarm", guardCharacter)

In this case, the event "RaiseAlarm" is sent to characterEntity with guardCharacter as the parameter.

Sending Events to Anubis

In Anubis, the SetEntityEvent function offers more flexibility:

SetEntityEvent(entity, eventName, parameters)

Differences in Anubis:

  • The entity can be any entity type, not just characters or items.
  • The parameters can be of any type – entities, booleans, floats, etc. – and you can pass more than one parameter.

For example, this would be valid to send an event to Anubis:

SetEntityEvent(me, "RaiseAlarm", alarmEntity, 5.0)

Accessing Parameters in the Event Handler

To handle an event with parameters in Anubis, you can access the Params field of the event.

events.EntityEvent = function(e)
   if e.TargetEntity == me and e.Event == "RaiseAlarm" then
	alarm = e.Params[1] -- alarmEntity
	delay = e.Params[2] -- 5.0
   end
end

Handling Events Without Immediate Actions

In Anubis, events cannot trigger long-running actions directly (MoveTo, CastSpell, etc.). These actions need to be handled in states rather than event handlers. Here's how to handle such scenarios:

Incorrect Approach

The approach below won't work – it includes the long-running action MoveTo:

events.EntityEvent = function(e)
   if e.TargetEntity == me and e.Event == "RaiseAlarm" then
      -- This will not work because MoveTo is a long-running action.
      MoveTo(me, alarm)
   end
end

Correct Approach

Instead of performing a long-running action directly in the event handler, use the event to set a flag or update a variable, which can then trigger a new state:

events.EntityEvent = function(e) 
   if e.TargetEntity == me and e.Event == "RaiseAlarm" then 
      SetFlag(runningToAlarm, me)
   end
end

The flag runningToAlarm is set, and a new state responsible for moving the entity will be unlocked in the behaviour tree.

Standard Events in Anubis

In addition to custom events, Anubis supports a wide variety of standard events that can be used to handle predefined game behaviours. Some of the commonly used standard events include:

  • FlagSet: Triggered when a flag is set.
  • FlagCleared: Triggered when a flag is cleared.
  • EnteredTrigger: Triggered when an entity enters a specified trigger.
  • LeftTrigger: Triggered when an entity leaves a specified trigger.

Example of Handling a Standard Event

local alarmRaised = Flag("AlarmRaised_af8d5e48-c937-40ec-a8b0-4a5b3e50c845") 

events.FlagSet = function(e) 
   if e.Flag == alarmRaised.Guid then 
      -- Alarm has been raised 
   end 
end

In this example:

  • We listen for the FlagSet event, which triggers when a flag is set.
  • The flag being monitored is alarmRaised.
  • Note: e.Flag is of type Guid, so you must compare it to alarmRaised.Guid rather than the flag directly.

Important Considerations for Events in Anubis

Events Sent to All States

Events are sent to all states, whether they are active or inactive. This ensures that states can react to global game events even if they aren’t currently running.

Event Order

Events of the same type arrive in the order they were sent. However, events of different types may arrive in any order relative to each other. Make sure to design your event handlers accordingly.

Single Event Handler Limitation

In Anubis, you cannot have more than one event handler for a specific event type (both custom and standard events) in the same script.

For example, the following code is incorrect because it defines two separate handlers for the EntityEvent:

events.EntityEvent = function(e)
    if e.TargetEntity == me then
        if e.Event == "RaiseAlarm" then
            SetFlag(electedForAlarm, me)
        end
    end
end

events.EntityEvent = function(e)
    if e.TargetEntity == me then
        if e.Event == "StopAlarm" then
            ClearFlag(electedForAlarm, me)
        end
    end
end

The correct approach is to combine the logic into a single handler, like this:

events.EntityEvent = function(e)
    if e.TargetEntity == me then
        if e.Event == "RaiseAlarm" then
            SetFlag(electedForAlarm, me)
        elseif e.Event == "StopAlarm" then
            ClearFlag(electedForAlarm, me)
        end
    end
end

By using a single handler for each event type, you ensure that all event logic is processed correctly within the same function.

Conclusion

In Anubis, events are a versatile and powerful mechanism for creating dynamic behaviours. Whether you're sending simple notifications or complex events with multiple parameters, Anubis provides the flexibility you need to manage your entities. Just remember:

  • Direct event-handling should be limited to simple, immediate effects.
  • For long-running actions, use events to set flags and unlock states that handle the heavy lifting.

With this guide, you should now have a solid understanding of how to send, receive, and handle events in Anubis, opening up endless possibilities for scripting custom behaviours in your game.