diff --git a/apps/openmw/mwmechanics/levelledlist.cpp b/apps/openmw/mwmechanics/levelledlist.cpp
new file mode 100644
index 0000000000..4dcafff49f
--- /dev/null
+++ b/apps/openmw/mwmechanics/levelledlist.cpp
@@ -0,0 +1,74 @@
+#include <components/debug/debuglog.hpp>
+#include <components/esm3/loadlevlist.hpp>
+
+#include "../mwworld/class.hpp"
+#include "../mwworld/esmstore.hpp"
+#include "../mwworld/manualref.hpp"
+#include "../mwworld/ptr.hpp"
+
+#include "../mwbase/environment.hpp"
+#include "../mwbase/world.hpp"
+
+#include "actorutil.hpp"
+#include "creaturestats.hpp"
+#include "levelledlist.hpp"
+
+namespace MWMechanics
+{
+
+    const ESM::RefId& getLevelledItem(const ESM::LevelledListBase* levItem, bool creature, Misc::Rng::Generator& prng)
+    {
+        const std::vector<ESM::LevelledListBase::LevelItem>& items = levItem->mList;
+
+        const MWWorld::Ptr& player = getPlayer();
+        int playerLevel = player.getClass().getCreatureStats(player).getLevel();
+
+        if (Misc::Rng::roll0to99(prng) < levItem->mChanceNone)
+            return ESM::RefId::sEmpty;
+
+        std::vector<const ESM::RefId*> candidates;
+        int highestLevel = 0;
+        for (const auto& levelledItem : items)
+        {
+            if (levelledItem.mLevel > highestLevel && levelledItem.mLevel <= playerLevel)
+                highestLevel = levelledItem.mLevel;
+        }
+
+        // For levelled creatures, the flags are swapped. This file format just makes so much sense.
+        bool allLevels = (levItem->mFlags & ESM::ItemLevList::AllLevels) != 0;
+        if (creature)
+            allLevels = levItem->mFlags & ESM::CreatureLevList::AllLevels;
+
+        for (const auto& levelledItem : items)
+        {
+            if (playerLevel >= levelledItem.mLevel && (allLevels || levelledItem.mLevel == highestLevel))
+                candidates.push_back(&levelledItem.mId);
+        }
+        if (candidates.empty())
+            return ESM::RefId::sEmpty;
+        const ESM::RefId& item = *candidates[Misc::Rng::rollDice(candidates.size(), prng)];
+
+        // Vanilla doesn't fail on nonexistent items in levelled lists
+        if (!MWBase::Environment::get().getWorld()->getStore().find(item))
+        {
+            Log(Debug::Warning) << "Warning: ignoring nonexistent item " << item << " in levelled list "
+                                << levItem->mId;
+            return ESM::RefId::sEmpty;
+        }
+
+        // Is this another levelled item or a real item?
+        MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), item, 1);
+        if (ref.getPtr().getType() != ESM::ItemLevList::sRecordId
+            && ref.getPtr().getType() != ESM::CreatureLevList::sRecordId)
+        {
+            return item;
+        }
+        else
+        {
+            if (ref.getPtr().getType() == ESM::ItemLevList::sRecordId)
+                return getLevelledItem(ref.getPtr().get<ESM::ItemLevList>()->mBase, false, prng);
+            else
+                return getLevelledItem(ref.getPtr().get<ESM::CreatureLevList>()->mBase, true, prng);
+        }
+    }
+}
diff --git a/apps/openmw/mwmechanics/levelledlist.hpp b/apps/openmw/mwmechanics/levelledlist.hpp
index 80579ea09a..08d9457bca 100644
--- a/apps/openmw/mwmechanics/levelledlist.hpp
+++ b/apps/openmw/mwmechanics/levelledlist.hpp
@@ -1,81 +1,19 @@
 #ifndef OPENMW_MECHANICS_LEVELLEDLIST_H
 #define OPENMW_MECHANICS_LEVELLEDLIST_H
 
-#include <components/debug/debuglog.hpp>
-#include <components/esm3/loadlevlist.hpp>
 #include <components/misc/rng.hpp>
 
-#include "../mwworld/class.hpp"
-#include "../mwworld/esmstore.hpp"
-#include "../mwworld/manualref.hpp"
-#include "../mwworld/ptr.hpp"
-
-#include "../mwbase/environment.hpp"
-#include "../mwbase/world.hpp"
-
-#include "actorutil.hpp"
-#include "creaturestats.hpp"
+namespace ESM
+{
+    struct LevelledListBase;
+    class RefId;
+}
 
 namespace MWMechanics
 {
 
     /// @return ID of resulting item, or empty if none
-    inline const ESM::RefId& getLevelledItem(
-        const ESM::LevelledListBase* levItem, bool creature, Misc::Rng::Generator& prng)
-    {
-        const std::vector<ESM::LevelledListBase::LevelItem>& items = levItem->mList;
-
-        const MWWorld::Ptr& player = getPlayer();
-        int playerLevel = player.getClass().getCreatureStats(player).getLevel();
-
-        if (Misc::Rng::roll0to99(prng) < levItem->mChanceNone)
-            return ESM::RefId::sEmpty;
-
-        std::vector<const ESM::RefId*> candidates;
-        int highestLevel = 0;
-        for (const auto& levelledItem : items)
-        {
-            if (levelledItem.mLevel > highestLevel && levelledItem.mLevel <= playerLevel)
-                highestLevel = levelledItem.mLevel;
-        }
-
-        // For levelled creatures, the flags are swapped. This file format just makes so much sense.
-        bool allLevels = (levItem->mFlags & ESM::ItemLevList::AllLevels) != 0;
-        if (creature)
-            allLevels = levItem->mFlags & ESM::CreatureLevList::AllLevels;
-
-        for (const auto& levelledItem : items)
-        {
-            if (playerLevel >= levelledItem.mLevel && (allLevels || levelledItem.mLevel == highestLevel))
-                candidates.push_back(&levelledItem.mId);
-        }
-        if (candidates.empty())
-            return ESM::RefId::sEmpty;
-        const ESM::RefId& item = *candidates[Misc::Rng::rollDice(candidates.size(), prng)];
-
-        // Vanilla doesn't fail on nonexistent items in levelled lists
-        if (!MWBase::Environment::get().getWorld()->getStore().find(item))
-        {
-            Log(Debug::Warning) << "Warning: ignoring nonexistent item " << item << " in levelled list "
-                                << levItem->mId;
-            return ESM::RefId::sEmpty;
-        }
-
-        // Is this another levelled item or a real item?
-        MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), item, 1);
-        if (ref.getPtr().getType() != ESM::ItemLevList::sRecordId
-            && ref.getPtr().getType() != ESM::CreatureLevList::sRecordId)
-        {
-            return item;
-        }
-        else
-        {
-            if (ref.getPtr().getType() == ESM::ItemLevList::sRecordId)
-                return getLevelledItem(ref.getPtr().get<ESM::ItemLevList>()->mBase, false, prng);
-            else
-                return getLevelledItem(ref.getPtr().get<ESM::CreatureLevList>()->mBase, true, prng);
-        }
-    }
+    const ESM::RefId& getLevelledItem(const ESM::LevelledListBase* levItem, bool creature, Misc::Rng::Generator& prng);
 
 }
 
diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp
index c96e0cdc76..f40f0474cd 100644
--- a/apps/openmw/mwworld/containerstore.cpp
+++ b/apps/openmw/mwworld/containerstore.cpp
@@ -6,6 +6,7 @@
 #include <components/debug/debuglog.hpp>
 #include <components/esm3/inventorystate.hpp>
 #include <components/esm3/loadench.hpp>
+#include <components/esm3/loadlevlist.hpp>
 #include <components/misc/strings/algorithm.hpp>
 #include <components/misc/strings/lower.hpp>
 #include <components/sceneutil/positionattitudetransform.hpp>
diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp
index 4bb56b9176..8c4fde332e 100644
--- a/apps/openmw/mwworld/worldimp.cpp
+++ b/apps/openmw/mwworld/worldimp.cpp
@@ -21,6 +21,7 @@
 #include <components/esm3/loadcrea.hpp>
 #include <components/esm3/loadench.hpp>
 #include <components/esm3/loadgmst.hpp>
+#include <components/esm3/loadlevlist.hpp>
 #include <components/esm3/loadmgef.hpp>
 #include <components/esm3/loadregn.hpp>
 #include <components/esm3/loadstat.hpp>