diff --git a/CHANGELOG.md b/CHANGELOG.md
index 221fc06d3..04b594fa8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file.
 
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 
+## 8193.34.27
+https://github.com/nwn-dotnet/Anvil/compare/v8193.34.26...v8193.34.27
+
+### Added
+- NwCreature: Added `BodyBag`, `BodyBagTemplate` properties.
+- NwPlaceable: Added `IsBodyBag` property.
+
+### Changed
+- OnPlayerGuiEvent: `EffectIcon` property is now nullable.
+- OnDebugPlayVisualEffect: `Effect` property is now nullable.
+- APIs that accept a `TableEntry` parameter now have implicit casts (e.g. `EffectIconTableEntry` & `EffectIcon`).
+
+### Fixed
+- NwCreature: Fixed an infinite loop caused by the `Associates` property when having dominated creature associates.
+- Added some index/range checks for some usages of game table data.
+
 ## 8193.34.26
 https://github.com/nwn-dotnet/Anvil/compare/v8193.34.25...v8193.34.26
 
diff --git a/NWN.Anvil/src/main/API/EngineStructures/ItemProperty.cs b/NWN.Anvil/src/main/API/EngineStructures/ItemProperty.cs
index 141263e59..6ed0d6810 100644
--- a/NWN.Anvil/src/main/API/EngineStructures/ItemProperty.cs
+++ b/NWN.Anvil/src/main/API/EngineStructures/ItemProperty.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Linq;
 using NWN.Core;
 using NWN.Native.API;
 
@@ -17,19 +18,7 @@ internal ItemProperty(CGameEffect effect, bool memoryOwn) : base(effect, memoryO
     /// <summary>
     /// Gets the cost table used by this item property.
     /// </summary>
-    public TwoDimArray<ItemPropertyCostTableEntry>? CostTable
-    {
-      get
-      {
-        int tableIndex = Effect.GetInteger(2);
-        if (tableIndex >= 0 && tableIndex < NwGameTables.ItemPropertyCostTables.Count)
-        {
-          return NwGameTables.ItemPropertyCostTables[tableIndex].Table;
-        }
-
-        return null;
-      }
-    }
+    public TwoDimArray<ItemPropertyCostTableEntry>? CostTable => NwGameTables.ItemPropertyCostTables.ElementAtOrDefault(Effect.GetInteger(2))?.Table;
 
     /// <summary>
     /// Gets or sets the cost table entry that is set for this item property.<br/>
@@ -62,19 +51,7 @@ public EffectDuration DurationType
     /// <summary>
     /// Gets the #1 param table used by this item property.
     /// </summary>
-    public TwoDimArray<ItemPropertyParamTableEntry>? Param1Table
-    {
-      get
-      {
-        int tableIndex = Effect.GetInteger(4);
-        if (tableIndex >= 0 && tableIndex < NwGameTables.ItemPropertyParamTables.Count)
-        {
-          return NwGameTables.ItemPropertyParamTables[tableIndex].Table;
-        }
-
-        return null;
-      }
-    }
+    public TwoDimArray<ItemPropertyParamTableEntry>? Param1Table => NwGameTables.ItemPropertyParamTables.ElementAtOrDefault(Effect.GetInteger(4))?.Table;
 
     /// <summary>
     /// Gets or sets the #1 param table entry that is set for this item property.<br/>
@@ -119,18 +96,7 @@ public ItemPropertyParamTableEntry? Param1TableValue
     /// </summary>
     public ItemPropertySubTypeTableEntry? SubType
     {
-      get
-      {
-        int tableIndex = Effect.GetInteger(1);
-        TwoDimArray<ItemPropertySubTypeTableEntry>? table = Property.SubTypeTable;
-
-        if (tableIndex >= 0 && table != null && tableIndex < table.Count)
-        {
-          return table[tableIndex];
-        }
-
-        return null;
-      }
+      get => Property.SubTypeTable?.ElementAtOrDefault(Effect.GetInteger(1));
       set => Effect.SetInteger(1, value?.RowIndex ?? -1);
     }
 
diff --git a/NWN.Anvil/src/main/API/Events/Game/ModuleEvents/ModuleEvents.OnPlayerGuiEvent.cs b/NWN.Anvil/src/main/API/Events/Game/ModuleEvents/ModuleEvents.OnPlayerGuiEvent.cs
index 569e2fb6c..cb69de62b 100644
--- a/NWN.Anvil/src/main/API/Events/Game/ModuleEvents/ModuleEvents.OnPlayerGuiEvent.cs
+++ b/NWN.Anvil/src/main/API/Events/Game/ModuleEvents/ModuleEvents.OnPlayerGuiEvent.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Linq;
 using Anvil.API.Events;
 using NWN.Core;
 
@@ -25,7 +26,7 @@ public sealed class OnPlayerGuiEvent : IEvent
       /// <summary>
       /// Gets the effect icon that was selected. Only valid in <see cref="GuiEventType.EffectIconClick"/> events.
       /// </summary>
-      public EffectIconTableEntry EffectIcon => NwGameTables.EffectIconTable[integerEventData];
+      public EffectIconTableEntry? EffectIcon => NwGameTables.EffectIconTable.ElementAtOrDefault(integerEventData);
 
       /// <summary>
       /// Gets the object data associated with this GUI event.
diff --git a/NWN.Anvil/src/main/API/Events/Native/DebugEvents/DebugEventFactory.cs b/NWN.Anvil/src/main/API/Events/Native/DebugEvents/DebugEventFactory.cs
index f189f8a0a..6cc53268c 100644
--- a/NWN.Anvil/src/main/API/Events/Native/DebugEvents/DebugEventFactory.cs
+++ b/NWN.Anvil/src/main/API/Events/Native/DebugEvents/DebugEventFactory.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Linq;
 using System.Numerics;
 using System.Runtime.InteropServices;
 using Anvil.Services;
@@ -120,7 +121,7 @@ private static OnDebugPlayVisualEffect HandleVisualEffectEvent(CNWSMessage messa
       {
         Player = player,
         TargetObject = target.ToNwObject(),
-        Effect = NwGameTables.VisualEffectTable[visualEffect],
+        Effect = NwGameTables.VisualEffectTable.ElementAtOrDefault(visualEffect),
         Duration = TimeSpan.FromSeconds(duration),
         TargetPosition = position,
       });
diff --git a/NWN.Anvil/src/main/API/Events/Native/DebugEvents/OnDebugPlayVisualEffect.cs b/NWN.Anvil/src/main/API/Events/Native/DebugEvents/OnDebugPlayVisualEffect.cs
index 90a58e3cd..5cadcb4f5 100644
--- a/NWN.Anvil/src/main/API/Events/Native/DebugEvents/OnDebugPlayVisualEffect.cs
+++ b/NWN.Anvil/src/main/API/Events/Native/DebugEvents/OnDebugPlayVisualEffect.cs
@@ -12,7 +12,7 @@ public sealed class OnDebugPlayVisualEffect : IEvent
     /// <summary>
     /// Gets the effect that is attempting to be played.
     /// </summary>
-    public VisualEffectTableEntry Effect { get; internal init; } = null!;
+    public VisualEffectTableEntry? Effect { get; internal init; }
 
     /// <summary>
     /// Gets the player attempting to spawn the visual effect.
diff --git a/NWN.Anvil/src/main/API/Objects/NwCreature.cs b/NWN.Anvil/src/main/API/Objects/NwCreature.cs
index d60c20e14..0cdf78bf2 100644
--- a/NWN.Anvil/src/main/API/Objects/NwCreature.cs
+++ b/NWN.Anvil/src/main/API/Objects/NwCreature.cs
@@ -52,7 +52,7 @@ internal CNWSCreature Creature
     internal NwCreature(CNWSCreature creature) : base(creature)
     {
       this.creature = creature;
-      faction = new NwFaction(creature.GetFaction());
+      faction = new NwFaction(Creature.GetFaction());
       Inventory = new Inventory(this, Creature.m_pcItemRepository);
     }
 
@@ -197,6 +197,20 @@ public byte BaseShieldArcaneSpellFailure
       set => Creature.m_pStats.m_nBaseShieldArcaneSpellFailure = value;
     }
 
+    /// <summary>
+    /// Gets the body bag assigned to this creature as a result of its death.
+    /// </summary>
+    public NwPlaceable? BodyBag => Creature.m_oidBodyBag.ToNwObject<NwPlaceable>();
+
+    /// <summary>
+    /// Gets or sets the body bag template to use when this creature dies.
+    /// </summary>
+    public BodyBagTableEntry BodyBagTemplate
+    {
+      get => NwGameTables.BodyBagTable[Creature.m_nBodyBag];
+      set => Creature.m_nBodyBag = (byte)value.RowIndex;
+    }
+
     /// <summary>
     /// Gets or sets the calculated challenge rating for this creature.
     /// </summary>
@@ -2529,16 +2543,23 @@ private async Task DoActionUnlockObject(NwGameObject target)
       NWScript.ActionUnlockObject(target);
     }
 
-    private IEnumerable<NwCreature> GetAssociates(AssociateType associateType)
+    private List<NwCreature> GetAssociates(AssociateType associateType)
     {
-      int i;
-      uint current;
+      List<NwCreature> associates = new List<NwCreature>();
       int type = (int)associateType;
 
-      for (i = 1, current = NWScript.GetAssociate(type, this, i); current != Invalid; i++, current = NWScript.GetAssociate(type, this, i))
+      for (int i = 0;; i++)
       {
-        yield return current.ToNwObject<NwCreature>()!;
+        NwCreature? associate = NWScript.GetAssociate(type, this, i).ToNwObject<NwCreature>();
+        if (associate == null || associates.Contains(associate))
+        {
+          break;
+        }
+
+        associates.Add(associate);
       }
+
+      return associates;
     }
 
     private PlayerQuickBarButton InternalGetQuickBarButton(byte index)
diff --git a/NWN.Anvil/src/main/API/Objects/NwPlaceable.cs b/NWN.Anvil/src/main/API/Objects/NwPlaceable.cs
index f3eeb7c59..1227b1813 100644
--- a/NWN.Anvil/src/main/API/Objects/NwPlaceable.cs
+++ b/NWN.Anvil/src/main/API/Objects/NwPlaceable.cs
@@ -70,6 +70,11 @@ public bool Illumination
     /// </summary>
     public Inventory Inventory { get; }
 
+    /// <summary>
+    /// Gets if this is a body bag placeable, spawned from a creature's death.
+    /// </summary>
+    public bool IsBodyBag => placeable.m_bIsBodyBag.ToBool();
+
     public bool IsStatic
     {
       get => Placeable.m_bStaticObject.ToBool();
diff --git a/NWN.Anvil/src/main/API/TwoDimArray/Tables/AppearanceTableEntry.cs b/NWN.Anvil/src/main/API/TwoDimArray/Tables/AppearanceTableEntry.cs
index 989a7c020..8c72c08d3 100644
--- a/NWN.Anvil/src/main/API/TwoDimArray/Tables/AppearanceTableEntry.cs
+++ b/NWN.Anvil/src/main/API/TwoDimArray/Tables/AppearanceTableEntry.cs
@@ -1,3 +1,5 @@
+using System.Linq;
+
 namespace Anvil.API
 {
   /// <summary>
@@ -115,5 +117,10 @@ void ITwoDimArrayEntry.InterpretEntry(TwoDimArrayEntry entry)
       BodyBag = entry.GetTableEntry("BODY_BAG", NwGameTables.BodyBagTable);
       Targetable = entry.GetBool("TARGETABLE");
     }
+
+    public static implicit operator AppearanceTableEntry?(AppearanceType appearanceType)
+    {
+      return NwGameTables.AppearanceTable.ElementAtOrDefault((int)appearanceType);
+    }
   }
 }
diff --git a/NWN.Anvil/src/main/API/TwoDimArray/Tables/EffectIconTableEntry.cs b/NWN.Anvil/src/main/API/TwoDimArray/Tables/EffectIconTableEntry.cs
index 368c622a5..43b49bb61 100644
--- a/NWN.Anvil/src/main/API/TwoDimArray/Tables/EffectIconTableEntry.cs
+++ b/NWN.Anvil/src/main/API/TwoDimArray/Tables/EffectIconTableEntry.cs
@@ -1,3 +1,5 @@
+using System.Linq;
+
 namespace Anvil.API
 {
   /// <summary>
@@ -28,5 +30,10 @@ public void InterpretEntry(TwoDimArrayEntry entry)
       Icon = entry.GetString("Icon");
       StrRef = entry.GetStrRef("StrRef");
     }
+
+    public static implicit operator EffectIconTableEntry?(EffectIcon effectIcon)
+    {
+      return NwGameTables.EffectIconTable.ElementAtOrDefault((int)effectIcon);
+    }
   }
 }
diff --git a/NWN.Anvil/src/main/API/TwoDimArray/Tables/ItemPropertyTableEntry.cs b/NWN.Anvil/src/main/API/TwoDimArray/Tables/ItemPropertyTableEntry.cs
index 186de59a5..613eb8ae1 100644
--- a/NWN.Anvil/src/main/API/TwoDimArray/Tables/ItemPropertyTableEntry.cs
+++ b/NWN.Anvil/src/main/API/TwoDimArray/Tables/ItemPropertyTableEntry.cs
@@ -1,3 +1,5 @@
+using System.Linq;
+
 namespace Anvil.API
 {
   public sealed class ItemPropertyTableEntry : ITwoDimArrayEntry
@@ -53,7 +55,7 @@ public sealed class ItemPropertyTableEntry : ITwoDimArrayEntry
 
     void ITwoDimArrayEntry.InterpretEntry(TwoDimArrayEntry entry)
     {
-      ItemMap = NwGameTables.ItemPropertyItemMapTable.GetRow(RowIndex);
+      ItemMap = NwGameTables.ItemPropertyItemMapTable.ElementAtOrDefault(RowIndex);
       Name = entry.GetStrRef("Name");
       Label = entry.GetString("Label");
       SubTypeTable = entry.GetTable<ItemPropertySubTypeTableEntry>("SubTypeResRef");
@@ -63,5 +65,10 @@ void ITwoDimArrayEntry.InterpretEntry(TwoDimArrayEntry entry)
       GameStrRef = entry.GetStrRef("GameStrRef");
       Description = entry.GetStrRef("Description");
     }
+
+    public static implicit operator ItemPropertyTableEntry?(ItemPropertyType propertyType)
+    {
+      return NwGameTables.ItemPropertyTable.ElementAtOrDefault((int)propertyType);
+    }
   }
 }
diff --git a/NWN.Anvil/src/main/API/TwoDimArray/Tables/PartsTableEntry.cs b/NWN.Anvil/src/main/API/TwoDimArray/Tables/PartsTableEntry.cs
index 6c325f538..b61aee853 100644
--- a/NWN.Anvil/src/main/API/TwoDimArray/Tables/PartsTableEntry.cs
+++ b/NWN.Anvil/src/main/API/TwoDimArray/Tables/PartsTableEntry.cs
@@ -1,3 +1,5 @@
+using System.Linq;
+
 namespace Anvil.API
 {
   public sealed class PartsTableEntry : ITwoDimArrayEntry
@@ -14,7 +16,7 @@ public void InterpretEntry(TwoDimArrayEntry entry)
     {
       CostModifier = entry.GetInt("COSTMODIFIER");
       ACBonus = entry.GetFloat("ACBONUS");
-      ArmorTableEntry = ACBonus.HasValue ? NwGameTables.ArmorTable[(int)ACBonus.Value] : null;
+      ArmorTableEntry = ACBonus.HasValue ? NwGameTables.ArmorTable.ElementAtOrDefault((int)ACBonus.Value) : null;
     }
   }
 }
diff --git a/NWN.Anvil/src/main/API/TwoDimArray/Tables/ProgrammedEffectTableEntry.cs b/NWN.Anvil/src/main/API/TwoDimArray/Tables/ProgrammedEffectTableEntry.cs
index f7778a69d..dea174ca7 100644
--- a/NWN.Anvil/src/main/API/TwoDimArray/Tables/ProgrammedEffectTableEntry.cs
+++ b/NWN.Anvil/src/main/API/TwoDimArray/Tables/ProgrammedEffectTableEntry.cs
@@ -1,3 +1,5 @@
+using System.Linq;
+
 namespace Anvil.API
 {
   public sealed class ProgrammedEffectTableEntry : ITwoDimArrayEntry
@@ -43,5 +45,10 @@ public void InterpretEntry(TwoDimArrayEntry entry)
         intParamValues[i] = entry.GetInt(columnName);
       }
     }
+
+    public static implicit operator ProgrammedEffectTableEntry?(ProgFxType fxType)
+    {
+      return NwGameTables.ProgrammedEffectTable.ElementAtOrDefault((int)fxType);
+    }
   }
 }
diff --git a/NWN.Anvil/src/main/API/TwoDimArray/Tables/VisualEffectTableEntry.cs b/NWN.Anvil/src/main/API/TwoDimArray/Tables/VisualEffectTableEntry.cs
index bb2ea81a8..49e79fd42 100644
--- a/NWN.Anvil/src/main/API/TwoDimArray/Tables/VisualEffectTableEntry.cs
+++ b/NWN.Anvil/src/main/API/TwoDimArray/Tables/VisualEffectTableEntry.cs
@@ -1,3 +1,5 @@
+using System.Linq;
+
 namespace Anvil.API
 {
   public sealed class VisualEffectTableEntry : ITwoDimArrayEntry
@@ -88,5 +90,10 @@ void ITwoDimArrayEntry.InterpretEntry(TwoDimArrayEntry entry)
       LowQualityVariant = entry.GetString("LowQuality");
       OrientWithObject = entry.GetBool("OrientWithObject");
     }
+
+    public static implicit operator VisualEffectTableEntry?(VfxType vfxType)
+    {
+      return NwGameTables.VisualEffectTable.ElementAtOrDefault((int)vfxType);
+    }
   }
 }
diff --git a/NWN.Anvil/src/main/Services/API/Creature/DamageLevelOverrideService.cs b/NWN.Anvil/src/main/Services/API/Creature/DamageLevelOverrideService.cs
index 5c02edcdb..713b8fdf1 100644
--- a/NWN.Anvil/src/main/Services/API/Creature/DamageLevelOverrideService.cs
+++ b/NWN.Anvil/src/main/Services/API/Creature/DamageLevelOverrideService.cs
@@ -1,3 +1,4 @@
+using System.Linq;
 using Anvil.API;
 using NLog;
 using NWN.Native.API;
@@ -36,7 +37,7 @@ public void ClearDamageLevelOverride(NwCreature creature)
       InternalVariableInt damageLevelOverride = InternalVariables.DamageLevelOverride(creature);
       if (damageLevelOverride.HasValue)
       {
-        return NwGameTables.DamageLevelTable[damageLevelOverride.Value];
+        return NwGameTables.DamageLevelTable.ElementAtOrDefault(damageLevelOverride.Value);
       }
 
       return null;