+ stringlistinit(&list);
+ listdirectory(&list, "", dir);
+ stringlistsort(&list, false);
+
+ // add any PAK package in the directory
+ for (i = 0;i < list.numstrings;i++)
+ {
+ if (!strcasecmp(FS_FileExtension(list.strings[i]), "pak"))
+ {
+ FS_AddPack_Fullpath(list.strings[i], list.strings[i] + strlen(dir), NULL, false);
+ }
+ }
+
+ // add any PK3 package in the directory
+ for (i = 0;i < list.numstrings;i++)
+ {
+ if (!strcasecmp(FS_FileExtension(list.strings[i]), "pk3") || !strcasecmp(FS_FileExtension(list.strings[i]), "obb") || !strcasecmp(FS_FileExtension(list.strings[i]), "pk3dir"))
+ {
+ FS_AddPack_Fullpath(list.strings[i], list.strings[i] + strlen(dir), NULL, false);
+ }
+ }
+
+ stringlistfreecontents(&list);
+
+ // Add the directory to the search path
+ // (unpacked files have the priority over packed files)
+ search = (searchpath_t *)Mem_Alloc(fs_mempool, sizeof(searchpath_t));
+ strlcpy (search->filename, dir, sizeof (search->filename));
+ search->next = fs_searchpaths;
+ fs_searchpaths = search;
+}
+
+
+/*
+================
+FS_AddGameHierarchy
+================
+*/
+static void FS_AddGameHierarchy (const char *dir)
+{
+ char vabuf[1024];
+ // Add the common game directory
+ FS_AddGameDirectory (va(vabuf, sizeof(vabuf), "%s%s/", fs_basedir, dir));
+
+ if (*fs_userdir)
+ FS_AddGameDirectory(va(vabuf, sizeof(vabuf), "%s%s/", fs_userdir, dir));
+}
+
+
+/*
+============
+FS_FileExtension
+============
+*/
+const char *FS_FileExtension (const char *in)
+{
+ const char *separator, *backslash, *colon, *dot;
+
+ separator = strrchr(in, '/');
+ backslash = strrchr(in, '\\');
+ if (!separator || separator < backslash)
+ separator = backslash;
+ colon = strrchr(in, ':');
+ if (!separator || separator < colon)
+ separator = colon;
+
+ dot = strrchr(in, '.');
+ if (dot == NULL || (separator && (dot < separator)))
+ return "";
+
+ return dot + 1;
+}
+
+
+/*
+============
+FS_FileWithoutPath
+============
+*/
+const char *FS_FileWithoutPath (const char *in)
+{
+ const char *separator, *backslash, *colon;
+
+ separator = strrchr(in, '/');
+ backslash = strrchr(in, '\\');
+ if (!separator || separator < backslash)
+ separator = backslash;
+ colon = strrchr(in, ':');
+ if (!separator || separator < colon)
+ separator = colon;
+ return separator ? separator + 1 : in;
+}
+
+
+/*
+================
+FS_ClearSearchPath
+================
+*/
+static void FS_ClearSearchPath (void)
+{
+ // unload all packs and directory information, close all pack files
+ // (if a qfile is still reading a pack it won't be harmed because it used
+ // dup() to get its own handle already)
+ while (fs_searchpaths)
+ {
+ searchpath_t *search = fs_searchpaths;
+ fs_searchpaths = search->next;
+ if (search->pack && search->pack != fs_selfpack)
+ {
+ if(!search->pack->vpack)
+ {
+ // close the file
+ close(search->pack->handle);
+ // free any memory associated with it
+ if (search->pack->files)
+ Mem_Free(search->pack->files);
+ }
+ Mem_Free(search->pack);
+ }
+ Mem_Free(search);
+ }
+}
+
+static void FS_AddSelfPack(void)
+{
+ if(fs_selfpack)
+ {
+ searchpath_t *search;
+ search = (searchpath_t *)Mem_Alloc(fs_mempool, sizeof(searchpath_t));
+ search->next = fs_searchpaths;
+ search->pack = fs_selfpack;
+ fs_searchpaths = search;
+ }
+}
+
+
+/*
+================
+FS_Rescan
+================
+*/
+void FS_Rescan (void)
+{
+ int i;
+ qboolean fs_modified = false;
+ qboolean reset = false;
+ char gamedirbuf[MAX_INPUTLINE];
+ char vabuf[1024];
+
+ if (fs_searchpaths)
+ reset = true;
+ FS_ClearSearchPath();
+
+ // automatically activate gamemode for the gamedirs specified
+ if (reset)
+ COM_ChangeGameTypeForGameDirs();
+
+ // add the game-specific paths
+ // gamedirname1 (typically id1)
+ FS_AddGameHierarchy (gamedirname1);
+ // update the com_modname (used for server info)
+ if (gamedirname2 && gamedirname2[0])
+ strlcpy(com_modname, gamedirname2, sizeof(com_modname));
+ else
+ strlcpy(com_modname, gamedirname1, sizeof(com_modname));
+
+ // add the game-specific path, if any
+ // (only used for mission packs and the like, which should set fs_modified)
+ if (gamedirname2 && gamedirname2[0])
+ {
+ fs_modified = true;
+ FS_AddGameHierarchy (gamedirname2);
+ }
+
+ // -game <gamedir>
+ // Adds basedir/gamedir as an override game
+ // LordHavoc: now supports multiple -game directories
+ // set the com_modname (reported in server info)
+ *gamedirbuf = 0;
+ for (i = 0;i < fs_numgamedirs;i++)
+ {
+ fs_modified = true;
+ FS_AddGameHierarchy (fs_gamedirs[i]);
+ // update the com_modname (used server info)
+ strlcpy (com_modname, fs_gamedirs[i], sizeof (com_modname));
+ if(i)
+ strlcat(gamedirbuf, va(vabuf, sizeof(vabuf), " %s", fs_gamedirs[i]), sizeof(gamedirbuf));
+ else
+ strlcpy(gamedirbuf, fs_gamedirs[i], sizeof(gamedirbuf));
+ }
+ Cvar_SetQuick(&cvar_fs_gamedir, gamedirbuf); // so QC or console code can query it
+
+ // add back the selfpack as new first item
+ FS_AddSelfPack();
+
+ // set the default screenshot name to either the mod name or the
+ // gamemode screenshot name
+ if (strcmp(com_modname, gamedirname1))
+ Cvar_SetQuick (&scr_screenshot_name, com_modname);
+ else
+ Cvar_SetQuick (&scr_screenshot_name, gamescreenshotname);
+
+ if((i = COM_CheckParm("-modname")) && i < com_argc - 1)
+ strlcpy(com_modname, com_argv[i+1], sizeof(com_modname));
+
+ // If "-condebug" is in the command line, remove the previous log file
+ if (COM_CheckParm ("-condebug") != 0)
+ unlink (va(vabuf, sizeof(vabuf), "%s/qconsole.log", fs_gamedir));
+
+ // look for the pop.lmp file and set registered to true if it is found
+ if (FS_FileExists("gfx/pop.lmp"))
+ Cvar_Set ("registered", "1");
+ switch(gamemode)
+ {
+ case GAME_NORMAL:
+ case GAME_HIPNOTIC:
+ case GAME_ROGUE:
+ if (!registered.integer)
+ {
+ if (fs_modified)
+ Con_Print("Playing shareware version, with modification.\nwarning: most mods require full quake data.\n");
+ else
+ Con_Print("Playing shareware version.\n");
+ }
+ else
+ Con_Print("Playing registered version.\n");
+ break;
+ case GAME_STEELSTORM:
+ if (registered.integer)
+ Con_Print("Playing registered version.\n");
+ else
+ Con_Print("Playing shareware version.\n");
+ break;
+ default:
+ break;
+ }