When you subscribe to creature's OnBlocked event, it's possible to get this exception:
anvil | E [2026/03/21 13:40:26.469] [Anvil.AnvilCore] An exception occured while executing script "____anvil_event"
anvil | System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
anvil | ---> System.InvalidCastException: Unable to cast object of type 'Anvil.API.NwCreature' to type 'Anvil.API.NwDoor'.
anvil | at Anvil.API.IntegerExtensions.ToNwObject[T](UInt32 objectId) in /home/runner/work/Anvil/Anvil/NWN.Anvil/src/main/API/Extensions/IntegerExtensions.cs:line 119
anvil | at Anvil.API.Events.CreatureEvents.OnBlocked..ctor() in /home/runner/work/Anvil/Anvil/NWN.Anvil/src/main/API/Events/Game/CreatureEvents/CreatureEvents.OnBlocked.cs:line 21
anvil | at System.RuntimeType.CreateInstanceOfT()
anvil | --- End of inner exception stack trace ---
anvil | at System.RuntimeType.CreateInstanceOfT()
anvil | at System.Activator.CreateInstance[T]()
anvil | at Anvil.API.Events.GameEventFactory.<CheckConstructorRegistered>g__Constructor|12_0[TEvent]() in /home/runner/work/Anvil/Anvil/NWN.Anvil/src/main/API/Events/Game/GameEventFactory.cs:line 72
anvil | at Anvil.Services.ScriptDispatchService.TryExecuteScript(String script, UInt32 objectSelf) in /home/runner/work/Anvil/Anvil/NWN.Anvil/src/main/Services/Scripts/ScriptDispatchService.cs:line 22
anvil | at Anvil.AnvilCore.OnRunScript(IntPtr scriptPtr, UInt32 oidSelf) in /home/runner/work/Anvil/Anvil/NWN.Anvil/src/main/AnvilCore.FunctionHandlers.cs:line 91
The reason for this is quite simple. The event arguments contain this:
public NwDoor BlockingDoor { get; } = NWScript.GetBlockingDoor().ToNwObject<NwDoor>();
The BlockingDoor property isn't always a door. Sometimes it's a creature. This is contrary to GetBlockingDoor documentation, but even the default event handler proves this is a thing that does happen:
//::///////////////////////////////////////////////
//:: Default On Blocked
//:: NW_C2_DEFAULTE
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
This will cause blocked creatures to open
or smash down doors depending on int and
str.
*/
//:://////////////////////////////////////////////
//:: Created By: Preston Watamaniuk
//:: Created On: Nov 23, 2001
//:://////////////////////////////////////////////
void main()
{
object oDoor = GetBlockingDoor();
if (GetObjectType(oDoor) == OBJECT_TYPE_CREATURE)
{
// * Increment number of times blocked
/*SetLocalInt(OBJECT_SELF, "X2_NUMTIMES_BLOCKED", GetLocalInt(OBJECT_SELF, "X2_NUMTIMES_BLOCKED") + 1);
if (GetLocalInt(OBJECT_SELF, "X2_NUMTIMES_BLOCKED") > 3)
{
SpeakString("Blocked by creature");
SetLocalInt(OBJECT_SELF, "X2_NUMTIMES_BLOCKED",0);
ClearAllActions();
object oEnemy = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY);
if (GetIsObjectValid(oEnemy) == TRUE)
{
ActionEquipMostDamagingRanged(oEnemy);
ActionAttack(oEnemy);
}
return;
} */
return;
}
if(GetAbilityScore(OBJECT_SELF, ABILITY_INTELLIGENCE) >= 5)
{
if(GetIsDoorActionPossible(oDoor, DOOR_ACTION_OPEN) && GetAbilityScore(OBJECT_SELF, ABILITY_INTELLIGENCE) >= 7 )
{
DoDoorAction(oDoor, DOOR_ACTION_OPEN);
}
else if(GetIsDoorActionPossible(oDoor, DOOR_ACTION_BASH))
{
DoDoorAction(oDoor, DOOR_ACTION_BASH);
}
}
}
When you subscribe to creature's OnBlocked event, it's possible to get this exception:
The reason for this is quite simple. The event arguments contain this:
The BlockingDoor property isn't always a door. Sometimes it's a creature. This is contrary to
GetBlockingDoordocumentation, but even the default event handler proves this is a thing that does happen: