diff --git a/polymer/eduke32/source/common.c b/polymer/eduke32/source/common.c
index 165d716e1..37c12fb38 100644
--- a/polymer/eduke32/source/common.c
+++ b/polymer/eduke32/source/common.c
@@ -129,6 +129,7 @@ const char *G_GrpFile(void)
     else
         return g_grpNamePtr;
 }
+
 const char *G_DefFile(void)
 {
     if (g_defNamePtr == NULL)
@@ -136,6 +137,7 @@ const char *G_DefFile(void)
     else
         return g_defNamePtr;
 }
+
 const char *G_ConFile(void)
 {
     if (g_scriptNamePtr == NULL)
@@ -273,6 +275,25 @@ void G_AddSearchPaths(void)
 #endif
 }
 
+void G_CleanupSearchPaths(void)
+{
+#ifdef _WIN32
+    char buf[BMAX_PATH];
+
+    if (G_GetInstallPath(INSTPATH_STEAM))
+    {
+        Bsprintf(buf, "%s/gameroot", G_GetInstallPath(INSTPATH_STEAM));
+        removesearchpath(buf);
+
+        Bsprintf(buf, "%s/gameroot/addons", G_GetInstallPath(INSTPATH_STEAM));
+        removesearchpath(buf);
+    }
+
+    if (G_GetInstallPath(INSTPATH_GOG))
+        removesearchpath(G_GetInstallPath(INSTPATH_GOG));
+#endif
+}
+
 //////////
 
 struct strllist *CommandPaths, *CommandGrps;
diff --git a/polymer/eduke32/source/common_game.h b/polymer/eduke32/source/common_game.h
index c99b1eeee..31522b388 100644
--- a/polymer/eduke32/source/common_game.h
+++ b/polymer/eduke32/source/common_game.h
@@ -11,6 +11,7 @@
 #define GAMEFLAG_NAM        0x00000002
 #define GAMEFLAG_NAPALM     0x00000004
 #define GAMEFLAG_WW2GI      0x00000008
+#define GAMEFLAG_ADDON      0x00000010
 
 extern int32_t g_gameType;
 
@@ -60,6 +61,7 @@ extern void G_MultiPskyInit(void);
 extern void G_ExtPreInit(void);
 
 extern void G_AddSearchPaths(void);
+extern void G_CleanupSearchPaths(void);
 
 extern const char * G_GetInstallPath(int32_t insttype);
 
diff --git a/polymer/eduke32/source/config.c b/polymer/eduke32/source/config.c
index afa6936c2..8ade82615 100644
--- a/polymer/eduke32/source/config.c
+++ b/polymer/eduke32/source/config.c
@@ -618,7 +618,7 @@ int32_t CONFIG_ReadSetup(void)
         }
 // #endif
 
-        if (g_grpNamePtr == NULL)
+        if (g_grpNamePtr == NULL && g_usingAddon == 0)
             SCRIPT_GetStringPtr(ud.config.scripthandle, "Setup","SelectedGRP",&g_grpNamePtr);
 
         if (!NAM)
diff --git a/polymer/eduke32/source/game.c b/polymer/eduke32/source/game.c
index 17f379750..6a8a673dc 100644
--- a/polymer/eduke32/source/game.c
+++ b/polymer/eduke32/source/game.c
@@ -136,6 +136,8 @@ char **g_scriptModules = NULL;
 int32_t g_scriptModulesNum = 0;
 char **g_defModules = NULL;
 int32_t g_defModulesNum = 0;
+int32_t g_dependencyCRC = 0;
+int32_t g_usingAddon = 0;
 
 #ifdef HAVE_CLIPSHAPE_FEATURE
 char **g_clipMapFiles = NULL;
@@ -8771,6 +8773,21 @@ static void G_CheckCommandLine(int32_t argc, const char **argv)
                     G_ShowParameterHelp();
                     exit(0);
                 }
+                if (!Bstrcasecmp(c+1,"addon"))
+                {
+                    if (argc > i+1)
+                    {
+                        g_usingAddon = atoi(argv[i+1]);
+
+                        if (g_usingAddon > ADDON_NONE && g_usingAddon < NUMADDONS)
+                            g_noSetup = 1;
+                        else g_usingAddon = ADDON_NONE;
+
+                        i++;
+                    }
+                    i++;
+                    continue;
+                }
                 if (!Bstrcasecmp(c+1,"debughelp") || !Bstrcasecmp(c+1,"-debughelp"))
                 {
                     G_ShowDebugHelp();
@@ -10102,6 +10119,46 @@ void G_MaybeAllocPlayer(int32_t pnum)
 #endif
 }
 
+void G_LoadAddon(void)
+{
+    struct grpfile * grp;
+    int32_t crc;
+
+    switch (g_usingAddon)
+    {
+    case ADDON_DUKEDC:
+        crc = DUKEDC_CRC;
+        break;
+    case ADDON_NWINTER:
+        crc = DUKENW_CRC;
+        break;
+    case ADDON_CARIBBEAN:
+        crc = DUKECB_CRC;
+        break;
+    }
+
+    if (!crc) return;
+
+    grp = FindGroup(crc);
+
+    if (grp && FindGroup(DUKE15_CRC))
+    {
+        int32_t i;
+
+        clearGrpNamePtr();
+        g_grpNamePtr = dup_filename(FindGroup(DUKE15_CRC)->name);
+
+        G_AddGroup(grp->name);
+
+        for (i = 0; i<NUMGRPFILES; i++) if (crc == grpfiles[i].crcval) break;
+        if (i != NUMGRPFILES && grpfiles[i].scriptname)
+        {
+            clearScriptNamePtr();
+            g_scriptNamePtr = dup_filename(grpfiles[i].scriptname);
+        }
+    }
+}
+
 EDUKE32_STATIC_ASSERT(sizeof(actor_t)==128);
 EDUKE32_STATIC_ASSERT(sizeof(DukePlayer_t)%4 == 0);
 
@@ -10392,8 +10449,6 @@ int32_t app_main(int32_t argc, const char **argv)
     }
 #endif
 
-    FreeGroups();
-
     if (WW2GI || NAM)
     {
         Bstrcpy(GametypeNames[0],"GruntMatch (Spawn)");
@@ -10424,9 +10479,24 @@ int32_t app_main(int32_t argc, const char **argv)
 #endif
     }
 
+    if (g_usingAddon)
+        G_LoadAddon();
+
     {
         const char *grpfile = G_GrpFile();
 
+        if (g_dependencyCRC)
+        {
+            struct grpfile * grp = FindGroup(g_dependencyCRC);
+            if (grp)
+            {
+                if ((i = initgroupfile(grp->name)) == -1)
+                    initprintf("Warning: could not find main data file \"%s\"!\n",grp->name);
+                else
+                    initprintf("Using \"%s\" as main game data file.\n", grp->name);
+            }
+        }
+
         if ((i = initgroupfile(grpfile)) == -1)
             initprintf("Warning: could not find main data file \"%s\"!\n",grpfile);
         else
@@ -10441,19 +10511,7 @@ int32_t app_main(int32_t argc, const char **argv)
         }
     }
 
-#ifdef _WIN32
-    if (G_GetInstallPath(INSTPATH_STEAM))
-    {
-        Bsprintf(buf, "%s/gameroot", G_GetInstallPath(INSTPATH_STEAM));
-        removesearchpath(buf);
-
-        Bsprintf(buf, "%s/gameroot/addons", G_GetInstallPath(INSTPATH_STEAM));
-        removesearchpath(buf);
-    }
-
-    if (G_GetInstallPath(INSTPATH_GOG))
-        removesearchpath(G_GetInstallPath(INSTPATH_GOG));
-#endif
+    FreeGroups();
 
     if (g_modDir[0] != '/')
         G_LoadGroupsInDir(g_modDir);
@@ -10499,6 +10557,8 @@ int32_t app_main(int32_t argc, const char **argv)
         pathsearchmode = 0;
     }
 
+    G_CleanupSearchPaths();
+
     i = kopen4load("DUKESW.BIN",1); // JBF 20030810
     if (i!=-1)
     {
diff --git a/polymer/eduke32/source/game.h b/polymer/eduke32/source/game.h
index 71389c3b5..2e2d0a867 100644
--- a/polymer/eduke32/source/game.h
+++ b/polymer/eduke32/source/game.h
@@ -242,6 +242,7 @@ extern int32_t g_cameraClock;
 extern int32_t g_cameraDistance;
 #endif
 extern int32_t g_crosshairSum;
+extern int32_t g_dependencyCRC;
 extern int32_t g_doQuickSave;
 extern int32_t g_forceWeaponChoice;
 extern int32_t g_fakeMultiMode;
@@ -249,6 +250,7 @@ extern int32_t g_levelTextTime;
 extern int32_t g_noSetup;
 extern int32_t g_quitDeadline;
 extern int32_t g_restorePalette;
+extern int32_t g_usingAddon;
 extern int32_t hud_glowingquotes;
 extern int32_t hud_showmapname;
 extern int32_t lastvisinc;
diff --git a/polymer/eduke32/source/grpscan.c b/polymer/eduke32/source/grpscan.c
index 007e7f630..6eacb2263 100644
--- a/polymer/eduke32/source/grpscan.c
+++ b/polymer/eduke32/source/grpscan.c
@@ -33,15 +33,18 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 struct grpfile grpfiles[NUMGRPFILES] =
 {
-    { "Duke Nukem 3D",                            (int32_t)0xBBC9CE44, 26524524, GAMEFLAG_DUKE, NULL },
-    { "Duke Nukem 3D (South Korean Censored)",    (int32_t)0xAA4F6A40, 26385383, GAMEFLAG_DUKE, NULL },
-    { "Duke Nukem 3D: Atomic Edition",            (int32_t)0xFD3DCFF1, 44356548, GAMEFLAG_DUKE, NULL },
-    { "Duke Nukem 3D: Plutonium Pak",             (int32_t)0xF514A6AC, 44348015, GAMEFLAG_DUKE, NULL },
-    { "Duke Nukem 3D Shareware",                  (int32_t)0x983AD923, 11035779, GAMEFLAG_DUKE, NULL },
-    { "Duke Nukem 3D Mac Shareware",              (int32_t)0xC5F71561, 10444391, GAMEFLAG_DUKE, NULL },
-    { "NAM",                                      (int32_t)0x75C1F07B, 43448927, GAMEFLAG_NAM,  NULL },
-    { "NAPALM",                                   (int32_t)0x3DE1589A, 44365728, GAMEFLAG_NAM|GAMEFLAG_NAPALM,  NULL },
-    { "WWII GI",                                  (int32_t)0x907B82BF, 77939508, GAMEFLAG_WW2GI|GAMEFLAG_NAM,  NULL },
+    { "Duke Nukem 3D",                         DUKE13_CRC, 26524524, GAMEFLAG_DUKE,                         0, NULL,          NULL },
+    { "Duke Nukem 3D (South Korean Censored)", DUKEKR_CRC, 26385383, GAMEFLAG_DUKE,                         0, NULL,          NULL },
+    { "Duke Nukem 3D: Atomic Edition",         DUKE15_CRC, 44356548, GAMEFLAG_DUKE,                         0, NULL,          NULL },
+    { "Duke Nukem 3D: Plutonium Pak",          DUKEPP_CRC, 44348015, GAMEFLAG_DUKE,                         0, NULL,          NULL },
+    { "Duke Nukem 3D Shareware",               DUKESW_CRC, 11035779, GAMEFLAG_DUKE,                         0, NULL,          NULL },
+    { "Duke Nukem 3D Mac Demo",                DUKEMD_CRC, 10444391, GAMEFLAG_DUKE,                         0, NULL,          NULL },
+    { "Duke it out in D.C.",                   DUKEDC_CRC, 8410183 , GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, NULL,          NULL },
+    { "Duke Caribbean: Life's a Beach",        DUKECB_CRC, 22213819, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, NULL,          NULL },
+    { "Duke: Nuclear Winter",                  DUKENW_CRC, 16169365, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, "nwinter.con", NULL },
+    { "NAM",                                   NAM_CRC,    43448927, GAMEFLAG_NAM,                          0, NULL,          NULL },
+    { "NAPALM",                                NAPALM_CRC, 44365728, GAMEFLAG_NAM|GAMEFLAG_NAPALM,          0, NULL,          NULL },
+    { "WWII GI",                               WW2GI_CRC,  77939508, GAMEFLAG_WW2GI|GAMEFLAG_NAM,           0, NULL,          NULL },
 };
 struct grpfile *foundgrps = NULL;
 
@@ -101,6 +104,41 @@ static void FreeGroupsCache(void)
     }
 }
 
+void RemoveGroup(int32_t crcval)
+{
+    struct grpfile *grp, *fg;
+
+    for (grp = foundgrps; grp; grp=grp->next)
+    {
+        if (grp->crcval == crcval)
+        {
+            if (grp == foundgrps)
+                foundgrps = grp->next;
+            else fg->next = grp->next;
+
+            Bfree((char *)grp->name);
+            Bfree(grp);
+
+            break;
+        }
+
+        fg = grp;
+    }
+}
+
+struct grpfile * FindGroup(int32_t crcval)
+{
+    struct grpfile *grp;
+
+    for (grp = foundgrps; grp; grp=grp->next)
+    {
+        if (grp->crcval == crcval)
+            return grp;
+    }
+
+    return NULL;
+}
+
 int32_t ScanGroups(void)
 {
     CACHE1D_FIND_REC *srch, *sidx;
@@ -199,6 +237,31 @@ int32_t ScanGroups(void)
     klistfree(srch);
     FreeGroupsCache();
 
+    for (grp = foundgrps; grp; /*grp=grp->next*/)
+    {
+        int32_t i;
+
+        for (i = 0; i<NUMGRPFILES; i++) if (grp->crcval == grpfiles[i].crcval) break;
+        if (i == NUMGRPFILES) continue; // unrecognised grp file
+
+        if (grpfiles[i].dependency)
+        {
+            //initprintf("found grp with dep\n");
+            for (grp = foundgrps; grp; grp=grp->next)
+                if (grp->crcval == grpfiles[i].dependency) break;
+
+            if (grp == NULL || grp->crcval != grpfiles[i].dependency) // couldn't find dependency
+            {
+                //initprintf("removing %s\n", grp->name);
+                RemoveGroup(grpfiles[i].crcval);
+                grp = foundgrps;
+                continue;
+            }
+        }
+
+        grp=grp->next;
+    }
+
     if (usedgrpcache)
     {
         int32_t i = 0;
@@ -227,6 +290,7 @@ int32_t ScanGroups(void)
     return 0;
 }
 
+
 void FreeGroups(void)
 {
     struct grpfile *fg;
diff --git a/polymer/eduke32/source/grpscan.h b/polymer/eduke32/source/grpscan.h
index 77e5cc93e..e3e1a42a8 100644
--- a/polymer/eduke32/source/grpscan.h
+++ b/polymer/eduke32/source/grpscan.h
@@ -24,18 +24,43 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #define __grpscan_h__
 
 // List of internally-known GRP files
-#define NUMGRPFILES 9
+#define NUMGRPFILES 12
+
+#define DUKE13_CRC (int32_t)0xBBC9CE44
+#define DUKEKR_CRC (int32_t)0xAA4F6A40
+#define DUKE15_CRC (int32_t)0xFD3DCFF1
+#define DUKEPP_CRC (int32_t)0xF514A6AC
+#define DUKESW_CRC (int32_t)0x983AD923
+#define DUKEMD_CRC (int32_t)0xC5F71561
+#define DUKEDC_CRC (int32_t)0xA8CF80DA
+#define DUKECB_CRC (int32_t)0x18F01C5B
+#define DUKENW_CRC (int32_t)0xF1CAE8E4
+#define NAM_CRC    (int32_t)0x75C1F07B
+#define NAPALM_CRC (int32_t)0x3DE1589A
+#define WW2GI_CRC  (int32_t)0x907B82BF
+
+enum addon_t {
+    ADDON_NONE,
+    ADDON_DUKEDC,
+    ADDON_NWINTER,
+    ADDON_CARIBBEAN,
+    NUMADDONS
+};
+
 typedef struct grpfile {
 	const char *name;
 	int32_t crcval;
 	int32_t size;
 	int32_t game;
+    int32_t dependency;
+    const char *scriptname;
 	struct grpfile *next;
 } grpfile_type;
 
 extern struct grpfile grpfiles[NUMGRPFILES];
 extern struct grpfile *foundgrps;
 
+extern struct grpfile * FindGroup(int32_t crcval);
 int32_t ScanGroups(void);
 void FreeGroups(void);
 
diff --git a/polymer/eduke32/source/startgtk.game.c b/polymer/eduke32/source/startgtk.game.c
index 633d7325c..4778ece25 100644
--- a/polymer/eduke32/source/startgtk.game.c
+++ b/polymer/eduke32/source/startgtk.game.c
@@ -932,7 +932,12 @@ int32_t startwin_run(void)
 
         for (i = 0; i<NUMGRPFILES; i++) if (settings.crcval == grpfiles[i].crcval) break;
         if (i != NUMGRPFILES)
+        {
             g_gameNamePtr = grpfiles[i].name;
+            g_dependencyCRC = grpfiles[i].dependency;
+            if (grpfiles[i].scriptname && g_scriptNamePtr == NULL)
+                g_scriptNamePtr = dup_filename(grpfiles[i].scriptname);
+        }
     }
 
     return retval;
diff --git a/polymer/eduke32/source/startwin.game.c b/polymer/eduke32/source/startwin.game.c
index 96d2a308e..ba45a146d 100644
--- a/polymer/eduke32/source/startwin.game.c
+++ b/polymer/eduke32/source/startwin.game.c
@@ -799,7 +799,12 @@ int32_t startwin_run(void)
 
         for (i = 0; i<NUMGRPFILES; i++) if (settings.crcval == grpfiles[i].crcval) break;
         if (i != NUMGRPFILES)
+        {
             g_gameNamePtr = grpfiles[i].name;
+            g_dependencyCRC = grpfiles[i].dependency;
+            if (grpfiles[i].scriptname && g_scriptNamePtr == NULL)
+                g_scriptNamePtr = dup_filename(grpfiles[i].scriptname);
+        }
     }
 
     if (wavedevs)