mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-10 22:51:57 +00:00
PACKAGEMANAGER is now a compiletime feature in its own right, and can be enabled separately from WEBCLIENT (although won't be able to download without WEBCLIENT).
SAVEDGAMES is now a new compiletime feature. Deathmatch/dedicated servers can freely disable it. menuqc now makes sure that any fields it needs are actually present. developer 1 should now report glsl line numbers a bit more reliably. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5284 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
61c0b9f83b
commit
0b2be8f4ba
21 changed files with 330 additions and 164 deletions
|
@ -3,8 +3,7 @@
|
||||||
//FIXME: block downloads of exe/dll/so/etc if not an https url (even if inside zips). also block such files from package lists over http.
|
//FIXME: block downloads of exe/dll/so/etc if not an https url (even if inside zips). also block such files from package lists over http.
|
||||||
#include "quakedef.h"
|
#include "quakedef.h"
|
||||||
|
|
||||||
#ifdef WEBCLIENT
|
#ifdef PACKAGEMANAGER
|
||||||
#define PACKAGEMANAGER
|
|
||||||
#if !defined(NOBUILTINMENUS) && !defined(SERVERONLY)
|
#if !defined(NOBUILTINMENUS) && !defined(SERVERONLY)
|
||||||
#define DOWNLOADMENU
|
#define DOWNLOADMENU
|
||||||
#endif
|
#endif
|
||||||
|
@ -134,7 +133,6 @@ typedef struct package_s {
|
||||||
|
|
||||||
struct package_s *alternative; //alternative (hidden) forms of this package.
|
struct package_s *alternative; //alternative (hidden) forms of this package.
|
||||||
|
|
||||||
unsigned int trymirrors;
|
|
||||||
char *mirror[8]; //FIXME: move to two types of dep...
|
char *mirror[8]; //FIXME: move to two types of dep...
|
||||||
char gamedir[16];
|
char gamedir[16];
|
||||||
enum fs_relative fsroot;
|
enum fs_relative fsroot;
|
||||||
|
@ -172,7 +170,10 @@ typedef struct package_s {
|
||||||
char name[1];
|
char name[1];
|
||||||
} *deps;
|
} *deps;
|
||||||
|
|
||||||
|
#ifdef WEBCLIENT
|
||||||
struct dl_download *download;
|
struct dl_download *download;
|
||||||
|
unsigned int trymirrors;
|
||||||
|
#endif
|
||||||
|
|
||||||
int flags;
|
int flags;
|
||||||
int priority;
|
int priority;
|
||||||
|
@ -190,8 +191,12 @@ static int domanifestinstall; //SECURITY_MANIFEST_*
|
||||||
#ifdef PLUGINS
|
#ifdef PLUGINS
|
||||||
static qboolean pluginpromptshown; //so we only show prompts for new externally-installed plugins once, instead of every time the file is reloaded.
|
static qboolean pluginpromptshown; //so we only show prompts for new externally-installed plugins once, instead of every time the file is reloaded.
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef WEBCLIENT
|
||||||
static qboolean doautoupdate; //updates will be marked (but not applied without the user's actions)
|
static qboolean doautoupdate; //updates will be marked (but not applied without the user's actions)
|
||||||
static qboolean pkg_updating; //when flagged, further changes are blocked until completion.
|
static qboolean pkg_updating; //when flagged, further changes are blocked until completion.
|
||||||
|
#else
|
||||||
|
static const qboolean pkg_updating = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
//FIXME: these are allocated for the life of the exe. changing basedir should purge the list.
|
//FIXME: these are allocated for the life of the exe. changing basedir should purge the list.
|
||||||
static int numdownloadablelists = 0;
|
static int numdownloadablelists = 0;
|
||||||
|
@ -1152,11 +1157,13 @@ void PM_Shutdown(void)
|
||||||
{
|
{
|
||||||
numdownloadablelists--;
|
numdownloadablelists--;
|
||||||
|
|
||||||
|
#ifdef WEBCLIENT
|
||||||
if (downloadablelist[numdownloadablelists].curdl)
|
if (downloadablelist[numdownloadablelists].curdl)
|
||||||
{
|
{
|
||||||
DL_Close(downloadablelist[numdownloadablelists].curdl);
|
DL_Close(downloadablelist[numdownloadablelists].curdl);
|
||||||
downloadablelist[numdownloadablelists].curdl = NULL;
|
downloadablelist[numdownloadablelists].curdl = NULL;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
downloadablelist[numdownloadablelists].received = 0;
|
downloadablelist[numdownloadablelists].received = 0;
|
||||||
Z_Free(downloadablelist[numdownloadablelists].url);
|
Z_Free(downloadablelist[numdownloadablelists].url);
|
||||||
downloadablelist[numdownloadablelists].url = NULL;
|
downloadablelist[numdownloadablelists].url = NULL;
|
||||||
|
@ -1232,6 +1239,7 @@ static void PM_UnmarkPackage(package_t *package)
|
||||||
return; //looks like its already deselected.
|
return; //looks like its already deselected.
|
||||||
package->flags &= ~(DPF_MARKED);
|
package->flags &= ~(DPF_MARKED);
|
||||||
|
|
||||||
|
#ifdef WEBCLIENT
|
||||||
//Is this safe?
|
//Is this safe?
|
||||||
package->trymirrors = 0; //if its enqueued, cancel that quickly...
|
package->trymirrors = 0; //if its enqueued, cancel that quickly...
|
||||||
if (package->download)
|
if (package->download)
|
||||||
|
@ -1239,6 +1247,7 @@ static void PM_UnmarkPackage(package_t *package)
|
||||||
DL_Close(package->download);
|
DL_Close(package->download);
|
||||||
package->download = NULL;
|
package->download = NULL;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
//remove stuff that depends on us
|
//remove stuff that depends on us
|
||||||
for (o = availablepackages; o; o = o->next)
|
for (o = availablepackages; o; o = o->next)
|
||||||
|
@ -1530,7 +1539,7 @@ static void PM_PrintChanges(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PM_ApplyChanges(void);
|
static void PM_ApplyChanges(void);
|
||||||
|
#ifdef WEBCLIENT
|
||||||
static void PM_ListDownloaded(struct dl_download *dl)
|
static void PM_ListDownloaded(struct dl_download *dl)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -1619,6 +1628,7 @@ static void PM_ListDownloaded(struct dl_download *dl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
//retry 1==
|
//retry 1==
|
||||||
static void PM_UpdatePackageList(qboolean autoupdate, int retry)
|
static void PM_UpdatePackageList(qboolean autoupdate, int retry)
|
||||||
{
|
{
|
||||||
|
@ -1633,6 +1643,10 @@ static void PM_UpdatePackageList(qboolean autoupdate, int retry)
|
||||||
if (*pm_downloads_url.string)
|
if (*pm_downloads_url.string)
|
||||||
PM_AddSubList(pm_downloads_url.string, "", true, true);
|
PM_AddSubList(pm_downloads_url.string, "", true, true);
|
||||||
|
|
||||||
|
#ifndef WEBCLIENT
|
||||||
|
for (i = 0; i < numdownloadablelists; i++)
|
||||||
|
downloadablelist[i].received = true;
|
||||||
|
#else
|
||||||
doautoupdate |= autoupdate;
|
doautoupdate |= autoupdate;
|
||||||
|
|
||||||
//kick off the initial tier of list-downloads.
|
//kick off the initial tier of list-downloads.
|
||||||
|
@ -1673,6 +1687,7 @@ static void PM_UpdatePackageList(qboolean autoupdate, int retry)
|
||||||
PM_PrintChanges();
|
PM_PrintChanges();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1860,6 +1875,7 @@ static void PM_WriteInstalledPackages(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WEBCLIENT
|
||||||
//callback from PM_Download_Got, extracts each file from an archive
|
//callback from PM_Download_Got, extracts each file from an archive
|
||||||
static int QDECL PM_ExtractFiles(const char *fname, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath)
|
static int QDECL PM_ExtractFiles(const char *fname, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath)
|
||||||
{ //this is gonna suck. threading would help, but gah.
|
{ //this is gonna suck. threading would help, but gah.
|
||||||
|
@ -2114,6 +2130,7 @@ static char *PM_GetTempName(package_t *p)
|
||||||
Z_Free(ts);
|
Z_Free(ts);
|
||||||
return Z_StrDup(destname);
|
return Z_StrDup(destname);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*static void PM_AddDownloadedPackage(const char *filename)
|
/*static void PM_AddDownloadedPackage(const char *filename)
|
||||||
{
|
{
|
||||||
|
@ -2143,8 +2160,9 @@ static char *PM_GetTempName(package_t *p)
|
||||||
|
|
||||||
int PM_IsApplying(qboolean listsonly)
|
int PM_IsApplying(qboolean listsonly)
|
||||||
{
|
{
|
||||||
package_t *p;
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
#ifdef WEBCLIENT
|
||||||
|
package_t *p;
|
||||||
int i;
|
int i;
|
||||||
if (!listsonly)
|
if (!listsonly)
|
||||||
{
|
{
|
||||||
|
@ -2159,12 +2177,14 @@ int PM_IsApplying(qboolean listsonly)
|
||||||
if (downloadablelist[i].curdl)
|
if (downloadablelist[i].curdl)
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
//looks for the next package that needs downloading, and grabs it
|
//looks for the next package that needs downloading, and grabs it
|
||||||
static void PM_StartADownload(void)
|
static void PM_StartADownload(void)
|
||||||
{
|
{
|
||||||
|
#ifdef WEBCLIENT
|
||||||
vfsfile_t *tmpfile;
|
vfsfile_t *tmpfile;
|
||||||
char *temp;
|
char *temp;
|
||||||
package_t *p;
|
package_t *p;
|
||||||
|
@ -2284,6 +2304,7 @@ static void PM_StartADownload(void)
|
||||||
|
|
||||||
//clear the updating flag once there's no more activity needed
|
//clear the updating flag once there's no more activity needed
|
||||||
pkg_updating = downloading;
|
pkg_updating = downloading;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
//'just' starts doing all the things needed to remove/install selected packages
|
//'just' starts doing all the things needed to remove/install selected packages
|
||||||
static void PM_ApplyChanges(void)
|
static void PM_ApplyChanges(void)
|
||||||
|
@ -2291,17 +2312,22 @@ static void PM_ApplyChanges(void)
|
||||||
package_t *p, **link;
|
package_t *p, **link;
|
||||||
char temp[MAX_OSPATH];
|
char temp[MAX_OSPATH];
|
||||||
|
|
||||||
|
#ifdef WEBCLIENT
|
||||||
if (pkg_updating)
|
if (pkg_updating)
|
||||||
return;
|
return;
|
||||||
pkg_updating = true;
|
pkg_updating = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
//delete any that don't exist
|
//delete any that don't exist
|
||||||
for (link = &availablepackages; *link ; )
|
for (link = &availablepackages; *link ; )
|
||||||
{
|
{
|
||||||
p = *link;
|
p = *link;
|
||||||
|
#ifdef WEBCLIENT
|
||||||
if (p->download)
|
if (p->download)
|
||||||
; //erk, dude, don't do two!
|
; //erk, dude, don't do two!
|
||||||
else if ((p->flags & DPF_PURGE) || (!(p->flags&DPF_MARKED) && (p->flags&DPF_ENABLED)))
|
else
|
||||||
|
#endif
|
||||||
|
if ((p->flags & DPF_PURGE) || (!(p->flags&DPF_MARKED) && (p->flags&DPF_ENABLED)))
|
||||||
{ //if we don't want it but we have it anyway. don't bother to follow this logic when reinstalling
|
{ //if we don't want it but we have it anyway. don't bother to follow this logic when reinstalling
|
||||||
qboolean reloadpacks = false;
|
qboolean reloadpacks = false;
|
||||||
struct packagedep_s *dep;
|
struct packagedep_s *dep;
|
||||||
|
@ -2416,12 +2442,14 @@ static void PM_ApplyChanges(void)
|
||||||
link = &(*link)->next;
|
link = &(*link)->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WEBCLIENT
|
||||||
//and flag any new/updated ones for a download
|
//and flag any new/updated ones for a download
|
||||||
for (p = availablepackages; p ; p=p->next)
|
for (p = availablepackages; p ; p=p->next)
|
||||||
{
|
{
|
||||||
if ((p->flags&DPF_MARKED) && !(p->flags&DPF_ENABLED) && !p->download)
|
if ((p->flags&DPF_MARKED) && !(p->flags&DPF_ENABLED) && !p->download)
|
||||||
p->trymirrors = ~0u;
|
p->trymirrors = ~0u;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
PM_StartADownload(); //and try to do those downloads.
|
PM_StartADownload(); //and try to do those downloads.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2496,14 +2524,18 @@ static qboolean PM_DeclinedPackages(char *out, size_t outsize)
|
||||||
}
|
}
|
||||||
static void PM_PromptApplyChanges_Callback(void *ctx, int opt)
|
static void PM_PromptApplyChanges_Callback(void *ctx, int opt)
|
||||||
{
|
{
|
||||||
|
#ifdef WEBCLIENT
|
||||||
pkg_updating = false;
|
pkg_updating = false;
|
||||||
|
#endif
|
||||||
if (opt == 0)
|
if (opt == 0)
|
||||||
PM_ApplyChanges();
|
PM_ApplyChanges();
|
||||||
}
|
}
|
||||||
static void PM_PromptApplyChanges(void);
|
static void PM_PromptApplyChanges(void);
|
||||||
static void PM_PromptApplyDecline_Callback(void *ctx, int opt)
|
static void PM_PromptApplyDecline_Callback(void *ctx, int opt)
|
||||||
{
|
{
|
||||||
|
#ifdef WEBCLIENT
|
||||||
pkg_updating = false;
|
pkg_updating = false;
|
||||||
|
#endif
|
||||||
if (opt == 1)
|
if (opt == 1)
|
||||||
{
|
{
|
||||||
PM_DeclinedPackages(NULL, 0);
|
PM_DeclinedPackages(NULL, 0);
|
||||||
|
@ -2514,6 +2546,7 @@ static void PM_PromptApplyChanges(void)
|
||||||
{
|
{
|
||||||
unsigned int changes;
|
unsigned int changes;
|
||||||
char text[8192];
|
char text[8192];
|
||||||
|
#ifdef WEBCLIENT
|
||||||
//lock it down, so noone can make any changes while this prompt is still displayed
|
//lock it down, so noone can make any changes while this prompt is still displayed
|
||||||
if (pkg_updating)
|
if (pkg_updating)
|
||||||
{
|
{
|
||||||
|
@ -2521,6 +2554,7 @@ static void PM_PromptApplyChanges(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pkg_updating = true;
|
pkg_updating = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
strcpy(text, "Really decline the following\nrecommendedpackages?\n\n");
|
strcpy(text, "Really decline the following\nrecommendedpackages?\n\n");
|
||||||
if (PM_DeclinedPackages(text+strlen(text), sizeof(text)-strlen(text)))
|
if (PM_DeclinedPackages(text+strlen(text), sizeof(text)-strlen(text)))
|
||||||
|
@ -2530,7 +2564,11 @@ static void PM_PromptApplyChanges(void)
|
||||||
strcpy(text, "Apply the following changes?\n\n");
|
strcpy(text, "Apply the following changes?\n\n");
|
||||||
changes = PM_ChangeList(text+strlen(text), sizeof(text)-strlen(text));
|
changes = PM_ChangeList(text+strlen(text), sizeof(text)-strlen(text));
|
||||||
if (!changes)
|
if (!changes)
|
||||||
|
{
|
||||||
|
#ifdef WEBCLIENT
|
||||||
pkg_updating = false;//no changes...
|
pkg_updating = false;//no changes...
|
||||||
|
#endif
|
||||||
|
}
|
||||||
else
|
else
|
||||||
M_Menu_Prompt(PM_PromptApplyChanges_Callback, NULL, text, "Apply", NULL, "Cancel");
|
M_Menu_Prompt(PM_PromptApplyChanges_Callback, NULL, text, "Apply", NULL, "Cancel");
|
||||||
}
|
}
|
||||||
|
@ -2903,11 +2941,13 @@ static void MD_Draw (int x, int y, struct menucustom_s *c, struct menu_s *m)
|
||||||
if (p->alternative && (p->flags & DPF_HIDDEN))
|
if (p->alternative && (p->flags & DPF_HIDDEN))
|
||||||
p = p->alternative;
|
p = p->alternative;
|
||||||
|
|
||||||
|
#ifdef WEBCLIENT
|
||||||
if (p->download)
|
if (p->download)
|
||||||
Draw_FunString (x+4, y, va("%i", (int)p->download->qdownload.percent));
|
Draw_FunString (x+4, y, va("%i", (int)p->download->qdownload.percent));
|
||||||
else if (p->trymirrors)
|
else if (p->trymirrors)
|
||||||
Draw_FunString (x+4, y, "PND");
|
Draw_FunString (x+4, y, "PND");
|
||||||
else
|
else
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
switch((p->flags & (DPF_ENABLED | DPF_MARKED)))
|
switch((p->flags & (DPF_ENABLED | DPF_MARKED)))
|
||||||
{
|
{
|
||||||
|
@ -3055,14 +3095,17 @@ static qboolean MD_Key (struct menucustom_s *c, struct menu_s *m, int key, unsig
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef WEBCLIENT
|
||||||
else
|
else
|
||||||
p->trymirrors = 0;
|
p->trymirrors = 0;
|
||||||
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WEBCLIENT
|
||||||
static void MD_AutoUpdate_Draw (int x, int y, struct menucustom_s *c, struct menu_s *m)
|
static void MD_AutoUpdate_Draw (int x, int y, struct menucustom_s *c, struct menu_s *m)
|
||||||
{
|
{
|
||||||
char *settings[] =
|
char *settings[] =
|
||||||
|
@ -3094,6 +3137,17 @@ static qboolean MD_AutoUpdate_Key (struct menucustom_s *c, struct menu_s *m, int
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static qboolean MD_MarkUpdatesButton (union menuoption_s *mo,struct menu_s *m,int key)
|
||||||
|
{
|
||||||
|
if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_START || key == K_MOUSE1)
|
||||||
|
{
|
||||||
|
PM_MarkUpdates();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
qboolean MD_PopMenu (union menuoption_s *mo,struct menu_s *m,int key)
|
qboolean MD_PopMenu (union menuoption_s *mo,struct menu_s *m,int key)
|
||||||
{
|
{
|
||||||
if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_START || key == K_MOUSE1)
|
if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_START || key == K_MOUSE1)
|
||||||
|
@ -3114,15 +3168,6 @@ static qboolean MD_ApplyDownloads (union menuoption_s *mo,struct menu_s *m,int k
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static qboolean MD_MarkUpdatesButton (union menuoption_s *mo,struct menu_s *m,int key)
|
|
||||||
{
|
|
||||||
if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_START || key == K_MOUSE1)
|
|
||||||
{
|
|
||||||
PM_MarkUpdates();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
static qboolean MD_RevertUpdates (union menuoption_s *mo,struct menu_s *m,int key)
|
static qboolean MD_RevertUpdates (union menuoption_s *mo,struct menu_s *m,int key)
|
||||||
{
|
{
|
||||||
if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_START || key == K_MOUSE1)
|
if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_START || key == K_MOUSE1)
|
||||||
|
@ -3154,20 +3199,22 @@ static void MD_AddItemsToDownloadMenu(menu_t *m)
|
||||||
y+=8;
|
y+=8;
|
||||||
if (!prefixlen)
|
if (!prefixlen)
|
||||||
{
|
{
|
||||||
|
#ifdef WEBCLIENT
|
||||||
MC_AddCommand(m, 0, 170, y, "Mark Updates", MD_MarkUpdatesButton);
|
MC_AddCommand(m, 0, 170, y, "Mark Updates", MD_MarkUpdatesButton);
|
||||||
y+=8;
|
y+=8;
|
||||||
|
#endif
|
||||||
|
|
||||||
MC_AddCommand(m, 0, 170, y, "Revert Updates", MD_RevertUpdates);
|
MC_AddCommand(m, 0, 170, y, "Revert Updates", MD_RevertUpdates);
|
||||||
y+=8;
|
y+=8;
|
||||||
}
|
|
||||||
if (!prefixlen)
|
#ifdef WEBCLIENT
|
||||||
{
|
|
||||||
c = MC_AddCustom(m, 0, y, p, 0);
|
c = MC_AddCustom(m, 0, y, p, 0);
|
||||||
c->draw = MD_AutoUpdate_Draw;
|
c->draw = MD_AutoUpdate_Draw;
|
||||||
c->key = MD_AutoUpdate_Key;
|
c->key = MD_AutoUpdate_Key;
|
||||||
c->common.width = 320;
|
c->common.width = 320;
|
||||||
c->common.height = 8;
|
c->common.height = 8;
|
||||||
y += 8;
|
y += 8;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
y+=4; //small gap
|
y+=4; //small gap
|
||||||
|
|
|
@ -187,9 +187,6 @@ qboolean M_Options_InvertMouse (menucheck_t *option, struct menu_s *menu, chk_se
|
||||||
void M_Menu_Options_f (void)
|
void M_Menu_Options_f (void)
|
||||||
{
|
{
|
||||||
extern cvar_t crosshair, r_projection;
|
extern cvar_t crosshair, r_projection;
|
||||||
#ifndef CLIENTONLY
|
|
||||||
extern cvar_t sv_autosave;
|
|
||||||
#endif
|
|
||||||
int y;
|
int y;
|
||||||
|
|
||||||
static const char *projections[] = {
|
static const char *projections[] = {
|
||||||
|
@ -211,7 +208,8 @@ void M_Menu_Options_f (void)
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef CLIENTONLY
|
#if !defined(CLIENTONLY) && defined(SAVEDGAMES)
|
||||||
|
extern cvar_t sv_autosave;
|
||||||
static const char *autosaveopts[] = {
|
static const char *autosaveopts[] = {
|
||||||
"Off",
|
"Off",
|
||||||
"30 secs",
|
"30 secs",
|
||||||
|
@ -234,8 +232,8 @@ void M_Menu_Options_f (void)
|
||||||
|
|
||||||
menubulk_t bulk[] = {
|
menubulk_t bulk[] = {
|
||||||
MB_CONSOLECMD("Customize controls", "menu_keys\n", "Modify keyboard and mouse inputs."),
|
MB_CONSOLECMD("Customize controls", "menu_keys\n", "Modify keyboard and mouse inputs."),
|
||||||
#ifdef WEBCLIENT
|
#ifdef PACKAGEMANAGER
|
||||||
MB_CONSOLECMD("Updates and packages", "menu_download\n", "Modify keyboard and mouse inputs."),
|
MB_CONSOLECMD("Updates and Packages", "menu_download\n", "Configure additional content and plugins."),
|
||||||
#endif
|
#endif
|
||||||
MB_CONSOLECMD("Go to console", "toggleconsole\nplay misc/menu2.wav\n", "Open up the engine console."),
|
MB_CONSOLECMD("Go to console", "toggleconsole\nplay misc/menu2.wav\n", "Open up the engine console."),
|
||||||
MB_CONSOLECMD("Reset to defaults", "cvarreset *\nexec default.cfg\nplay misc/menu2.wav\n", "Reloads the default configuration."),
|
MB_CONSOLECMD("Reset to defaults", "cvarreset *\nexec default.cfg\nplay misc/menu2.wav\n", "Reloads the default configuration."),
|
||||||
|
@ -250,7 +248,7 @@ void M_Menu_Options_f (void)
|
||||||
MB_CHECKBOXCVAR("Lookspring", lookspring, 0),
|
MB_CHECKBOXCVAR("Lookspring", lookspring, 0),
|
||||||
MB_CHECKBOXCVAR("Lookstrafe", lookstrafe, 0),
|
MB_CHECKBOXCVAR("Lookstrafe", lookstrafe, 0),
|
||||||
MB_CHECKBOXCVAR("Windowed Mouse", _windowed_mouse, 0),
|
MB_CHECKBOXCVAR("Windowed Mouse", _windowed_mouse, 0),
|
||||||
#ifndef CLIENTONLY
|
#if !defined(CLIENTONLY) && defined(SAVEDGAMES)
|
||||||
MB_COMBOCVAR("Auto Save", sv_autosave, autosaveopts, autosavevals, NULL),
|
MB_COMBOCVAR("Auto Save", sv_autosave, autosaveopts, autosavevals, NULL),
|
||||||
#endif
|
#endif
|
||||||
MB_SPACING(4),
|
MB_SPACING(4),
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include "winquake.h"
|
#include "winquake.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
#ifndef NOBUILTINMENUS
|
#ifndef NOBUILTINMENUS
|
||||||
#ifndef CLIENTONLY
|
#if !defined(CLIENTONLY) && defined(SAVEDGAMES)
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
/* LOAD/SAVE MENU */
|
/* LOAD/SAVE MENU */
|
||||||
|
|
||||||
|
@ -329,10 +329,10 @@ void M_Menu_SinglePlayer_f (void)
|
||||||
MC_AddConsoleCommand (menu, 64, 170, 40, "Easy", va("closemenu; skill 0;deathmatch 0; coop %i;newgame\n", cl_splitscreen.ival>0));
|
MC_AddConsoleCommand (menu, 64, 170, 40, "Easy", va("closemenu; skill 0;deathmatch 0; coop %i;newgame\n", cl_splitscreen.ival>0));
|
||||||
MC_AddConsoleCommand (menu, 64, 170, 48, "Medium", va("closemenu; skill 1;deathmatch 0; coop %i;newgame\n", cl_splitscreen.ival>0));
|
MC_AddConsoleCommand (menu, 64, 170, 48, "Medium", va("closemenu; skill 1;deathmatch 0; coop %i;newgame\n", cl_splitscreen.ival>0));
|
||||||
MC_AddConsoleCommand (menu, 64, 170, 56, "Hard", va("closemenu; skill 2;deathmatch 0; coop %i;newgame\n", cl_splitscreen.ival>0));
|
MC_AddConsoleCommand (menu, 64, 170, 56, "Hard", va("closemenu; skill 2;deathmatch 0; coop %i;newgame\n", cl_splitscreen.ival>0));
|
||||||
|
#ifdef SAVEDGAMES
|
||||||
MC_AddConsoleCommand (menu, 64, 170, 72, "Load Game", "menu_load\n");
|
MC_AddConsoleCommand (menu, 64, 170, 72, "Load Game", "menu_load\n");
|
||||||
MC_AddConsoleCommand (menu, 64, 170, 80, "Save Game", "menu_save\n");
|
MC_AddConsoleCommand (menu, 64, 170, 80, "Save Game", "menu_save\n");
|
||||||
|
#endif
|
||||||
menu->cursoritem = (menuoption_t*)MC_AddWhiteText(menu, 48, 0, 40, NULL, false);
|
menu->cursoritem = (menuoption_t*)MC_AddWhiteText(menu, 48, 0, 40, NULL, false);
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
@ -455,8 +455,10 @@ void M_Menu_SinglePlayer_f (void)
|
||||||
menu->selecteditem = (menuoption_t*)
|
menu->selecteditem = (menuoption_t*)
|
||||||
MC_AddConsoleCommandHexen2BigFont(menu, 80, y+=20, "New Game", "menu_single class demo1\n");
|
MC_AddConsoleCommandHexen2BigFont(menu, 80, y+=20, "New Game", "menu_single class demo1\n");
|
||||||
}
|
}
|
||||||
|
#ifdef SAVEDGAMES
|
||||||
MC_AddConsoleCommandHexen2BigFont(menu, 80, y+=20, "Save Game", "menu_save\n");
|
MC_AddConsoleCommandHexen2BigFont(menu, 80, y+=20, "Save Game", "menu_save\n");
|
||||||
MC_AddConsoleCommandHexen2BigFont(menu, 80, y+=20, "Load Game", "menu_load\n");
|
MC_AddConsoleCommandHexen2BigFont(menu, 80, y+=20, "Load Game", "menu_load\n");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
menu->cursoritem = (menuoption_t *)MC_AddCursor(menu, &resel, 56, menu->selecteditem?menu->selecteditem->common.posy:0);
|
menu->cursoritem = (menuoption_t *)MC_AddCursor(menu, &resel, 56, menu->selecteditem?menu->selecteditem->common.posy:0);
|
||||||
|
@ -474,8 +476,10 @@ void M_Menu_SinglePlayer_f (void)
|
||||||
|
|
||||||
menu->selecteditem = (menuoption_t*)
|
menu->selecteditem = (menuoption_t*)
|
||||||
MC_AddConsoleCommandQBigFont (menu, 72, 32, "New Game", "closemenu;disconnect;maxclients 1;samelevel \"\";deathmatch \"\";set_calc coop ($cl_splitscreen>0);startmap_sp\n");
|
MC_AddConsoleCommandQBigFont (menu, 72, 32, "New Game", "closemenu;disconnect;maxclients 1;samelevel \"\";deathmatch \"\";set_calc coop ($cl_splitscreen>0);startmap_sp\n");
|
||||||
|
#ifdef SAVEDGAMES
|
||||||
MC_AddConsoleCommandQBigFont (menu, 72, 52, "Load Game", "menu_load\n");
|
MC_AddConsoleCommandQBigFont (menu, 72, 52, "Load Game", "menu_load\n");
|
||||||
MC_AddConsoleCommandQBigFont (menu, 72, 72, "Save Game", "menu_save\n");
|
MC_AddConsoleCommandQBigFont (menu, 72, 72, "Save Game", "menu_save\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
menu->cursoritem = (menuoption_t*)MC_AddCursor(menu, &resel, 54, 32);
|
menu->cursoritem = (menuoption_t*)MC_AddCursor(menu, &resel, 54, 32);
|
||||||
return;
|
return;
|
||||||
|
@ -525,12 +529,14 @@ void M_Menu_SinglePlayer_f (void)
|
||||||
menu->selecteditem = (menuoption_t *)b;
|
menu->selecteditem = (menuoption_t *)b;
|
||||||
b->common.width = width;
|
b->common.width = width;
|
||||||
b->common.height = 20;
|
b->common.height = 20;
|
||||||
|
#ifdef SAVEDGAMES
|
||||||
b = MC_AddConsoleCommand (menu, 72, 304, 52, "", "menu_load\n");
|
b = MC_AddConsoleCommand (menu, 72, 304, 52, "", "menu_load\n");
|
||||||
b->common.width = width;
|
b->common.width = width;
|
||||||
b->common.height = 20;
|
b->common.height = 20;
|
||||||
b = MC_AddConsoleCommand (menu, 72, 304, 72, "", "menu_save\n");
|
b = MC_AddConsoleCommand (menu, 72, 304, 72, "", "menu_save\n");
|
||||||
b->common.width = width;
|
b->common.width = width;
|
||||||
b->common.height = 20;
|
b->common.height = 20;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if MAX_SPLITS > 1
|
#if MAX_SPLITS > 1
|
||||||
b = (menubutton_t*)MC_AddCvarCombo(menu, 72, 72+width/2, 92, "", &cl_splitscreen, opts, vals);
|
b = (menubutton_t*)MC_AddCvarCombo(menu, 72, 72+width/2, 92, "", &cl_splitscreen, opts, vals);
|
||||||
|
|
|
@ -1222,7 +1222,7 @@ void M_Init_Internal (void)
|
||||||
return;
|
return;
|
||||||
internalmenusregistered = true;
|
internalmenusregistered = true;
|
||||||
|
|
||||||
#ifndef CLIENTONLY
|
#if !defined(CLIENTONLY) && defined(SAVEDGAMES)
|
||||||
Cmd_AddCommand ("menu_save", M_Menu_Save_f);
|
Cmd_AddCommand ("menu_save", M_Menu_Save_f);
|
||||||
Cmd_AddCommand ("menu_load", M_Menu_Load_f);
|
Cmd_AddCommand ("menu_load", M_Menu_Load_f);
|
||||||
Cmd_AddCommand ("menu_loadgame", M_Menu_Load_f); //q2...
|
Cmd_AddCommand ("menu_loadgame", M_Menu_Load_f); //q2...
|
||||||
|
@ -1371,7 +1371,7 @@ void M_Init (void)
|
||||||
Cmd_AddCommand ("menu_servers", M_Menu_ServerList2_f);
|
Cmd_AddCommand ("menu_servers", M_Menu_ServerList2_f);
|
||||||
#endif
|
#endif
|
||||||
//downloads menu needs sandboxing, so cannot be provided by qc.
|
//downloads menu needs sandboxing, so cannot be provided by qc.
|
||||||
#ifdef WEBCLIENT
|
#ifdef PACKAGEMANAGER
|
||||||
Cmd_AddCommand ("menu_download", Menu_DownloadStuff_f);
|
Cmd_AddCommand ("menu_download", Menu_DownloadStuff_f);
|
||||||
#endif
|
#endif
|
||||||
//demo menu is allowed to see outside of the quakedir. you can't replicate that in qc's sandbox.
|
//demo menu is allowed to see outside of the quakedir. you can't replicate that in qc's sandbox.
|
||||||
|
|
|
@ -1817,6 +1817,8 @@ static void QCBUILTIN PF_m_setmodel(pubprogfuncs_t *prinst, struct globalvars_s
|
||||||
model_t *mod = Mod_ForName(modelname, MLV_WARN);
|
model_t *mod = Mod_ForName(modelname, MLV_WARN);
|
||||||
if (modelval)
|
if (modelval)
|
||||||
modelval->string = G_INT(OFS_PARM1); //lets hope garbage collection is enough.
|
modelval->string = G_INT(OFS_PARM1); //lets hope garbage collection is enough.
|
||||||
|
else
|
||||||
|
Con_Printf("PF_m_setmodel: no model field!\n");
|
||||||
|
|
||||||
if (mod)
|
if (mod)
|
||||||
while(mod->loadstate == MLS_LOADING)
|
while(mod->loadstate == MLS_LOADING)
|
||||||
|
@ -1834,7 +1836,10 @@ static void QCBUILTIN PF_m_setcustomskin(pubprogfuncs_t *prinst, struct globalva
|
||||||
const char *skindata = PF_VarString(prinst, 2, pr_globals);
|
const char *skindata = PF_VarString(prinst, 2, pr_globals);
|
||||||
eval_t *val = prinst->GetEdictFieldValue(prinst, (void*)ent, "skinobject", ev_string, &menuc_eval.skinobject);
|
eval_t *val = prinst->GetEdictFieldValue(prinst, (void*)ent, "skinobject", ev_string, &menuc_eval.skinobject);
|
||||||
if (!val)
|
if (!val)
|
||||||
|
{
|
||||||
|
Con_Printf("PF_m_setcustomskin: no skinobject field!\n");
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (val->_float > 0)
|
if (val->_float > 0)
|
||||||
{
|
{
|
||||||
|
@ -1858,6 +1863,8 @@ static void QCBUILTIN PF_m_setorigin(pubprogfuncs_t *prinst, struct globalvars_s
|
||||||
eval_t *val = prinst->GetEdictFieldValue(prinst, (void*)ent, "origin", ev_vector, &menuc_eval.origin);
|
eval_t *val = prinst->GetEdictFieldValue(prinst, (void*)ent, "origin", ev_vector, &menuc_eval.origin);
|
||||||
if (val)
|
if (val)
|
||||||
VectorCopy(org, val->_vector);
|
VectorCopy(org, val->_vector);
|
||||||
|
else
|
||||||
|
Con_Printf("PF_m_setorigin: no origin field!\n");
|
||||||
}
|
}
|
||||||
static void QCBUILTIN PF_m_clearscene(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
static void QCBUILTIN PF_m_clearscene(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||||
{
|
{
|
||||||
|
@ -2645,6 +2652,12 @@ qboolean MP_Init (void)
|
||||||
|
|
||||||
PR_ProgsAdded(menu_world.progs, mprogs, "menu.dat");
|
PR_ProgsAdded(menu_world.progs, mprogs, "menu.dat");
|
||||||
|
|
||||||
|
//ensure that there's space for these fields in.
|
||||||
|
//other fields will always be referenced/defined by the qc, or 0.
|
||||||
|
PR_RegisterFieldVar(menu_world.progs, ev_string, "model", -1, -1);
|
||||||
|
PR_RegisterFieldVar(menu_world.progs, ev_vector, "origin", -1, -1);
|
||||||
|
PR_RegisterFieldVar(menu_world.progs, ev_float, "skinobject", -1, -1);
|
||||||
|
|
||||||
menuentsize = PR_InitEnts(menu_world.progs, 8192);
|
menuentsize = PR_InitEnts(menu_world.progs, 8192);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1453,7 +1453,7 @@ void V_ClearRefdef(playerview_t *pv)
|
||||||
r_refdef.fovv_x = 0;
|
r_refdef.fovv_x = 0;
|
||||||
r_refdef.fovv_y = 0;
|
r_refdef.fovv_y = 0;
|
||||||
|
|
||||||
r_refdef.drawsbar = cl.intermissionmode == IM_NONE;
|
r_refdef.drawsbar = (cl.intermissionmode == IM_NONE);
|
||||||
r_refdef.flags = 0;
|
r_refdef.flags = 0;
|
||||||
|
|
||||||
r_refdef.areabitsknown = false;
|
r_refdef.areabitsknown = false;
|
||||||
|
|
|
@ -111,6 +111,7 @@
|
||||||
#define SUBSERVERS //Allows the server to fork itself, each acting as an MMO-style server instance of a single 'realm'.
|
#define SUBSERVERS //Allows the server to fork itself, each acting as an MMO-style server instance of a single 'realm'.
|
||||||
//#define HLCLIENT 7 //we can run HL gamecode (not protocol compatible, set to 6 or 7)
|
//#define HLCLIENT 7 //we can run HL gamecode (not protocol compatible, set to 6 or 7)
|
||||||
//#define HLSERVER 140 //we can run HL gamecode (not protocol compatible, set to 138 or 140)
|
//#define HLSERVER 140 //we can run HL gamecode (not protocol compatible, set to 138 or 140)
|
||||||
|
#define SAVEDGAMES //Can save the game.
|
||||||
|
|
||||||
// Networking options
|
// Networking options
|
||||||
#define NQPROT //act as an nq client/server, with nq gamecode.
|
#define NQPROT //act as an nq client/server, with nq gamecode.
|
||||||
|
@ -124,6 +125,7 @@
|
||||||
//#define IRCCONNECT //lame support for routing game packets via irc server. not a good idea.
|
//#define IRCCONNECT //lame support for routing game packets via irc server. not a good idea.
|
||||||
#define SUPPORT_ICE //Internet Connectivity Establishment, for use by plugins to establish voice or game connections.
|
#define SUPPORT_ICE //Internet Connectivity Establishment, for use by plugins to establish voice or game connections.
|
||||||
#define CL_MASTER //Clientside Server Browser functionality.
|
#define CL_MASTER //Clientside Server Browser functionality.
|
||||||
|
#define PACKAGEMANAGER //Allows the user to enable/disable/download(with WEBCLIENT) packages and plugins.
|
||||||
|
|
||||||
// Audio Drivers
|
// Audio Drivers
|
||||||
#define AVAIL_OPENAL
|
#define AVAIL_OPENAL
|
||||||
|
|
|
@ -113,6 +113,7 @@
|
||||||
//#define SUBSERVERS //Allows the server to fork itself, each acting as an MMO-style server instance of a single 'realm'.
|
//#define SUBSERVERS //Allows the server to fork itself, each acting as an MMO-style server instance of a single 'realm'.
|
||||||
////#define HLCLIENT 7 //we can run HL gamecode (not protocol compatible, set to 6 or 7)
|
////#define HLCLIENT 7 //we can run HL gamecode (not protocol compatible, set to 6 or 7)
|
||||||
////#define HLSERVER 140 //we can run HL gamecode (not protocol compatible, set to 138 or 140)
|
////#define HLSERVER 140 //we can run HL gamecode (not protocol compatible, set to 138 or 140)
|
||||||
|
//#define SAVEDGAMES //Can save the game.
|
||||||
|
|
||||||
// Networking options
|
// Networking options
|
||||||
//#define NQPROT //act as an nq client/server, with nq gamecode.
|
//#define NQPROT //act as an nq client/server, with nq gamecode.
|
||||||
|
@ -126,6 +127,7 @@
|
||||||
//#define IRCCONNECT //lame support for routing game packets via irc server. not a good idea.
|
//#define IRCCONNECT //lame support for routing game packets via irc server. not a good idea.
|
||||||
//#define SUPPORT_ICE //Internet Connectivity Establishment, for use by plugins to establish voice or game connections.
|
//#define SUPPORT_ICE //Internet Connectivity Establishment, for use by plugins to establish voice or game connections.
|
||||||
//#define CL_MASTER //Clientside Server Browser functionality.
|
//#define CL_MASTER //Clientside Server Browser functionality.
|
||||||
|
//#define PACKAGEMANAGER //Allows the user to enable/disable/download packages and plugins.
|
||||||
|
|
||||||
// Audio Drivers
|
// Audio Drivers
|
||||||
//#define AVAIL_OPENAL
|
//#define AVAIL_OPENAL
|
||||||
|
|
|
@ -110,6 +110,7 @@
|
||||||
//#define SUBSERVERS //Allows the server to fork itself, each acting as an MMO-style server instance of a single 'realm'.
|
//#define SUBSERVERS //Allows the server to fork itself, each acting as an MMO-style server instance of a single 'realm'.
|
||||||
//#define HLCLIENT 7 //we can run HL gamecode (not protocol compatible, set to 6 or 7)
|
//#define HLCLIENT 7 //we can run HL gamecode (not protocol compatible, set to 6 or 7)
|
||||||
//#define HLSERVER 140 //we can run HL gamecode (not protocol compatible, set to 138 or 140)
|
//#define HLSERVER 140 //we can run HL gamecode (not protocol compatible, set to 138 or 140)
|
||||||
|
#define SAVEDGAMES //Can save the game.
|
||||||
|
|
||||||
// Networking options
|
// Networking options
|
||||||
//#define NQPROT //act as an nq client/server, with nq gamecode.
|
//#define NQPROT //act as an nq client/server, with nq gamecode.
|
||||||
|
@ -123,6 +124,7 @@
|
||||||
//#define IRCCONNECT //lame support for routing game packets via irc server. not a good idea.
|
//#define IRCCONNECT //lame support for routing game packets via irc server. not a good idea.
|
||||||
#define SUPPORT_ICE //Internet Connectivity Establishment, for use by plugins to establish voice or game connections.
|
#define SUPPORT_ICE //Internet Connectivity Establishment, for use by plugins to establish voice or game connections.
|
||||||
#define CL_MASTER //Clientside Server Browser functionality.
|
#define CL_MASTER //Clientside Server Browser functionality.
|
||||||
|
//#define PACKAGEMANAGER //Allows the user to enable/disable/download packages and plugins.
|
||||||
|
|
||||||
// Audio Drivers
|
// Audio Drivers
|
||||||
#define AVAIL_OPENAL
|
#define AVAIL_OPENAL
|
||||||
|
|
|
@ -163,6 +163,8 @@
|
||||||
#undef HAVE_MEDIA_DECODER //can play cin/roq, more with plugins
|
#undef HAVE_MEDIA_DECODER //can play cin/roq, more with plugins
|
||||||
#undef HAVE_MEDIA_ENCODER //capture/capturedemo work.
|
#undef HAVE_MEDIA_ENCODER //capture/capturedemo work.
|
||||||
#undef HAVE_SPEECHTOTEXT //windows speech-to-text thing
|
#undef HAVE_SPEECHTOTEXT //windows speech-to-text thing
|
||||||
|
//#define SAVEDGAMES //Can save the game.
|
||||||
|
#undef PACKAGEMANAGER //Allows the user to enable/disable/download packages and plugins.
|
||||||
|
|
||||||
#ifdef COMPILE_OPTS
|
#ifdef COMPILE_OPTS
|
||||||
//things to configure qclib, which annoyingly doesn't include this file itself
|
//things to configure qclib, which annoyingly doesn't include this file itself
|
||||||
|
|
|
@ -2242,6 +2242,11 @@ bspx_header_t *BSPX_Setup(model_t *mod, char *filebase, unsigned int filelen, lu
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SERVERONLY
|
||||||
|
void BSPX_LoadEnvmaps(model_t *mod, bspx_header_t *bspx, void *mod_base)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#else
|
||||||
/*
|
/*
|
||||||
void *SCR_ScreenShot_Capture(int fbwidth, int fbheight, int *stride, enum uploadfmt *fmt);
|
void *SCR_ScreenShot_Capture(int fbwidth, int fbheight, int *stride, enum uploadfmt *fmt);
|
||||||
void BSPX_RenderEnvmaps(model_t *mod)
|
void BSPX_RenderEnvmaps(model_t *mod)
|
||||||
|
@ -2408,9 +2413,6 @@ void BSPX_LoadEnvmaps(model_t *mod, bspx_header_t *bspx, void *mod_base)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if 1//ndef SERVERONLY
|
|
||||||
|
|
||||||
struct bspxrw
|
struct bspxrw
|
||||||
{
|
{
|
||||||
fromgame_t fg;
|
fromgame_t fg;
|
||||||
|
@ -2632,7 +2634,13 @@ unsigned int Mod_NearestCubeForSurf(msurface_t *surf, denvmap_t *envmap, size_t
|
||||||
for (n = 0; n < nenvmap; n++)
|
for (n = 0; n < nenvmap; n++)
|
||||||
{
|
{
|
||||||
VectorSubtract(mid, envmap[n].origin, diff);
|
VectorSubtract(mid, envmap[n].origin, diff);
|
||||||
|
#if 1
|
||||||
|
//axial distance
|
||||||
|
dist = min(min(fabs(diff[0]), fabs(diff[1])), fabs(diff[2]));
|
||||||
|
#else
|
||||||
|
//radial distance (squared)
|
||||||
dist = DotProduct(diff,diff);
|
dist = DotProduct(diff,diff);
|
||||||
|
#endif
|
||||||
if (bestdist > dist)
|
if (bestdist > dist)
|
||||||
{
|
{
|
||||||
best = n;
|
best = n;
|
||||||
|
|
|
@ -736,10 +736,12 @@ void Mod_Purge(enum mod_purge_e ptype)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef SERVERONLY
|
||||||
void Mod_FindCubemaps_f(void);
|
void Mod_FindCubemaps_f(void);
|
||||||
void Mod_Realign_f(void);
|
void Mod_Realign_f(void);
|
||||||
void Mod_BSPX_List_f(void);
|
void Mod_BSPX_List_f(void);
|
||||||
void Mod_BSPX_Strip_f(void);
|
void Mod_BSPX_Strip_f(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===============
|
===============
|
||||||
|
@ -777,10 +779,12 @@ void Mod_Init (qboolean initial)
|
||||||
Cmd_AddCommand("sv_saveentfile", Mod_SaveEntFile_f);
|
Cmd_AddCommand("sv_saveentfile", Mod_SaveEntFile_f);
|
||||||
Cmd_AddCommand("version_modelformats", Mod_PrintFormats_f);
|
Cmd_AddCommand("version_modelformats", Mod_PrintFormats_f);
|
||||||
|
|
||||||
|
#ifndef SERVERONLY
|
||||||
Cmd_AddCommandD("map_findcubemaps", Mod_FindCubemaps_f, "Scans the entities of a map to find reflection envmap sites and determines the nearest one to each surface.");
|
Cmd_AddCommandD("map_findcubemaps", Mod_FindCubemaps_f, "Scans the entities of a map to find reflection envmap sites and determines the nearest one to each surface.");
|
||||||
Cmd_AddCommandD("map_realign", Mod_Realign_f, "Reads the named bsp and writes it back out with only alignment changes.");
|
Cmd_AddCommandD("map_realign", Mod_Realign_f, "Reads the named bsp and writes it back out with only alignment changes.");
|
||||||
Cmd_AddCommandD("map_bspx_list", Mod_BSPX_List_f, "Lists all lumps (and their sizes) in the specified bsp.");
|
Cmd_AddCommandD("map_bspx_list", Mod_BSPX_List_f, "Lists all lumps (and their sizes) in the specified bsp.");
|
||||||
Cmd_AddCommandD("map_bspx_strip", Mod_BSPX_Strip_f, "Strips a named extension lump from a bsp file.");
|
Cmd_AddCommandD("map_bspx_strip", Mod_BSPX_Strip_f, "Strips a named extension lump from a bsp file.");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (initial)
|
if (initial)
|
||||||
|
|
|
@ -1877,26 +1877,74 @@ static const char *glsl_hdrs[] =
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
qboolean GLSlang_GenerateIncludes(int maxstrings, int *strings, const GLchar *prstrings[], GLint length[], const char *shadersource)
|
#define GLSLPARTS (64+16)
|
||||||
|
struct glslparts_s
|
||||||
|
{
|
||||||
|
const GLchar *str[GLSLPARTS];
|
||||||
|
GLint len[GLSLPARTS];
|
||||||
|
const GLchar *file[GLSLPARTS];
|
||||||
|
int line[GLSLPARTS];
|
||||||
|
int strings;
|
||||||
|
|
||||||
|
const char *error;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void GLSlang_GenerateInternal(struct glslparts_s *glsl, const char *shadersource)
|
||||||
|
{
|
||||||
|
if (glsl->strings == GLSLPARTS)
|
||||||
|
{
|
||||||
|
glsl->error = "Too many parts";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
glsl->str[glsl->strings] = shadersource;
|
||||||
|
glsl->len[glsl->strings] = strlen(shadersource);
|
||||||
|
glsl->file[glsl->strings] = NULL;
|
||||||
|
glsl->line[glsl->strings] = 0;
|
||||||
|
glsl->strings += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GLSlang_Generate(struct glslparts_s *glsl, const char *shadersource, GLint length, const char *filename, int linenumber)
|
||||||
|
{
|
||||||
|
if (glsl->strings == GLSLPARTS)
|
||||||
|
{
|
||||||
|
glsl->error = "Too many parts";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
glsl->str[glsl->strings] = shadersource;
|
||||||
|
glsl->len[glsl->strings] = length;
|
||||||
|
glsl->file[glsl->strings] = filename;
|
||||||
|
glsl->line[glsl->strings] = linenumber;
|
||||||
|
glsl->strings += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static qboolean GLSlang_GenerateIncludes(struct glslparts_s *glsl, const char *shadersource, const char *filename, int linenumber)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
char *incline, *inc;
|
char *incline, *inc;
|
||||||
char incname[256];
|
char incname[256];
|
||||||
while((incline=strstr(shadersource, "#include")))
|
while((incline=strstr(shadersource, "#include")))
|
||||||
{
|
{
|
||||||
if (*strings == maxstrings)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/*emit up to the include*/
|
/*emit up to the include*/
|
||||||
if (incline - shadersource)
|
if (incline - shadersource)
|
||||||
{
|
{
|
||||||
prstrings[*strings] = shadersource;
|
char *e = incline;
|
||||||
length[*strings] = incline - shadersource;
|
while(e > shadersource && (e[-1] == ' ' || e[-1] == '\t'))
|
||||||
*strings += 1;
|
e--;
|
||||||
|
if (e > shadersource && e[-1] == '\n')
|
||||||
|
GLSlang_Generate(glsl, shadersource, e-shadersource, filename, linenumber);
|
||||||
|
else
|
||||||
|
GLSlang_Generate(glsl, shadersource, incline-shadersource, filename, linenumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
incline += 8;
|
incline += 8;
|
||||||
incline = COM_ParseOut (incline, incname, sizeof(incname));
|
incline = COM_ParseOut (incline, incname, sizeof(incname));
|
||||||
|
if (!incline)
|
||||||
|
{
|
||||||
|
glsl->error = "missing include name";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
while (*incline == ' ' || *incline == '\t')
|
||||||
|
incline++;
|
||||||
|
|
||||||
if (!strncmp(incname, "cvar/", 5))
|
if (!strncmp(incname, "cvar/", 5))
|
||||||
{
|
{
|
||||||
|
@ -1904,17 +1952,13 @@ qboolean GLSlang_GenerateIncludes(int maxstrings, int *strings, const GLchar *pr
|
||||||
if (var)
|
if (var)
|
||||||
{
|
{
|
||||||
var->flags |= CVAR_SHADERSYSTEM;
|
var->flags |= CVAR_SHADERSYSTEM;
|
||||||
if (!GLSlang_GenerateIncludes(maxstrings, strings, prstrings, length, var->string))
|
if (!GLSlang_GenerateIncludes(glsl, var->string, NULL, 0))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*dump something if the cvar doesn't exist*/
|
/*dump something if the cvar doesn't exist*/
|
||||||
if (*strings == maxstrings)
|
GLSlang_Generate(glsl, "0", strlen("0"), filename, linenumber);
|
||||||
return false;
|
|
||||||
prstrings[*strings] = "0";
|
|
||||||
length[*strings] = strlen("0");
|
|
||||||
*strings += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1923,38 +1967,39 @@ qboolean GLSlang_GenerateIncludes(int maxstrings, int *strings, const GLchar *pr
|
||||||
{
|
{
|
||||||
if (!strcmp(incname, glsl_hdrs[i]))
|
if (!strcmp(incname, glsl_hdrs[i]))
|
||||||
{
|
{
|
||||||
if (!GLSlang_GenerateIncludes(maxstrings, strings, prstrings, length, glsl_hdrs[i+1]))
|
if (!GLSlang_GenerateIncludes(glsl, glsl_hdrs[i+1], glsl_hdrs[i], 1))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!glsl_hdrs[i])
|
if (!glsl_hdrs[i])
|
||||||
{
|
{
|
||||||
if (FS_LoadFile(incname, (void**)&inc) != (qofs_t)-1)
|
size_t sz;
|
||||||
|
inc = COM_LoadTempMoreFile(incname, &sz);
|
||||||
|
if (inc)
|
||||||
{
|
{
|
||||||
if (!GLSlang_GenerateIncludes(maxstrings, strings, prstrings, length, inc))
|
if (!GLSlang_GenerateIncludes(glsl, inc, NULL, 1))
|
||||||
{
|
|
||||||
FS_FreeFile(inc);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
FS_FreeFile(inc);
|
else
|
||||||
|
{
|
||||||
|
glsl->error = "include file not found";
|
||||||
|
return false; //FIXME: add a warning
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*move the pointer past the include*/
|
/*move the pointer past the include*/
|
||||||
shadersource = incline;
|
while (shadersource < incline)
|
||||||
}
|
|
||||||
if (*shadersource)
|
|
||||||
{
|
{
|
||||||
if (*strings == maxstrings)
|
if (*shadersource == '\n')
|
||||||
return false;
|
linenumber++;
|
||||||
|
shadersource++;
|
||||||
/*dump the remaining shader string*/
|
|
||||||
prstrings[*strings] = shadersource;
|
|
||||||
length[*strings] = strlen(prstrings[*strings]);
|
|
||||||
*strings += 1;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*shadersource)
|
||||||
|
GLSlang_Generate(glsl, shadersource, strlen(shadersource), filename, linenumber);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1965,11 +2010,12 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int
|
||||||
{
|
{
|
||||||
GLhandleARB shader;
|
GLhandleARB shader;
|
||||||
int i;
|
int i;
|
||||||
const GLchar *prstrings[64+16];
|
struct glslparts_s glsl;
|
||||||
GLint length[sizeof(prstrings)/sizeof(prstrings[0])];
|
|
||||||
int strings = 0;
|
|
||||||
char verline[64];
|
char verline[64];
|
||||||
|
|
||||||
|
glsl.strings = 0;
|
||||||
|
glsl.error = NULL;
|
||||||
|
|
||||||
if (!shadersource)
|
if (!shadersource)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -2013,44 +2059,32 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int
|
||||||
Q_snprintfz(verline, sizeof(verline), "#version %u compatibility\n", ver);
|
Q_snprintfz(verline, sizeof(verline), "#version %u compatibility\n", ver);
|
||||||
else
|
else
|
||||||
Q_snprintfz(verline, sizeof(verline), "#version %u\n", ver); //core assumed, where defined
|
Q_snprintfz(verline, sizeof(verline), "#version %u\n", ver); //core assumed, where defined
|
||||||
prstrings[strings] = verline;
|
GLSlang_GenerateInternal(&glsl, verline);
|
||||||
length[strings] = strlen(prstrings[strings]);
|
|
||||||
strings++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while(*precompilerconstants)
|
while(*precompilerconstants)
|
||||||
{
|
GLSlang_GenerateInternal(&glsl, *precompilerconstants++);
|
||||||
prstrings[strings] = *precompilerconstants++;
|
|
||||||
length[strings] = strlen(prstrings[strings]);
|
|
||||||
strings++;
|
|
||||||
}
|
|
||||||
|
|
||||||
prstrings[strings] = "#define ENGINE_"DISTRIBUTION"\n";
|
GLSlang_GenerateInternal(&glsl, "#define ENGINE_"DISTRIBUTION"\n");
|
||||||
length[strings] = strlen(prstrings[strings]);
|
|
||||||
strings++;
|
|
||||||
|
|
||||||
switch (shadertype)
|
switch (shadertype)
|
||||||
{
|
{
|
||||||
case GL_FRAGMENT_SHADER_ARB:
|
case GL_FRAGMENT_SHADER_ARB:
|
||||||
prstrings[strings] = "#define FRAGMENT_SHADER\n";
|
GLSlang_GenerateInternal(&glsl, "#define FRAGMENT_SHADER\n");
|
||||||
length[strings] = strlen(prstrings[strings]);
|
|
||||||
strings++;
|
|
||||||
if (gl_config.gles)
|
if (gl_config.gles)
|
||||||
{
|
{
|
||||||
prstrings[strings] =
|
GLSlang_GenerateInternal(&glsl,
|
||||||
"#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
|
"#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
|
||||||
"precision highp float;\n"
|
"precision highp float;\n"
|
||||||
"#else\n"
|
"#else\n"
|
||||||
"precision mediump float;\n"
|
"precision mediump float;\n"
|
||||||
"#endif\n"
|
"#endif\n"
|
||||||
;
|
);
|
||||||
length[strings] = strlen(prstrings[strings]);
|
|
||||||
strings++;
|
|
||||||
}
|
}
|
||||||
if (ver >= 130)
|
if (ver >= 130)
|
||||||
{
|
{
|
||||||
prstrings[strings] =
|
GLSlang_GenerateInternal(&glsl,
|
||||||
//gl3+ deprecated the some things. these are removed in forwards-compatible / core contexts.
|
//gl3+ deprecated the some things. these are removed in forwards-compatible / core contexts.
|
||||||
//varying became either in or out, which is important if you have geometry shaders...
|
//varying became either in or out, which is important if you have geometry shaders...
|
||||||
"#define varying in\n"
|
"#define varying in\n"
|
||||||
|
@ -2071,20 +2105,16 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int
|
||||||
"out vec4 fte_fragdata3;"
|
"out vec4 fte_fragdata3;"
|
||||||
"\n#endif\n" //gles3 requires this
|
"\n#endif\n" //gles3 requires this
|
||||||
"#define gl_FragColor fte_fragdata0\n"
|
"#define gl_FragColor fte_fragdata0\n"
|
||||||
;
|
);
|
||||||
length[strings] = strlen(prstrings[strings]);
|
|
||||||
strings++;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
prstrings[strings] =
|
GLSlang_GenerateInternal(&glsl,
|
||||||
"#define fte_fragdata0 gl_FragData[0]\n"
|
"#define fte_fragdata0 gl_FragData[0]\n"
|
||||||
"#define fte_fragdata1 gl_FragData[1]\n"
|
"#define fte_fragdata1 gl_FragData[1]\n"
|
||||||
"#define fte_fragdata2 gl_FragData[2]\n"
|
"#define fte_fragdata2 gl_FragData[2]\n"
|
||||||
"#define fte_fragdata3 gl_FragData[3]\n"
|
"#define fte_fragdata3 gl_FragData[3]\n"
|
||||||
;
|
);
|
||||||
length[strings] = strlen(prstrings[strings]);
|
|
||||||
strings++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prog)
|
if (prog)
|
||||||
|
@ -2127,82 +2157,62 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int
|
||||||
for (i = 0; i < countof(defaultsamplernames); i++)
|
for (i = 0; i < countof(defaultsamplernames); i++)
|
||||||
{
|
{
|
||||||
if (prog->defaulttextures & (1u<<i))
|
if (prog->defaulttextures & (1u<<i))
|
||||||
{
|
GLSlang_GenerateInternal(&glsl, defaultsamplernames[i]);
|
||||||
prstrings[strings] = defaultsamplernames[i];
|
|
||||||
length[strings] = strlen(prstrings[strings]);
|
|
||||||
strings++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
for (i = 0; i < prog->numsamplers && i < countof(numberedsamplernames); i++)
|
for (i = 0; i < prog->numsamplers && i < countof(numberedsamplernames); i++)
|
||||||
{
|
GLSlang_GenerateInternal(&glsl, numberedsamplernames[i]);
|
||||||
prstrings[strings] = numberedsamplernames[i];
|
|
||||||
length[strings] = strlen(prstrings[strings]);
|
|
||||||
strings++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GL_GEOMETRY_SHADER_ARB:
|
case GL_GEOMETRY_SHADER_ARB:
|
||||||
prstrings[strings] = "#define GEOMETRY_SHADER\n";
|
GLSlang_GenerateInternal(&glsl, "#define GEOMETRY_SHADER\n");
|
||||||
length[strings] = strlen(prstrings[strings]);
|
|
||||||
strings++;
|
|
||||||
break;
|
break;
|
||||||
case GL_TESS_CONTROL_SHADER_ARB:
|
case GL_TESS_CONTROL_SHADER_ARB:
|
||||||
prstrings[strings] =
|
GLSlang_GenerateInternal(&glsl,
|
||||||
"#define TESS_CONTROL_SHADER\n"
|
"#define TESS_CONTROL_SHADER\n"
|
||||||
"#if __VERSION__ < 400\n"
|
"#if __VERSION__ < 400\n"
|
||||||
"#extension GL_ARB_tessellation_shader : enable\n"
|
"#extension GL_ARB_tessellation_shader : enable\n"
|
||||||
"#endif\n";
|
"#endif\n"
|
||||||
//varyings are arrays, so don't bother defining that here.
|
//varyings are arrays, so don't bother defining that here.
|
||||||
length[strings] = strlen(prstrings[strings]);
|
);
|
||||||
strings++;
|
|
||||||
break;
|
break;
|
||||||
case GL_TESS_EVALUATION_SHADER_ARB:
|
case GL_TESS_EVALUATION_SHADER_ARB:
|
||||||
prstrings[strings] =
|
GLSlang_GenerateInternal(&glsl,
|
||||||
"#define TESS_EVALUATION_SHADER\n"
|
"#define TESS_EVALUATION_SHADER\n"
|
||||||
"#if __VERSION__ < 400\n"
|
"#if __VERSION__ < 400\n"
|
||||||
"#extension GL_ARB_tessellation_shader : enable\n"
|
"#extension GL_ARB_tessellation_shader : enable\n"
|
||||||
"#endif\n"
|
"#endif\n"
|
||||||
"#define varying out\n";
|
"#define varying out\n"
|
||||||
length[strings] = strlen(prstrings[strings]);
|
);
|
||||||
strings++;
|
|
||||||
break;
|
break;
|
||||||
case GL_VERTEX_SHADER_ARB:
|
case GL_VERTEX_SHADER_ARB:
|
||||||
prstrings[strings] = "#define VERTEX_SHADER\n";
|
GLSlang_GenerateInternal(&glsl, "#define VERTEX_SHADER\n");
|
||||||
length[strings] = strlen(prstrings[strings]);
|
|
||||||
strings++;
|
|
||||||
#ifdef RTLIGHTS
|
#ifdef RTLIGHTS
|
||||||
if (!r_shadow_shadowmapping.ival && ver >= 120)
|
if (!r_shadow_shadowmapping.ival && ver >= 120)
|
||||||
{
|
{
|
||||||
prstrings[strings] = "invariant gl_Position;\n";
|
GLSlang_GenerateInternal(&glsl, "invariant gl_Position;\n");
|
||||||
length[strings] = strlen(prstrings[strings]);
|
|
||||||
strings++;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (gl_config.gles)
|
if (gl_config.gles)
|
||||||
{
|
{
|
||||||
prstrings[strings] =
|
GLSlang_GenerateInternal(&glsl,
|
||||||
"#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
|
"#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
|
||||||
"precision highp float;\n"
|
"precision highp float;\n"
|
||||||
"#else\n"
|
"#else\n"
|
||||||
"precision mediump float;\n"
|
"precision mediump float;\n"
|
||||||
"#endif\n"
|
"#endif\n"
|
||||||
;
|
);
|
||||||
length[strings] = strlen(prstrings[strings]);
|
|
||||||
strings++;
|
|
||||||
}
|
}
|
||||||
if (ver >= 130)
|
if (ver >= 130)
|
||||||
{
|
{
|
||||||
prstrings[strings] =
|
GLSlang_GenerateInternal(&glsl,
|
||||||
"#define attribute in\n"
|
"#define attribute in\n"
|
||||||
"#define varying out\n"
|
"#define varying out\n"
|
||||||
;
|
);
|
||||||
length[strings] = strlen(prstrings[strings]);
|
|
||||||
strings++;
|
|
||||||
}
|
}
|
||||||
if (gl_config_nofixedfunc)
|
if (gl_config_nofixedfunc)
|
||||||
{
|
{
|
||||||
prstrings[strings] =
|
GLSlang_GenerateInternal(&glsl,
|
||||||
"attribute vec3 v_position1;\n"
|
"attribute vec3 v_position1;\n"
|
||||||
"#ifdef FRAMEBLEND\n"
|
"#ifdef FRAMEBLEND\n"
|
||||||
"attribute vec3 v_position2;\n"
|
"attribute vec3 v_position2;\n"
|
||||||
|
@ -2218,13 +2228,11 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int
|
||||||
#else
|
#else
|
||||||
"#define ftetransform() (m_modelviewprojection * vec4(v_position, 1.0))\n"
|
"#define ftetransform() (m_modelviewprojection * vec4(v_position, 1.0))\n"
|
||||||
#endif
|
#endif
|
||||||
;
|
);
|
||||||
length[strings] = strlen(prstrings[strings]);
|
|
||||||
strings++;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
prstrings[strings] =
|
GLSlang_GenerateInternal(&glsl,
|
||||||
"#ifdef FRAMEBLEND\n"
|
"#ifdef FRAMEBLEND\n"
|
||||||
"attribute vec3 v_position2;\n"
|
"attribute vec3 v_position2;\n"
|
||||||
"uniform vec2 e_vblend;\n"
|
"uniform vec2 e_vblend;\n"
|
||||||
|
@ -2236,24 +2244,51 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int
|
||||||
"uniform mat4 m_modelviewprojection;\n"
|
"uniform mat4 m_modelviewprojection;\n"
|
||||||
"#define ftetransform ftransform\n"
|
"#define ftetransform ftransform\n"
|
||||||
"#endif\n"
|
"#endif\n"
|
||||||
;
|
);
|
||||||
length[strings] = strlen(prstrings[strings]);
|
|
||||||
strings++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
prstrings[strings] = "#define UNKNOWN_SHADER\n";
|
GLSlang_GenerateInternal(&glsl, "#define UNKNOWN_SHADER\n");
|
||||||
length[strings] = strlen(prstrings[strings]);
|
|
||||||
strings++;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLSlang_GenerateIncludes(sizeof(prstrings)/sizeof(prstrings[0]), &strings, prstrings, length, shadersource);
|
GLSlang_GenerateIncludes(&glsl, shadersource, name, 1);
|
||||||
|
|
||||||
shader = qglCreateShaderObjectARB(shadertype);
|
shader = qglCreateShaderObjectARB(shadertype);
|
||||||
|
|
||||||
if (gl_workaround_ati_shadersource.ival)
|
if (developer.ival)
|
||||||
|
{
|
||||||
|
GLcharARB *combined;
|
||||||
|
int totallen = 1;
|
||||||
|
for (i = 0; i < glsl.strings; i++)
|
||||||
|
totallen += glsl.len[i] + 64;
|
||||||
|
combined = malloc(totallen);
|
||||||
|
totallen = 0;
|
||||||
|
combined[totallen] = 0;
|
||||||
|
for (i = 0; i < glsl.strings; i++)
|
||||||
|
{
|
||||||
|
if (ver && !i)
|
||||||
|
; //#version MUST be the first line, don't prefix it with a #line, it'll just break things.
|
||||||
|
else if (!totallen || combined[totallen-1] == '\n')
|
||||||
|
{ //last line was a newline, hurrah. safe to insert without breaking anything
|
||||||
|
Q_snprintfz(combined+totallen, 64, "#line %i %i //%s\n", glsl.line[i], i, glsl.file[i]);
|
||||||
|
totallen += strlen(combined+totallen);
|
||||||
|
}
|
||||||
|
else if (glsl.len[i] && *glsl.str[i] == '\n')
|
||||||
|
{ //last line didn't end with a newline, but there is one after. that's okay too, but we need to play it safe.
|
||||||
|
Q_snprintfz(combined+totallen, 64, "\n#line %i %i //%s\n", glsl.line[i], i, glsl.file[i]);
|
||||||
|
totallen += strlen(combined+totallen);
|
||||||
|
}
|
||||||
|
//now shove stuff there.
|
||||||
|
memcpy(combined+totallen, glsl.str[i], glsl.len[i]);
|
||||||
|
totallen += glsl.len[i];
|
||||||
|
combined[totallen] = 0;
|
||||||
|
}
|
||||||
|
qglShaderSourceARB(shader, 1, (const GLcharARB**)&combined, NULL);
|
||||||
|
free(combined);
|
||||||
|
}
|
||||||
|
else if (gl_workaround_ati_shadersource.ival)
|
||||||
{
|
{
|
||||||
/*ATI Driver Bug: ATI drivers ignore the 'length' array.
|
/*ATI Driver Bug: ATI drivers ignore the 'length' array.
|
||||||
this code does what the drivers fail to do.
|
this code does what the drivers fail to do.
|
||||||
|
@ -2262,22 +2297,22 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int
|
||||||
*/
|
*/
|
||||||
GLcharARB *combined;
|
GLcharARB *combined;
|
||||||
int totallen = 1;
|
int totallen = 1;
|
||||||
for (i = 0; i < strings; i++)
|
for (i = 0; i < glsl.strings; i++)
|
||||||
totallen += length[i];
|
totallen += glsl.len[i];
|
||||||
combined = malloc(totallen);
|
combined = malloc(totallen);
|
||||||
totallen = 0;
|
totallen = 0;
|
||||||
combined[totallen] = 0;
|
combined[totallen] = 0;
|
||||||
for (i = 0; i < strings; i++)
|
for (i = 0; i < glsl.strings; i++)
|
||||||
{
|
{
|
||||||
memcpy(combined + totallen, prstrings[i], length[i]);
|
memcpy(combined + totallen, glsl.str[i], glsl.len[i]);
|
||||||
totallen += length[i];
|
totallen += glsl.len[i];
|
||||||
combined[totallen] = 0;
|
combined[totallen] = 0;
|
||||||
}
|
}
|
||||||
qglShaderSourceARB(shader, 1, (const GLcharARB**)&combined, NULL);
|
qglShaderSourceARB(shader, 1, (const GLcharARB**)&combined, NULL);
|
||||||
free(combined);
|
free(combined);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
qglShaderSourceARB(shader, strings, prstrings, length);
|
qglShaderSourceARB(shader, glsl.strings, glsl.str, glsl.len);
|
||||||
qglCompileShaderARB(shader);
|
qglCompileShaderARB(shader);
|
||||||
|
|
||||||
return shader;
|
return shader;
|
||||||
|
|
|
@ -13621,7 +13621,7 @@ QCC_def_t *QCC_PR_DummyDef(QCC_type_t *type, const char *name, QCC_function_t *s
|
||||||
}
|
}
|
||||||
else if (type->type == ev_field)
|
else if (type->type == ev_field)
|
||||||
{
|
{
|
||||||
if (type->aux_type->type == ev_vector && !arraysize)
|
if (type->aux_type->type == ev_vector && !arraysize && *def->name != ':')
|
||||||
{
|
{
|
||||||
//do the vector thing.
|
//do the vector thing.
|
||||||
QC_snprintfz(newname, sizeof(newname), "%s_x", def->name);
|
QC_snprintfz(newname, sizeof(newname), "%s_x", def->name);
|
||||||
|
|
|
@ -5625,11 +5625,12 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
|
||||||
d = QCC_PR_GetDef(NULL, membername, NULL, 0, 0, GDF_CONST);
|
d = QCC_PR_GetDef(NULL, membername, NULL, 0, 0, GDF_CONST);
|
||||||
if (!d)
|
if (!d)
|
||||||
{
|
{
|
||||||
d = QCC_PR_GetDef(QCC_PR_FieldType(*basictypes[newparm->type]), membername, NULL, 2, 0, GDF_CONST|GDF_POSTINIT);
|
d = QCC_PR_GetDef(QCC_PR_FieldType(*basictypes[newparm->type]), membername, NULL, 2, 0, GDF_CONST|GDF_POSTINIT|GDF_USED);
|
||||||
// for (i = 0; (unsigned int)i < newparm->size*(arraysize?arraysize:1); i++)
|
// for (i = 0; (unsigned int)i < newparm->size*(arraysize?arraysize:1); i++)
|
||||||
// d->symboldata[i]._int = pr.size_fields+i;
|
// d->symboldata[i]._int = pr.size_fields+i;
|
||||||
// pr.size_fields += i;
|
// pr.size_fields += i;
|
||||||
|
|
||||||
|
d->used = true;
|
||||||
d->referenced = true; //always referenced, so you can inherit safely.
|
d->referenced = true; //always referenced, so you can inherit safely.
|
||||||
}
|
}
|
||||||
if (d->arraysize < basicindex+(arraysize?arraysize:1))
|
if (d->arraysize < basicindex+(arraysize?arraysize:1))
|
||||||
|
@ -5637,7 +5638,17 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
|
||||||
if (d->symboldata)
|
if (d->symboldata)
|
||||||
QCC_PR_ParseError(ERR_INTERNAL, "array members are kinda limited, sorry. try rearranging them or adding padding for alignment\n"); //FIXME: add relocs to cope with this all of a type can then be contiguous and thus allow arrays.
|
QCC_PR_ParseError(ERR_INTERNAL, "array members are kinda limited, sorry. try rearranging them or adding padding for alignment\n"); //FIXME: add relocs to cope with this all of a type can then be contiguous and thus allow arrays.
|
||||||
else
|
else
|
||||||
d->arraysize = basicindex+(arraysize?arraysize:1);
|
{
|
||||||
|
int newsize = basicindex+(arraysize?arraysize:1);
|
||||||
|
if (d->type->type == ev_union || d->type->type == ev_struct)
|
||||||
|
d->arraysize = newsize;
|
||||||
|
else while(d->arraysize < newsize)
|
||||||
|
{
|
||||||
|
QC_snprintfz(membername, sizeof(membername), "::%s[%i]", basictypenames[newparm->type], d->arraysize/d->type->size);
|
||||||
|
QCC_PR_DummyDef(d->type, membername, d->scope, 0, d, d->arraysize, true, GDF_CONST);
|
||||||
|
d->arraysize+=d->type->size;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QCC_FreeDef(d);
|
QCC_FreeDef(d);
|
||||||
|
|
|
@ -604,6 +604,25 @@ void QCC_PrintStrings (void)
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
void QCC_SortFields (void)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
QCC_ddef32_t t;
|
||||||
|
|
||||||
|
// good 'ol bubble sort
|
||||||
|
//(qsort doesn't guarentee ordering)
|
||||||
|
for (i = 0; i < numfielddefs; i++)
|
||||||
|
{
|
||||||
|
for (j = i; j < numfielddefs; j++)
|
||||||
|
if (fields[i].ofs > fields[j].ofs)
|
||||||
|
{
|
||||||
|
t = fields[i];
|
||||||
|
fields[i] = fields[j];
|
||||||
|
fields[j] = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void QCC_PrintFields (void)
|
void QCC_PrintFields (void)
|
||||||
{
|
{
|
||||||
extern char *basictypenames[];
|
extern char *basictypenames[];
|
||||||
|
@ -1855,6 +1874,7 @@ pbool QCC_WriteData (int crc)
|
||||||
printf("code: %s:%i: %s%s%s %s@%i\n", def->filen, def->s_line, dd->type&DEF_SAVEGLOBAL?"save ":"nosave ", dd->type&DEF_SHARED?"shared ":"", basictypenames[dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)], strings+dd->s_name, dd->ofs);
|
printf("code: %s:%i: %s%s%s %s@%i\n", def->filen, def->s_line, dd->type&DEF_SAVEGLOBAL?"save ":"nosave ", dd->type&DEF_SHARED?"shared ":"", basictypenames[dd->type&~(DEF_SHARED|DEF_SAVEGLOBAL)], strings+dd->s_name, dd->ofs);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
QCC_SortFields();
|
||||||
|
|
||||||
if (dupewarncount > 10 && !verbose)
|
if (dupewarncount > 10 && !verbose)
|
||||||
QCC_PR_Note(WARN_NOTREFERENCED, NULL, 0, "suppressed %i more warnings about unreferenced variables, as you clearly don't care about the first 10.", dupewarncount-10);
|
QCC_PR_Note(WARN_NOTREFERENCED, NULL, 0, "suppressed %i more warnings about unreferenced variables, as you clearly don't care about the first 10.", dupewarncount-10);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "quakedef.h"
|
#include "quakedef.h"
|
||||||
#include "pr_common.h"
|
#include "pr_common.h"
|
||||||
|
|
||||||
#ifndef CLIENTONLY
|
#if !defined(CLIENTONLY) && defined(SAVEDGAMES)
|
||||||
|
|
||||||
extern cvar_t skill;
|
extern cvar_t skill;
|
||||||
extern cvar_t deathmatch;
|
extern cvar_t deathmatch;
|
||||||
|
@ -9,7 +9,7 @@ extern cvar_t coop;
|
||||||
extern cvar_t teamplay;
|
extern cvar_t teamplay;
|
||||||
extern cvar_t pr_enable_profiling;
|
extern cvar_t pr_enable_profiling;
|
||||||
|
|
||||||
cvar_t sv_savefmt = CVARFD("sv_savefmt", "1", CVAR_SAVE, "Specifies the format used for the saved game.\n0=legacy.\n1=fte\n2=binary");
|
cvar_t sv_savefmt = CVARFD("sv_savefmt", "", CVAR_SAVE, "Specifies the format used for the saved game.\n0=legacy.\n1=fte\n2=binary");
|
||||||
cvar_t sv_autosave = CVARFD("sv_autosave", "5", CVAR_SAVE, "Interval for autosaves, in minutes. Set to 0 to disable autosave.");
|
cvar_t sv_autosave = CVARFD("sv_autosave", "5", CVAR_SAVE, "Interval for autosaves, in minutes. Set to 0 to disable autosave.");
|
||||||
|
|
||||||
void SV_Savegame_f (void);
|
void SV_Savegame_f (void);
|
||||||
|
@ -78,7 +78,7 @@ void SV_SavegameComment (char *text, size_t textsize)
|
||||||
|
|
||||||
#ifndef QUAKETC
|
#ifndef QUAKETC
|
||||||
//expects the version to have already been parsed
|
//expects the version to have already been parsed
|
||||||
void SV_Loadgame_Legacy(char *filename, vfsfile_t *f, int version)
|
static void SV_Loadgame_Legacy(char *filename, vfsfile_t *f, int version)
|
||||||
{
|
{
|
||||||
//FIXME: Multiplayer save probably won't work with spectators.
|
//FIXME: Multiplayer save probably won't work with spectators.
|
||||||
char mapname[MAX_QPATH];
|
char mapname[MAX_QPATH];
|
||||||
|
@ -394,7 +394,7 @@ static void SV_LegacySavegame (const char *savename)
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf (name, "%s", savename);
|
sprintf (name, "%s", savename);
|
||||||
COM_RequireExtension (name, ".sav", sizeof(name));
|
COM_RequireExtension (name, ".sav", sizeof(name)); //do NOT allow .pak etc
|
||||||
if (!FS_NativePath(name, FS_GAMEONLY, native, sizeof(native)))
|
if (!FS_NativePath(name, FS_GAMEONLY, native, sizeof(native)))
|
||||||
return;
|
return;
|
||||||
Con_TPrintf (U8("Saving game to %s...\n"), native);
|
Con_TPrintf (U8("Saving game to %s...\n"), native);
|
||||||
|
@ -1109,7 +1109,7 @@ void SV_SaveLevelCache(const char *savedir, qboolean dontharmgame)
|
||||||
//FIXME: static entities
|
//FIXME: static entities
|
||||||
//FIXME: midi track
|
//FIXME: midi track
|
||||||
//FIXME: custom temp-ents?
|
//FIXME: custom temp-ents?
|
||||||
//FIXME: pending uri_gets? (if only just to report fails)
|
//FIXME: pending uri_gets? (if only just to report fails on load)
|
||||||
//FIXME: routing calls?
|
//FIXME: routing calls?
|
||||||
//FIXME: sql queries?
|
//FIXME: sql queries?
|
||||||
//FIXME: frik files?
|
//FIXME: frik files?
|
||||||
|
|
|
@ -116,7 +116,9 @@ typedef struct
|
||||||
unsigned int csqcchecksum;
|
unsigned int csqcchecksum;
|
||||||
qboolean mapchangelocked;
|
qboolean mapchangelocked;
|
||||||
|
|
||||||
|
#ifdef SAVEDGAMES
|
||||||
double autosave_time;
|
double autosave_time;
|
||||||
|
#endif
|
||||||
double time;
|
double time;
|
||||||
double starttime;
|
double starttime;
|
||||||
int framenum;
|
int framenum;
|
||||||
|
@ -1572,7 +1574,6 @@ typedef struct
|
||||||
int SV_MVD_GotQTVRequest(vfsfile_t *clientstream, char *headerstart, char *headerend, qtvpendingstate_t *p);
|
int SV_MVD_GotQTVRequest(vfsfile_t *clientstream, char *headerstart, char *headerend, qtvpendingstate_t *p);
|
||||||
|
|
||||||
// savegame.c
|
// savegame.c
|
||||||
void SV_LegacySavegame_f(void);
|
|
||||||
void SV_Savegame_f (void);
|
void SV_Savegame_f (void);
|
||||||
void SV_Savegame_c(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx);
|
void SV_Savegame_c(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx);
|
||||||
void SV_Loadgame_f (void);
|
void SV_Loadgame_f (void);
|
||||||
|
|
|
@ -675,6 +675,7 @@ void SV_Map_f (void)
|
||||||
if (!isrestart)
|
if (!isrestart)
|
||||||
SV_SaveSpawnparms ();
|
SV_SaveSpawnparms ();
|
||||||
|
|
||||||
|
#ifdef SAVEDGAMES
|
||||||
if (newunit)
|
if (newunit)
|
||||||
SV_FlushLevelCache(); //forget all on new unit
|
SV_FlushLevelCache(); //forget all on new unit
|
||||||
else if (startspot && !isrestart && !newunit)
|
else if (startspot && !isrestart && !newunit)
|
||||||
|
@ -698,6 +699,7 @@ void SV_Map_f (void)
|
||||||
#endif
|
#endif
|
||||||
SV_SaveLevelCache(NULL, false);
|
SV_SaveLevelCache(NULL, false);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef Q3SERVER
|
#ifdef Q3SERVER
|
||||||
{
|
{
|
||||||
|
@ -783,7 +785,11 @@ void SV_Map_f (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
SCR_SetLoadingFile("spawnserver");
|
SCR_SetLoadingFile("spawnserver");
|
||||||
if (newunit || !startspot || cinematic || !SV_LoadLevelCache(NULL, level, startspot, false))
|
if (newunit || !startspot || cinematic
|
||||||
|
#ifdef SAVEDGAMES
|
||||||
|
|| !SV_LoadLevelCache(NULL, level, startspot, false)
|
||||||
|
#endif
|
||||||
|
)
|
||||||
{
|
{
|
||||||
if (waschangelevel && !startspot)
|
if (waschangelevel && !startspot)
|
||||||
startspot = "";
|
startspot = "";
|
||||||
|
@ -854,12 +860,13 @@ void SV_Map_f (void)
|
||||||
Cvar_Set(nsv, "");
|
Cvar_Set(nsv, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SAVEDGAMES
|
||||||
if (q2savetos0)
|
if (q2savetos0)
|
||||||
{
|
{
|
||||||
if (sv.state != ss_cinematic) //too weird.
|
if (sv.state != ss_cinematic) //too weird.
|
||||||
SV_Savegame("s0", true);
|
SV_Savegame("s0", true);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (isDedicated)
|
if (isDedicated)
|
||||||
Mod_Purge(MP_MAPCHANGED);
|
Mod_Purge(MP_MAPCHANGED);
|
||||||
|
|
|
@ -650,7 +650,9 @@ void SV_UnspawnServer (void) //terminate the running server.
|
||||||
free(svs.clients);
|
free(svs.clients);
|
||||||
svs.clients = NULL;
|
svs.clients = NULL;
|
||||||
svs.allocated_client_slots = 0;
|
svs.allocated_client_slots = 0;
|
||||||
|
#ifdef SAVEDGAMES
|
||||||
SV_FlushLevelCache();
|
SV_FlushLevelCache();
|
||||||
|
#endif
|
||||||
NET_CloseServer ();
|
NET_CloseServer ();
|
||||||
SV_RunCmdCleanup();
|
SV_RunCmdCleanup();
|
||||||
}
|
}
|
||||||
|
@ -1614,7 +1616,9 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents,
|
||||||
|
|
||||||
if (!startspot)
|
if (!startspot)
|
||||||
{
|
{
|
||||||
|
#ifdef SAVEDGAMES
|
||||||
SV_FlushLevelCache(); //to make sure it's caught
|
SV_FlushLevelCache(); //to make sure it's caught
|
||||||
|
#endif
|
||||||
for (i=0 ; i<sv.allocated_client_slots ; i++)
|
for (i=0 ; i<sv.allocated_client_slots ; i++)
|
||||||
{
|
{
|
||||||
if (svs.clients[i].spawninfo)
|
if (svs.clients[i].spawninfo)
|
||||||
|
@ -1730,7 +1734,9 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents,
|
||||||
SV_SetMoveVars();
|
SV_SetMoveVars();
|
||||||
|
|
||||||
sv.starttime = Sys_DoubleTime() - sv.time;
|
sv.starttime = Sys_DoubleTime() - sv.time;
|
||||||
|
#ifdef SAVEDGAMES
|
||||||
sv.autosave_time = sv.time + sv_autosave.value*60;
|
sv.autosave_time = sv.time + sv_autosave.value*60;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4899,8 +4899,10 @@ float SV_Frame (void)
|
||||||
{
|
{
|
||||||
isidle = false;
|
isidle = false;
|
||||||
|
|
||||||
|
#ifdef SAVEDGAMES
|
||||||
if (sv.time > sv.autosave_time)
|
if (sv.time > sv.autosave_time)
|
||||||
SV_AutoSave();
|
SV_AutoSave();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -5203,10 +5205,9 @@ void SV_InitLocal (void)
|
||||||
|
|
||||||
Cmd_AddCommand ("openroute", SV_OpenRoute_f);
|
Cmd_AddCommand ("openroute", SV_OpenRoute_f);
|
||||||
|
|
||||||
#ifndef NOBUILTINMENUS
|
#ifdef SAVEDGAMES
|
||||||
#ifndef SERVERONLY
|
#if !defined(NOBUILTINMENUS) && !defined(SERVERONLY)
|
||||||
Cvar_Register(&sv_autosave, cvargroup_servercontrol);
|
Cvar_Register(&sv_autosave, cvargroup_servercontrol);
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
Cvar_Register(&sv_savefmt, cvargroup_servercontrol);
|
Cvar_Register(&sv_savefmt, cvargroup_servercontrol);
|
||||||
#ifndef QUAKETC
|
#ifndef QUAKETC
|
||||||
|
@ -5216,6 +5217,7 @@ void SV_InitLocal (void)
|
||||||
Cmd_AddCommandAD ("loadgame", SV_Loadgame_f, SV_Savegame_c, "Loads an existing saved game.");
|
Cmd_AddCommandAD ("loadgame", SV_Loadgame_f, SV_Savegame_c, "Loads an existing saved game.");
|
||||||
Cmd_AddCommandAD ("save", SV_Savegame_f, SV_Savegame_c, "Saves the game to the named location.");
|
Cmd_AddCommandAD ("save", SV_Savegame_f, SV_Savegame_c, "Saves the game to the named location.");
|
||||||
Cmd_AddCommandAD ("load", SV_Loadgame_f, SV_Savegame_c, "Loads an existing saved game.");
|
Cmd_AddCommandAD ("load", SV_Loadgame_f, SV_Savegame_c, "Loads an existing saved game.");
|
||||||
|
#endif
|
||||||
|
|
||||||
SV_MVDInit();
|
SV_MVDInit();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue