diff --git a/source/blood/CMakeLists.txt b/source/blood/CMakeLists.txt
index d473b60cf..c6db6f310 100644
--- a/source/blood/CMakeLists.txt
+++ b/source/blood/CMakeLists.txt
@@ -54,6 +54,7 @@ set( PCH_SOURCES
 	src/osdcmd.cpp
 	src/player.cpp
 	src/prediction.cpp
+	src/preload.cpp
 	src/qav.cpp
 	src/replace.cpp
 	src/sbar.cpp
diff --git a/source/blood/src/blood.cpp b/source/blood/src/blood.cpp
index c4b8ab8e0..e38d99010 100644
--- a/source/blood/src/blood.cpp
+++ b/source/blood/src/blood.cpp
@@ -79,45 +79,6 @@ int gChokeCounter = 0;
 
 bool gQuitGame;
 
-enum gametokens
-{
-    T_INCLUDE = 0,
-    T_INTERFACE = 0,
-    T_LOADGRP = 1,
-    T_MODE = 1,
-    T_CACHESIZE = 2,
-    T_ALLOW = 2,
-    T_NOAUTOLOAD,
-    T_INCLUDEDEFAULT,
-    T_SOUND,
-    T_FILE,
-    //T_CUTSCENE,
-    //T_ANIMSOUNDS,
-    //T_NOFLOORPALRANGE,
-    T_ID,
-    T_MINPITCH,
-    T_MAXPITCH,
-    T_PRIORITY,
-    T_TYPE,
-    T_DISTANCE,
-    T_VOLUME,
-    T_DELAY,
-    T_RENAMEFILE,
-    T_GLOBALGAMEFLAGS,
-    T_ASPECT,
-    T_FORCEFILTER,
-    T_FORCENOFILTER,
-    T_TEXTUREFILTER,
-    T_RFFDEFINEID,
-    T_TILEFROMTEXTURE,
-    T_IFCRC, T_IFMATCH, T_CRC32,
-    T_SIZE,
-    T_SURFACE,
-    T_VOXEL,
-    T_VIEW,
-    T_SHADE,
-};
-
 int blood_globalflags;
 
 void QuitGame(void)
@@ -125,216 +86,6 @@ void QuitGame(void)
     throw CExitEvent(0);
 }
 
-void PrecacheDude(spritetype *pSprite)
-{
-    DUDEINFO *pDudeInfo = getDudeInfo(pSprite->type);
-    seqPrecacheId(pDudeInfo->seqStartID);
-    seqPrecacheId(pDudeInfo->seqStartID+5);
-    seqPrecacheId(pDudeInfo->seqStartID+1);
-    seqPrecacheId(pDudeInfo->seqStartID+2);
-    switch (pSprite->type)
-    {
-    case kDudeCultistTommy:
-    case kDudeCultistShotgun:
-    case kDudeCultistTesla:
-    case kDudeCultistTNT:
-        seqPrecacheId(pDudeInfo->seqStartID+6);
-        seqPrecacheId(pDudeInfo->seqStartID+7);
-        seqPrecacheId(pDudeInfo->seqStartID+8);
-        seqPrecacheId(pDudeInfo->seqStartID+9);
-        seqPrecacheId(pDudeInfo->seqStartID+13);
-        seqPrecacheId(pDudeInfo->seqStartID+14);
-        seqPrecacheId(pDudeInfo->seqStartID+15);
-        break;
-    case kDudeZombieButcher:
-    case kDudeGillBeast:
-        seqPrecacheId(pDudeInfo->seqStartID+6);
-        seqPrecacheId(pDudeInfo->seqStartID+7);
-        seqPrecacheId(pDudeInfo->seqStartID+8);
-        seqPrecacheId(pDudeInfo->seqStartID+9);
-        seqPrecacheId(pDudeInfo->seqStartID+10);
-        seqPrecacheId(pDudeInfo->seqStartID+11);
-        break;
-    case kDudeGargoyleStatueFlesh:
-    case kDudeGargoyleStatueStone:
-        seqPrecacheId(pDudeInfo->seqStartID+6);
-        seqPrecacheId(pDudeInfo->seqStartID+6);
-        fallthrough__;
-    case kDudeGargoyleFlesh:
-    case kDudeGargoyleStone:
-        seqPrecacheId(pDudeInfo->seqStartID+6);
-        seqPrecacheId(pDudeInfo->seqStartID+7);
-        seqPrecacheId(pDudeInfo->seqStartID+8);
-        seqPrecacheId(pDudeInfo->seqStartID+9);
-        break;
-    case kDudePhantasm:
-    case kDudeHellHound:
-    case kDudeSpiderBrown:
-    case kDudeSpiderRed:
-    case kDudeSpiderBlack:
-    case kDudeSpiderMother:
-    case kDudeTchernobog:
-        seqPrecacheId(pDudeInfo->seqStartID+6);
-        seqPrecacheId(pDudeInfo->seqStartID+7);
-        seqPrecacheId(pDudeInfo->seqStartID+8);
-        break;
-    case kDudeCerberusTwoHead:
-        seqPrecacheId(pDudeInfo->seqStartID+6);
-        seqPrecacheId(pDudeInfo->seqStartID+7);
-        fallthrough__;
-    case kDudeHand:
-    case kDudeBoneEel:
-    case kDudeBat:
-    case kDudeRat:
-        seqPrecacheId(pDudeInfo->seqStartID+6);
-        seqPrecacheId(pDudeInfo->seqStartID+7);
-        break;
-    case kDudeCultistBeast:
-        seqPrecacheId(pDudeInfo->seqStartID+6);
-        break;
-    case kDudeZombieAxeBuried:
-        seqPrecacheId(pDudeInfo->seqStartID+12);
-        seqPrecacheId(pDudeInfo->seqStartID+9);
-        fallthrough__;
-    case kDudeZombieAxeLaying:
-        seqPrecacheId(pDudeInfo->seqStartID+10);
-        fallthrough__;
-    case kDudeZombieAxeNormal:
-        seqPrecacheId(pDudeInfo->seqStartID+6);
-        seqPrecacheId(pDudeInfo->seqStartID+7);
-        seqPrecacheId(pDudeInfo->seqStartID+8);
-        seqPrecacheId(pDudeInfo->seqStartID+11);
-        seqPrecacheId(pDudeInfo->seqStartID+13);
-        seqPrecacheId(pDudeInfo->seqStartID+14);
-        break;
-    }
-}
-
-void PrecacheThing(spritetype *pSprite) {
-    switch (pSprite->type) {
-        case kThingGlassWindow: // worthless...
-        case kThingFluorescent:
-            seqPrecacheId(12);
-            break;
-        case kThingSpiderWeb:
-            seqPrecacheId(15);
-            break;
-        case kThingMetalGrate:
-            seqPrecacheId(21);
-            break;
-        case kThingFlammableTree:
-            seqPrecacheId(25);
-            seqPrecacheId(26);
-            break;
-        case kTrapMachinegun:
-            seqPrecacheId(38);
-            seqPrecacheId(40);
-            seqPrecacheId(28);
-            break;
-        case kThingObjectGib:
-        //case kThingObjectExplode: weird that only gib object is precached and this one is not
-            break;
-    }
-    tilePrecacheTile(pSprite->picnum);
-}
-
-void PreloadTiles(void)
-{
-    nPrecacheCount = 0;
-    int skyTile = -1;
-    memset(gotpic,0,sizeof(gotpic));
-    // Fonts
-    for (int i = 0; i < numsectors; i++)
-    {
-        tilePrecacheTile(sector[i].floorpicnum, 0);
-        tilePrecacheTile(sector[i].ceilingpicnum, 0);
-        if ((sector[i].ceilingstat&1) != 0 && skyTile == -1)
-            skyTile = sector[i].ceilingpicnum;
-    }
-    for (int i = 0; i < numwalls; i++)
-    {
-        tilePrecacheTile(wall[i].picnum, 0);
-        if (wall[i].overpicnum >= 0)
-            tilePrecacheTile(wall[i].overpicnum, 0);
-    }
-    for (int i = 0; i < kMaxSprites; i++)
-    {
-        if (sprite[i].statnum < kMaxStatus)
-        {
-            spritetype *pSprite = &sprite[i];
-            switch (pSprite->statnum)
-            {
-            case kStatDude:
-                PrecacheDude(pSprite);
-                break;
-            case kStatThing:
-                PrecacheThing(pSprite);
-                break;
-            default:
-                tilePrecacheTile(pSprite->picnum);
-                break;
-            }
-        }
-    }
-
-    // Precache common SEQs
-    for (int i = 0; i < 100; i++)
-    {
-        seqPrecacheId(i);
-    }
-
-    tilePrecacheTile(1147); // water drip
-    tilePrecacheTile(1160); // blood drip
-
-    // Player SEQs
-    seqPrecacheId(dudeInfo[31].seqStartID+6);
-    seqPrecacheId(dudeInfo[31].seqStartID+7);
-    seqPrecacheId(dudeInfo[31].seqStartID+8);
-    seqPrecacheId(dudeInfo[31].seqStartID+9);
-    seqPrecacheId(dudeInfo[31].seqStartID+10);
-    seqPrecacheId(dudeInfo[31].seqStartID+14);
-    seqPrecacheId(dudeInfo[31].seqStartID+15);
-    seqPrecacheId(dudeInfo[31].seqStartID+12);
-    seqPrecacheId(dudeInfo[31].seqStartID+16);
-    seqPrecacheId(dudeInfo[31].seqStartID+17);
-    seqPrecacheId(dudeInfo[31].seqStartID+18);
-
-    if (skyTile > -1 && skyTile < kMaxTiles)
-    {
-        for (int i = 1; i < gSkyCount; i++)
-            tilePrecacheTile(skyTile+i, 0);
-    }
-
-    WeaponPrecache();
-    viewPrecacheTiles();
-    fxPrecache();
-    gibPrecache();
-
-    I_GetEvent();
-}
-
-void PreloadCache(void)
-{
-    PreloadTiles();
-    int cnt = 0;
-    int percentDisplayed = -1;
-
-    for (int i = 0; i < kMaxTiles; i++)
-    {
-        if (TestBitString(gotpic, i))
-        {
-            // For the hardware renderer precaching the raw pixel data is pointless.
-            if (videoGetRenderMode() < REND_POLYMOST)
-                tileLoad(i);
-
-            if (r_precache) PrecacheHardwareTextures(i);
-
-            if ((++cnt & 7) == 0)
-                I_GetEvent();
-        }
-    }
-    memset(gotpic,0,sizeof(gotpic));
-}
 
 void EndLevel(void)
 {
diff --git a/source/blood/src/preload.cpp b/source/blood/src/preload.cpp
new file mode 100644
index 000000000..9b71efb5b
--- /dev/null
+++ b/source/blood/src/preload.cpp
@@ -0,0 +1,291 @@
+//-------------------------------------------------------------------------
+/*
+Copyright (C) 2010-2019 EDuke32 developers and contributors
+Copyright (C) 2019 Nuke.YKT
+
+This file is part of NBlood.
+
+NBlood is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License version 2
+as published by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+//-------------------------------------------------------------------------
+
+#include "ns.h"	// Must come before everything else!
+#include "build.h"
+#include "common_game.h"
+#include "dude.h"
+#include "seq.h"
+#include "view.h"
+#include "fx.h"
+#include "gib.h"
+#include "g_input.h"
+
+BEGIN_BLD_NS
+
+// To do: This needs to handle the sprite palettes as well to properly precache the needed content.
+
+void viewPrecacheTiles(void)
+{
+    tilePrecacheTile(2173, 0);
+    tilePrecacheTile(2200, 0);
+    tilePrecacheTile(2201, 0);
+    tilePrecacheTile(2202, 0);
+    tilePrecacheTile(2207, 0);
+    tilePrecacheTile(2208, 0);
+    tilePrecacheTile(2209, 0);
+    tilePrecacheTile(2229, 0);
+    tilePrecacheTile(2260, 0);
+    tilePrecacheTile(2559, 0);
+    tilePrecacheTile(2169, 0);
+    tilePrecacheTile(2578, 0);
+    tilePrecacheTile(2586, 0);
+    tilePrecacheTile(2602, 0);
+    for (int i = 0; i < 10; i++)
+    {
+        tilePrecacheTile(2190 + i, 0);
+        tilePrecacheTile(2230 + i, 0);
+        tilePrecacheTile(2240 + i, 0);
+        tilePrecacheTile(2250 + i, 0);
+        tilePrecacheTile(kSBarNumberHealth + i, 0);
+        tilePrecacheTile(kSBarNumberAmmo + i, 0);
+        tilePrecacheTile(kSBarNumberInv + i, 0);
+        tilePrecacheTile(kSBarNumberArmor1 + i, 0);
+        tilePrecacheTile(kSBarNumberArmor2 + i, 0);
+        tilePrecacheTile(kSBarNumberArmor3 + i, 0);
+    }
+    /*
+    for (int i = 0; i < 5; i++)
+    {
+        tilePrecacheTile(gPackIcons[i], 0);
+        tilePrecacheTile(gPackIcons2[i].nTile, 0);
+    }
+    */
+    for (int i = 0; i < 6; i++)
+    {
+        tilePrecacheTile(2220 + i, 0);
+        tilePrecacheTile(2552 + i, 0);
+    }
+}
+
+
+
+void PrecacheDude(spritetype *pSprite)
+{
+    DUDEINFO *pDudeInfo = getDudeInfo(pSprite->type);
+    seqPrecacheId(pDudeInfo->seqStartID);
+    seqPrecacheId(pDudeInfo->seqStartID+5);
+    seqPrecacheId(pDudeInfo->seqStartID+1);
+    seqPrecacheId(pDudeInfo->seqStartID+2);
+    switch (pSprite->type)
+    {
+    case kDudeCultistTommy:
+    case kDudeCultistShotgun:
+    case kDudeCultistTesla:
+    case kDudeCultistTNT:
+        seqPrecacheId(pDudeInfo->seqStartID+6);
+        seqPrecacheId(pDudeInfo->seqStartID+7);
+        seqPrecacheId(pDudeInfo->seqStartID+8);
+        seqPrecacheId(pDudeInfo->seqStartID+9);
+        seqPrecacheId(pDudeInfo->seqStartID+13);
+        seqPrecacheId(pDudeInfo->seqStartID+14);
+        seqPrecacheId(pDudeInfo->seqStartID+15);
+        break;
+    case kDudeZombieButcher:
+    case kDudeGillBeast:
+        seqPrecacheId(pDudeInfo->seqStartID+6);
+        seqPrecacheId(pDudeInfo->seqStartID+7);
+        seqPrecacheId(pDudeInfo->seqStartID+8);
+        seqPrecacheId(pDudeInfo->seqStartID+9);
+        seqPrecacheId(pDudeInfo->seqStartID+10);
+        seqPrecacheId(pDudeInfo->seqStartID+11);
+        break;
+    case kDudeGargoyleStatueFlesh:
+    case kDudeGargoyleStatueStone:
+        seqPrecacheId(pDudeInfo->seqStartID+6);
+        seqPrecacheId(pDudeInfo->seqStartID+6);
+        fallthrough__;
+    case kDudeGargoyleFlesh:
+    case kDudeGargoyleStone:
+        seqPrecacheId(pDudeInfo->seqStartID+6);
+        seqPrecacheId(pDudeInfo->seqStartID+7);
+        seqPrecacheId(pDudeInfo->seqStartID+8);
+        seqPrecacheId(pDudeInfo->seqStartID+9);
+        break;
+    case kDudePhantasm:
+    case kDudeHellHound:
+    case kDudeSpiderBrown:
+    case kDudeSpiderRed:
+    case kDudeSpiderBlack:
+    case kDudeSpiderMother:
+    case kDudeTchernobog:
+        seqPrecacheId(pDudeInfo->seqStartID+6);
+        seqPrecacheId(pDudeInfo->seqStartID+7);
+        seqPrecacheId(pDudeInfo->seqStartID+8);
+        break;
+    case kDudeCerberusTwoHead:
+        seqPrecacheId(pDudeInfo->seqStartID+6);
+        seqPrecacheId(pDudeInfo->seqStartID+7);
+        fallthrough__;
+    case kDudeHand:
+    case kDudeBoneEel:
+    case kDudeBat:
+    case kDudeRat:
+        seqPrecacheId(pDudeInfo->seqStartID+6);
+        seqPrecacheId(pDudeInfo->seqStartID+7);
+        break;
+    case kDudeCultistBeast:
+        seqPrecacheId(pDudeInfo->seqStartID+6);
+        break;
+    case kDudeZombieAxeBuried:
+        seqPrecacheId(pDudeInfo->seqStartID+12);
+        seqPrecacheId(pDudeInfo->seqStartID+9);
+        fallthrough__;
+    case kDudeZombieAxeLaying:
+        seqPrecacheId(pDudeInfo->seqStartID+10);
+        fallthrough__;
+    case kDudeZombieAxeNormal:
+        seqPrecacheId(pDudeInfo->seqStartID+6);
+        seqPrecacheId(pDudeInfo->seqStartID+7);
+        seqPrecacheId(pDudeInfo->seqStartID+8);
+        seqPrecacheId(pDudeInfo->seqStartID+11);
+        seqPrecacheId(pDudeInfo->seqStartID+13);
+        seqPrecacheId(pDudeInfo->seqStartID+14);
+        break;
+    }
+}
+
+void PrecacheThing(spritetype *pSprite) {
+    switch (pSprite->type) {
+        case kThingGlassWindow: // worthless...
+        case kThingFluorescent:
+            seqPrecacheId(12);
+            break;
+        case kThingSpiderWeb:
+            seqPrecacheId(15);
+            break;
+        case kThingMetalGrate:
+            seqPrecacheId(21);
+            break;
+        case kThingFlammableTree:
+            seqPrecacheId(25);
+            seqPrecacheId(26);
+            break;
+        case kTrapMachinegun:
+            seqPrecacheId(38);
+            seqPrecacheId(40);
+            seqPrecacheId(28);
+            break;
+        case kThingObjectGib:
+        //case kThingObjectExplode: weird that only gib object is precached and this one is not
+            break;
+    }
+    tilePrecacheTile(pSprite->picnum);
+}
+
+void PreloadTiles(void)
+{
+    nPrecacheCount = 0;
+    int skyTile = -1;
+    memset(gotpic,0,sizeof(gotpic));
+    // Fonts
+    for (int i = 0; i < numsectors; i++)
+    {
+        tilePrecacheTile(sector[i].floorpicnum, 0);
+        tilePrecacheTile(sector[i].ceilingpicnum, 0);
+        if ((sector[i].ceilingstat&1) != 0 && skyTile == -1)
+            skyTile = sector[i].ceilingpicnum;
+    }
+    for (int i = 0; i < numwalls; i++)
+    {
+        tilePrecacheTile(wall[i].picnum, 0);
+        if (wall[i].overpicnum >= 0)
+            tilePrecacheTile(wall[i].overpicnum, 0);
+    }
+    for (int i = 0; i < kMaxSprites; i++)
+    {
+        if (sprite[i].statnum < kMaxStatus)
+        {
+            spritetype *pSprite = &sprite[i];
+            switch (pSprite->statnum)
+            {
+            case kStatDude:
+                PrecacheDude(pSprite);
+                break;
+            case kStatThing:
+                PrecacheThing(pSprite);
+                break;
+            default:
+                tilePrecacheTile(pSprite->picnum);
+                break;
+            }
+        }
+    }
+
+    // Precache common SEQs
+    for (int i = 0; i < 100; i++)
+    {
+        seqPrecacheId(i);
+    }
+
+    tilePrecacheTile(1147); // water drip
+    tilePrecacheTile(1160); // blood drip
+
+    // Player SEQs
+    seqPrecacheId(dudeInfo[31].seqStartID+6);
+    seqPrecacheId(dudeInfo[31].seqStartID+7);
+    seqPrecacheId(dudeInfo[31].seqStartID+8);
+    seqPrecacheId(dudeInfo[31].seqStartID+9);
+    seqPrecacheId(dudeInfo[31].seqStartID+10);
+    seqPrecacheId(dudeInfo[31].seqStartID+14);
+    seqPrecacheId(dudeInfo[31].seqStartID+15);
+    seqPrecacheId(dudeInfo[31].seqStartID+12);
+    seqPrecacheId(dudeInfo[31].seqStartID+16);
+    seqPrecacheId(dudeInfo[31].seqStartID+17);
+    seqPrecacheId(dudeInfo[31].seqStartID+18);
+
+    if (skyTile > -1 && skyTile < kMaxTiles)
+    {
+        for (int i = 1; i < gSkyCount; i++)
+            tilePrecacheTile(skyTile+i, 0);
+    }
+
+    WeaponPrecache();
+    viewPrecacheTiles();
+    fxPrecache();
+    gibPrecache();
+
+    I_GetEvent();
+}
+
+void PreloadCache(void)
+{
+    PreloadTiles();
+    int cnt = 0;
+    int percentDisplayed = -1;
+
+    for (int i = 0; i < kMaxTiles; i++)
+    {
+        if (TestBitString(gotpic, i))
+        {
+            if (r_precache) PrecacheHardwareTextures(i);
+
+            if ((++cnt & 7) == 0)
+                I_GetEvent();
+        }
+    }
+    memset(gotpic,0,sizeof(gotpic));
+}
+
+END_BLD_NS
+
diff --git a/source/blood/src/view.cpp b/source/blood/src/view.cpp
index fc2bb7657..2d5127946 100644
--- a/source/blood/src/view.cpp
+++ b/source/blood/src/view.cpp
@@ -263,49 +263,6 @@ void viewDrawAimedPlayerName(void)
     }
 }
 
-void viewPrecacheTiles(void)
-{
-    tilePrecacheTile(2173, 0);
-    tilePrecacheTile(2200, 0);
-    tilePrecacheTile(2201, 0);
-    tilePrecacheTile(2202, 0);
-    tilePrecacheTile(2207, 0);
-    tilePrecacheTile(2208, 0);
-    tilePrecacheTile(2209, 0);
-    tilePrecacheTile(2229, 0);
-    tilePrecacheTile(2260, 0);
-    tilePrecacheTile(2559, 0);
-    tilePrecacheTile(2169, 0);
-    tilePrecacheTile(2578, 0);
-    tilePrecacheTile(2586, 0);
-    tilePrecacheTile(2602, 0);
-    for (int i = 0; i < 10; i++)
-    {
-        tilePrecacheTile(2190 + i, 0);
-        tilePrecacheTile(2230 + i, 0);
-        tilePrecacheTile(2240 + i, 0);
-        tilePrecacheTile(2250 + i, 0);
-        tilePrecacheTile(kSBarNumberHealth + i, 0);
-        tilePrecacheTile(kSBarNumberAmmo + i, 0);
-        tilePrecacheTile(kSBarNumberInv + i, 0);
-        tilePrecacheTile(kSBarNumberArmor1 + i, 0);
-        tilePrecacheTile(kSBarNumberArmor2 + i, 0);
-        tilePrecacheTile(kSBarNumberArmor3 + i, 0);
-    }
-    /*
-    for (int i = 0; i < 5; i++)
-    {
-        tilePrecacheTile(gPackIcons[i], 0);
-        tilePrecacheTile(gPackIcons2[i].nTile, 0);
-    }
-    */
-    for (int i = 0; i < 6; i++)
-    {
-        tilePrecacheTile(2220 + i, 0);
-        tilePrecacheTile(2552 + i, 0);
-    }
-}
-
 static TArray<uint8_t> lensdata;
 int *lensTable;
 
diff --git a/source/blood/src/view.h b/source/blood/src/view.h
index 05c051750..bce4cf04e 100644
--- a/source/blood/src/view.h
+++ b/source/blood/src/view.h
@@ -170,7 +170,6 @@ void viewDrawScreen(bool sceneonly = false);
 void viewUpdateDelirium(void);
 void viewUpdateShake(void);
 void viewSetSystemMessage(const char* pMessage, ...);
-void viewPrecacheTiles(void);
 
 inline void viewInterpolateSector(int nSector, sectortype *pSector)
 {