diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index d8c62bded..ef7f6c7b9 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -1986,7 +1986,7 @@ void CL_Record_f (void) static int QDECL CompleteDemoList (const char *name, qofs_t flags, time_t mtime, void *parm, searchpathfuncs_t *spath) { struct xcommandargcompletioncb_s *ctx = parm; - ctx->cb(name, ctx); + ctx->cb(name, NULL, NULL, ctx); return true; } void CL_DemoList_c(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx) diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index a51b90da6..e96e64997 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -1233,6 +1233,7 @@ CL_Connect_f ================ */ +void CL_Connect_c(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx); void CL_Connect_f (void) { char *server; @@ -1492,9 +1493,9 @@ void CL_ResetFog(int ftype) memset(&cl.fog[ftype], 0, sizeof(cl.fog[ftype])); cl.fog[ftype].time = realtime; cl.fog[ftype].density = 0; - cl.fog[ftype].colour[0] = 0.3; - cl.fog[ftype].colour[1] = 0.3; - cl.fog[ftype].colour[2] = 0.3; + cl.fog[ftype].colour[0] = //SRGBf(0.3); + cl.fog[ftype].colour[1] = //SRGBf(0.3); + cl.fog[ftype].colour[2] = SRGBf(0.3); cl.fog[ftype].alpha = 1; cl.fog[ftype].depthbias = 0; /* @@ -3962,20 +3963,20 @@ void CL_Fog_f(void) break; case 3: cl.fog[ftype].density = atof(Cmd_Argv(1)); - cl.fog[ftype].colour[0] = cl.fog[ftype].colour[1] = cl.fog[ftype].colour[2] = atof(Cmd_Argv(2)); + cl.fog[ftype].colour[0] = cl.fog[ftype].colour[1] = cl.fog[ftype].colour[2] = SRGBf(atof(Cmd_Argv(2))); break; case 4: cl.fog[ftype].density = 0.05; //make something up for vauge compat with fitzquake, so it doesn't get the default of 0 - cl.fog[ftype].colour[0] = atof(Cmd_Argv(1)); - cl.fog[ftype].colour[1] = atof(Cmd_Argv(2)); - cl.fog[ftype].colour[2] = atof(Cmd_Argv(3)); + cl.fog[ftype].colour[0] = SRGBf(atof(Cmd_Argv(1))); + cl.fog[ftype].colour[1] = SRGBf(atof(Cmd_Argv(2))); + cl.fog[ftype].colour[2] = SRGBf(atof(Cmd_Argv(3))); break; case 5: default: cl.fog[ftype].density = atof(Cmd_Argv(1)); - cl.fog[ftype].colour[0] = atof(Cmd_Argv(2)); - cl.fog[ftype].colour[1] = atof(Cmd_Argv(3)); - cl.fog[ftype].colour[2] = atof(Cmd_Argv(4)); + cl.fog[ftype].colour[0] = SRGBf(atof(Cmd_Argv(2))); + cl.fog[ftype].colour[1] = SRGBf(atof(Cmd_Argv(3))); + cl.fog[ftype].colour[2] = SRGBf(atof(Cmd_Argv(4))); break; } @@ -4357,13 +4358,22 @@ void CL_Init (void) Cmd_AddCommandD ("quit", CL_Quit_f, "Use this command when you get angry. Does not save any cvars. Use cfg_save to save settings, or use the menu for a prompt."); #if defined(CL_MASTER) - Cmd_AddCommandD ("connectbr", CL_ConnectBestRoute_f, "connect address:port\nConnect to a qw server using the best route we can detect."); + Cmd_AddCommandAD ("connectbr", CL_ConnectBestRoute_f, CL_Connect_c, "connect address:port\nConnect to a qw server using the best route we can detect."); #endif - Cmd_AddCommandD ("connect", CL_Connect_f, "connect scheme://address:port\nConnect to a server. " + Cmd_AddCommandAD("connect", CL_Connect_f, CL_Connect_c, "connect scheme://address:port\nConnect to a server. " + #if defined(FTE_TARGET_WEB) - "Use a scheme of ws:// or wss:// to connect via using websockets." -#else + "Use a scheme of rtc[s]://broker/gamename to connect via a webrtc broker." + "Use a scheme of ws[s]://server to connect via websockets." +#elif defined(TCPCONNECT) "Use a scheme of tcp:// or tls:// to connect via non-udp protocols." +// "Use a scheme of ws[s]://server to connect via websockets." +#endif +#ifdef HAVE_DTLS + "Use a scheme of dtls://server to connect securely." +#endif +#if defined(IRCCONNECT) + "Use irc://network:6667/user[@channel] to connect via an irc server. Not recommended." #endif #if defined(NQPROT) || defined(Q2CLIENT) || defined(Q3CLIENT) "\nDefault port is port "STRINGIFY(PORT_DEFAULTSERVER)"." @@ -4383,17 +4393,17 @@ void CL_Init (void) ); Cmd_AddCommandD ("cl_transfer", CL_Transfer_f, "Connect to a different server, disconnecting from the current server only when the new server replies."); #ifdef TCPCONNECT - Cmd_AddCommandD ("tcpconnect", CL_TCPConnect_f, "Connect to a server using the tcp:// prefix"); + Cmd_AddCommandAD ("tcpconnect", CL_TCPConnect_f, CL_Connect_c, "Connect to a server using the tcp:// prefix"); #endif #ifdef IRCCONNECT Cmd_AddCommand ("ircconnect", CL_IRCConnect_f); #endif #ifdef NQPROT - Cmd_AddCommandD ("nqconnect", CLNQ_Connect_f, "Connects to the specified server, defaulting to port "STRINGIFY(PORT_NQSERVER)"."); + Cmd_AddCommandD ("nqconnect", CLNQ_Connect_f, "Connects to the specified server, defaulting to port "STRINGIFY(PORT_NQSERVER)". Otherwise identical to the connect command."); #endif Cmd_AddCommand ("reconnect", CL_Reconnect_f); - Cmd_AddCommand ("join", CL_Join_f); - Cmd_AddCommand ("observe", CL_Observe_f); + Cmd_AddCommandAD ("join", CL_Join_f, CL_Connect_c, "Switches away from spectator mode, optionally connecting to a different server."); + Cmd_AddCommandAD ("observe", CL_Observe_f, CL_Connect_c, "Switches to spectator mode, optionally connecting to a different server."); Cmd_AddCommand ("rcon", CL_Rcon_f); Cmd_AddCommand ("packet", CL_Packet_f); @@ -4405,10 +4415,9 @@ void CL_Init (void) Cmd_AddCommand ("color", CL_Color_f); Cmd_AddCommand ("download", CL_Download_f); - Cmd_AddCommand ("dlsize", CL_DownloadSize_f); - - Cmd_AddCommand ("nextul", CL_NextUpload); - Cmd_AddCommand ("stopul", CL_StopUpload); + Cmd_AddCommandD ("dlsize", CL_DownloadSize_f, "For internal use"); + Cmd_AddCommandD ("nextul", CL_NextUpload, "For internal use"); + Cmd_AddCommandD ("stopul", CL_StopUpload, "For internal use"); Cmd_AddCommand ("skipdl", CL_SkipDownload_f); Cmd_AddCommand ("finishdl", CL_FinishDownload_f); @@ -4427,8 +4436,6 @@ void CL_Init (void) Cmd_AddCommand ("topten", NULL); - Cmd_AddCommandD ("fog", CL_Fog_f, "fog "); - Cmd_AddCommandD ("waterfog", CL_Fog_f, "waterfog "); Cmd_AddCommand ("kill", NULL); Cmd_AddCommand ("pause", NULL); Cmd_AddCommand ("say", CL_Say_f); @@ -4441,6 +4448,8 @@ void CL_Init (void) Cmd_AddCommand ("serverinfo", CL_ServerInfo_f); #endif + Cmd_AddCommandD ("fog", CL_Fog_f, "fog "); + Cmd_AddCommandD ("waterfog", CL_Fog_f, "waterfog "); Cmd_AddCommand ("skygroup", CL_Skygroup_f); // // Windows commands diff --git a/engine/client/cl_master.h b/engine/client/cl_master.h index 8709dfa4e..593e3f4c9 100644 --- a/engine/client/cl_master.h +++ b/engine/client/cl_master.h @@ -31,6 +31,9 @@ enum masterprotocol_e #define SS_KEEPINFO (1<<6u) #define SS_PROXY (1<<7u) +#define PING_DEAD 0xffff //default ping value to denote servers that are not responding. +#define PING_MAX 0xfffe //default ping value to denote servers that are not responding. + //despite not supporting nq or q2, we still load them. We just filter them. This is to make sure we properly write the listing files. enum mastertype_e diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index e26d561ac..79bf8651d 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -1610,6 +1610,21 @@ void CL_RequestNextDownload (void) stage = CL_LoadSounds(stage, true); total_loading_size = stage; cl.contentstage = 0; + + //might be safer to do it later, but kinder to do it before wasting time. + if (!FS_PureOkay()) + { + #ifdef HAVE_MEDIA_ENCODER + if (cls.demoplayback && Media_Capturing()) + { + Con_Printf(CON_ERROR "Aborting capture\n"); + CL_StopPlayback(); + } + #endif + SCR_SetLoadingStage(LS_NONE); + CL_Disconnect(); + return; + } } stage = 0; @@ -8038,9 +8053,9 @@ void CLNQ_ParseServerMessage (void) case svcfitz_fog: CL_ResetFog(0); cl.fog[0].density = MSG_ReadByte()/255.0f; - cl.fog[0].colour[0] = MSG_ReadByte()/255.0f; - cl.fog[0].colour[1] = MSG_ReadByte()/255.0f; - cl.fog[0].colour[2] = MSG_ReadByte()/255.0f; + cl.fog[0].colour[0] = SRGBf(MSG_ReadByte()/255.0f); + cl.fog[0].colour[1] = SRGBf(MSG_ReadByte()/255.0f); + cl.fog[0].colour[2] = SRGBf(MSG_ReadByte()/255.0f); cl.fog[0].time += ((unsigned short)MSG_ReadShort()) / 100.0; cl.fog_locked = !!cl.fog[0].density; break; diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index 52960b2fd..bfee59a9a 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -483,12 +483,14 @@ void CL_CalcCrouch (playerview_t *pv) return; } - //check if we moved in the x/y axis. if we didn't then we're on a moving platform and shouldn't be crouching. -/* VectorMA(pv->oldorigin, pv->oldz-orgz, pv->gravitydir, pv->oldorigin); +/*fixme: this helps lifts with cl_nopred, but seems to harm ramps slightly, might just be my imagination. I guess we need to check last frame too. + //check if we moved in the x/y axis. if we didn't then we're on a vertically moving platform and shouldn't be crouching. + VectorMA(pv->oldorigin, pv->oldz-orgz, pv->gravitydir, pv->oldorigin); VectorSubtract(pv->simorg, pv->oldorigin, delta); if (Length(delta)<0.001) pv->oldz = orgz; */ + VectorCopy (pv->simorg, pv->oldorigin); diff --git a/engine/client/console.c b/engine/client/console.c index 6e1e985da..6a249d3d1 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -65,6 +65,7 @@ cvar_t con_notify_y = CVAR("con_notify_y","0"); cvar_t con_notify_w = CVAR("con_notify_w","1"); cvar_t con_centernotify = CVAR("con_centernotify", "0"); cvar_t con_displaypossibilities = CVAR("con_displaypossibilities", "1"); +cvar_t con_showcompletion = CVAR("con_showcompletion", "1"); cvar_t con_maxlines = CVAR("con_maxlines", "1024"); cvar_t cl_chatmode = CVARD("cl_chatmode", "2", "0(nq) - everything is assumed to be a console command. prefix with 'say', or just use a messagemode bind\n1(q3) - everything is assumed to be chat, unless its prefixed with a /\n2(qw) - anything explicitly recognised as a command will be used as a command, anything unrecognised will be a chat message.\n/ prefix is supported in all cases.\nctrl held when pressing enter always makes any implicit chat into team chat instead."); cvar_t con_numnotifylines_chat = CVAR("con_numnotifylines_chat", "8"); @@ -1293,7 +1294,7 @@ int Con_DrawInput (console_t *con, qboolean focused, int left, int right, int y, i = 0; x = left; - if (con->commandcompletion) + if (con->commandcompletion && con_) { if (cl_chatmode.ival && (text[0] == '/' || (cl_chatmode.ival == 2 && Cmd_IsCommand(text)))) { //color the first token yellow, it's a valid command @@ -1310,7 +1311,7 @@ int Con_DrawInput (console_t *con, qboolean focused, int left, int right, int y, fname = Cmd_CompleteCommand(text+cmdstart, true, true, con_commandmatch, NULL); if (fname && strlen(fname) < 256) //we can compleate it to: { - for (p = min(strlen(fname), key_linepos-cmdstart); fname[p]>' '; p++) + for (p = min(strlen(fname), key_linepos-cmdstart); fname[p]>0; p++) textstart[p+cmdstart] = (unsigned int)fname[p] | (COLOR_GREEN<completionline->length = 0; - for (i = 1; ; i++) + c = Cmd_Complete(text+cmdstart, true); + + for (i = 0; i < c->num; i++) { - cmd = Cmd_CompleteCommand (text+cmdstart, true, true, i, NULL);//&desc); - if (!cmd) - { - if (i <= 2) - con_commandmatch = 0; - break; - } - - if (i == 50) - { - s = (conchar_t*)(con->completionline+1); - end = COM_ParseFunString((COLOR_WHITE<completionline->length, (con->completionline->maxlength-con->completionline->length)*sizeof(maskedtext[0]), true); - con->completionline->length = end - s; - break; - } - s = (conchar_t*)(con->completionline+1); + + cmd = c->completions[i].text; +// desc = c->completions[i].desc; // if (desc) // end = COM_ParseFunString((COLOR_GREEN<completionline->length, (con->completionline->maxlength-con->completionline->length)*sizeof(maskedtext[0]), true); // else end = COM_ParseFunString((COLOR_GREEN<completionline->length, (con->completionline->maxlength-con->completionline->length)*sizeof(maskedtext[0]), true); con->completionline->length = end - s; } + if (c->extra) + { + s = (conchar_t*)(con->completionline+1); + end = COM_ParseFunString((COLOR_WHITE<extra), s+con->completionline->length, (con->completionline->maxlength-con->completionline->length)*sizeof(maskedtext[0]), true); + con->completionline->length = end - s; + } if (con->completionline->length) y = Con_DrawConsoleLines(con, con->completionline, left, right, y, 0, selactive, selsx, selex, selsy, seley, 0); diff --git a/engine/client/keys.c b/engine/client/keys.c index 0ee3f4648..f94113294 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -337,12 +337,11 @@ int PaddedPrint (char *s, int x) } int con_commandmatch; -void CompleteCommand (qboolean force) +void Key_UpdateCompletionDesc(void) { - char *cmd, *s; const char *desc; - - s = key_lines[edit_line]; + cmd_completion_t *c; + const char *s = key_lines[edit_line]; if (*s == ' ' || *s == '\t') s++; if (*s == '\\' || *s == '/') @@ -350,68 +349,20 @@ void CompleteCommand (qboolean force) if (*s == ' ' || *s == '\t') s++; - //check for singular matches and complete if found - cmd = force?NULL:Cmd_CompleteCommand (s, true, true, 2, NULL); - if (!cmd) - { - if (!force) - cmd = Cmd_CompleteCommand (s, false, true, 1, &desc); - else - cmd = Cmd_CompleteCommand (s, true, true, con_commandmatch, &desc); - if (cmd) - { - if (strlen(cmd) < strlen(s)) - return; - - //complete to that (maybe partial) cmd. - Key_ClearTyping(); - Key_ConsoleInsert("/"); - Key_ConsoleInsert(cmd); - s = key_lines[edit_line]+1; - - //if its the only match, add a space ready for arguments. - cmd = Cmd_CompleteCommand (s, true, true, 0, NULL); - if (cmd && !strcmp(s, cmd)) - { - Key_ConsoleInsert(" "); - } - - if (!con_commandmatch) - con_commandmatch = 1; - - if (desc) - Con_Footerf(NULL, false, "%s: %s", cmd, desc); - else - Con_Footerf(NULL, false, ""); - return; - } - } - //complete to a partial match. - cmd = Cmd_CompleteCommand (s, false, true, 0, &desc); - if (cmd) - { - int i = key_lines[edit_line][0] == '/'?1:0; - if (i != 1 || strcmp(key_lines[edit_line]+i, cmd)) - { //if successful, use that instead. - Key_ClearTyping(); - Key_ConsoleInsert("/"); - Key_ConsoleInsert(cmd); - - s = key_lines[edit_line]; //readjust to cope with the insertion of a / - if (*s == '\\' || *s == '/') - s++; - } - } - con_commandmatch++; - cmd = Cmd_CompleteCommand(s, true, true, con_commandmatch, &desc); - if (!cmd) - { + c = Cmd_Complete(s, true); + if (!con_commandmatch || con_commandmatch > c->num) con_commandmatch = 1; - cmd = Cmd_CompleteCommand(s, true, true, con_commandmatch, &desc); - } - if (cmd) + + if (con_commandmatch <= c->num) { - cvar_t *var = Cvar_FindVar(cmd); + const char *cmd; + cvar_t *var; + if (c->completions[con_commandmatch-1].repl) + cmd = c->completions[con_commandmatch-1].repl; + else + cmd = c->completions[con_commandmatch-1].text; + desc = c->completions[con_commandmatch-1].desc; + var = Cvar_FindVar(cmd); if (var) { if (desc) @@ -434,6 +385,88 @@ void CompleteCommand (qboolean force) } } +void CompleteCommand (qboolean force) +{ + const char *cmd, *s; + const char *desc; + cmd_completion_t *c; + + s = key_lines[edit_line]; + if (*s == ' ' || *s == '\t') + s++; + if (*s == '\\' || *s == '/') + s++; + if (*s == ' ' || *s == '\t') + s++; + + //check for singular matches and complete if found + c = Cmd_Complete(s, true); + if (c->num == 1 || force) + { + desc = NULL; + if (!force && c->num != 1) + cmd = c->guessed; + else if (c->num) + { + int idx = max(0, con_commandmatch-1); + if (c->completions[idx].repl) + cmd = c->completions[idx].repl; + else + cmd = c->completions[idx].text; + } + else + cmd = NULL; + if (cmd) + { + if (strlen(cmd) < strlen(s)) + return; + + //complete to that (maybe partial) cmd. + Key_ClearTyping(); + Key_ConsoleInsert("/"); + Key_ConsoleInsert(cmd); + s = key_lines[edit_line]; + if (*s == '/') + s++; + + //if its the only match, add a space ready for arguments. + c = Cmd_Complete(s, true); + cmd = ((c->num >= 1)?(c->completions[0].repl?c->completions[0].repl:c->completions[0].text):NULL); + desc = ((c->num >= 1)?c->completions[0].desc:NULL); + if (c->num == 1) + Key_ConsoleInsert(" "); + + if (!con_commandmatch) + con_commandmatch = 1; + + if (desc) + Con_Footerf(NULL, false, "%s: %s", cmd, desc); + else + Con_Footerf(NULL, false, ""); + return; + } + } + //complete to a partial match. + cmd = c->guessed; + if (cmd) + { + int i = key_lines[edit_line][0] == '/'?1:0; + if (i != 1 || strcmp(key_lines[edit_line]+i, cmd)) + { //if successful, use that instead. + Key_ClearTyping(); + Key_ConsoleInsert("/"); + Key_ConsoleInsert(cmd); + + s = key_lines[edit_line]; //readjust to cope with the insertion of a / + if (*s == '\\' || *s == '/') + s++; + } + } + + con_commandmatch++; + Key_UpdateCompletionDesc(); +} + int Con_Navigate(console_t *con, char *line) { if (con->backshader) @@ -1266,8 +1299,12 @@ qboolean Key_EntryLine(unsigned char **line, int lineoffset, int *linepos, int k memmove((*line)+*linepos-charlen, (*line)+*linepos, strlen((*line)+*linepos)+1); *linepos -= charlen; } - if (!(*line)[lineoffset]) //oops? - con_commandmatch = 0; + + if (con_commandmatch) + { + Con_Footerf(NULL, false, ""); + con_commandmatch = 1; + } return true; } @@ -1579,14 +1616,16 @@ qboolean Key_Console (console_t *con, unsigned int unicode, int key) if (con_commandmatch) { //if that isn't actually a command, and we can actually complete it to something, then lets try to complete it. - char *txt = key_lines[edit_line]+1; + char *txt = key_lines[edit_line]; if (*txt == '/') txt++; - if (!Cmd_IsCommand(txt) && !Cmd_CompleteCommand(txt, true, true, con_commandmatch, NULL)) + if (!Cmd_IsCommand(txt) && Cmd_CompleteCommand(txt, true, true, con_commandmatch, NULL)) { CompleteCommand (true); return true; } + Con_Footerf(con, false, ""); + con_commandmatch = 0; } @@ -1598,7 +1637,6 @@ qboolean Key_Console (console_t *con, unsigned int unicode, int key) history_line = edit_line; } } - con_commandmatch = 0; Z_Free(key_lines[edit_line]); key_lines[edit_line] = BZ_Malloc(1); @@ -1609,7 +1647,7 @@ qboolean Key_Console (console_t *con, unsigned int unicode, int key) if (key == K_SPACE && ctrl && con->commandcompletion) { - char *txt = key_lines[edit_line]+1; + char *txt = key_lines[edit_line]; if (*txt == '/') txt++; if (Cmd_CompleteCommand(txt, true, true, con->commandcompletion, NULL)) @@ -2003,7 +2041,7 @@ void Key_Bind_c(int argn, const char *partial, struct xcommandargcompletioncb_s for (kn=keynames ; kn->name ; kn++) { if (!Q_strncasecmp(partial,kn->name, len)) - ctx->cb(kn->name, ctx); + ctx->cb(kn->name, NULL, NULL, ctx); } } /* diff --git a/engine/client/net_master.c b/engine/client/net_master.c index 1f7ca2740..5b80f0ace 100644 --- a/engine/client/net_master.c +++ b/engine/client/net_master.c @@ -890,8 +890,8 @@ qboolean Master_PassesMasks(serverinfo_t *a) // qboolean enabled; //always filter out dead unresponsive servers. -// if (!(a->status & 1)) -// return false; + if (!(a->status & 1)) + return false; /* switch(a->special & SS_PROTOCOLMASK) { @@ -1309,7 +1309,7 @@ static void Master_FloodRoute(serverinfo_t *node) struct peers_s *peer = node->peers; for (i = 0; i < node->numpeers; i++, peer++) { - if (peer->ping) + if (peer->ping && peer->ping != PING_DEAD) if ((unsigned int)(peer->peer->cost) > (unsigned int)(node->cost + peer->ping)) { //we found a shorter route. flood into it. peer->peer->prevpeer = node; @@ -2305,7 +2305,7 @@ void MasterInfo_ProcessHTTP(struct dl_download *dl) #endif info->refreshtime = 0; - info->ping = 0xffff; + info->ping = PING_DEAD; snprintf(info->name, sizeof(info->name), "%s h", NET_AdrToString(adrbuf, sizeof(adrbuf), &info->adr)); @@ -2406,7 +2406,7 @@ char *jsonnode(int level, char *node) else { info = Z_Malloc(sizeof(serverinfo_t)); - info->ping = 0xffff; + info->ping = PING_DEAD; info->adr = adr; info->sends = 1; info->special = flags; @@ -2644,7 +2644,7 @@ void MasterInfo_Refresh(void) #endif #ifdef NQPROT Master_AddMasterHTTP("http://www.gameaholic.com/servers/qspy-quake", MT_MASTERHTTP, MP_NETQUAKE, "gameaholic's NQ master"); - Master_AddMasterHTTP("http://servers.quakeone.com/index.php?format=json", MT_MASTERHTTPJSON, MP_NETQUAKE, "quakeone's server listing"); +// Master_AddMasterHTTP("http://servers.quakeone.com/index.php?format=json", MT_MASTERHTTPJSON, MP_NETQUAKE, "quakeone's server listing"); Master_AddMaster("255.255.255.255:"STRINGIFY(PORT_NQSERVER), MT_BCAST, MP_NETQUAKE, "Nearby Quake1 servers"); Master_AddMaster("255.255.255.255:"STRINGIFY(PORT_NQSERVER), MT_BCAST, MP_DPMASTER, "Nearby DarkPlaces servers"); #endif @@ -2980,7 +2980,7 @@ int CL_ReadServerInfo(char *msg, enum masterprotocol_e prototype, qboolean favor //server replied from a broadcast message, make sure we ping it to retrieve its actual ping info->sends = 1; - info->ping = 0xffff; //not known + info->ping = PING_DEAD; //not known info->special |= SS_LOCAL; } else @@ -2989,8 +2989,8 @@ int CL_ReadServerInfo(char *msg, enum masterprotocol_e prototype, qboolean favor if (info->refreshtime) { ping = (Sys_DoubleTime() - info->refreshtime)*1000; - if (ping > 0xfffe) - info->ping = 0xfffe; //highest (that is known) + if (ping > PING_MAX) + info->ping = PING_MAX; //highest (that is known) else info->ping = ping; } @@ -3048,7 +3048,7 @@ int CL_ReadServerInfo(char *msg, enum masterprotocol_e prototype, qboolean favor peer->peer->sends = 1; peer->peer->special = SS_QUAKEWORLD; peer->peer->refreshtime = 0; - peer->peer->ping = 0xffff; + peer->peer->ping = PING_DEAD; peer->peer->next = firstserver; snprintf(peer->peer->name, sizeof(peer->peer->name), "%s p", NET_AdrToString(adr, sizeof(adr), &pa)); firstserver = peer->peer; @@ -3427,7 +3427,7 @@ void CL_MasterListParse(netadrtype_t adrtype, int type, qboolean slashpad) default: break; } - info->ping = 0xffff; + info->ping = PING_DEAD; p1 = MSG_ReadByte(); p2 = MSG_ReadByte(); @@ -3463,5 +3463,41 @@ void CL_MasterListParse(netadrtype_t adrtype, int type, qboolean slashpad) firstserver = last; } + + +void CL_Connect_c(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx) +{ + serverinfo_t *info; + char buf[512]; + int len; + if (argn == 1) + { + len = strlen(partial); + if (len > 1 && partial[len-1] == '\"') + len--; + for (info = firstserver; info; info = info->next) + { + if (info->ping != PING_DEAD) + { + if (len && !Q_strncasecmp(partial, info->name, len)) + { + ctx->cb(info->name, va("^[%s^], %i players, %i ping", info->name, info->players, info->ping), NET_AdrToString(buf, sizeof(buf), &info->adr), ctx); + continue; + } + + NET_AdrToString(buf, sizeof(buf), &info->adr); + //there are too many meaningless servers out there, so only suggest IP addresses if those servers are actually significant (ie: active, or favourite) + if (!strncmp(partial, buf, len)) + { + if (info->players || (info->special & SS_FAVORITE) || NET_ClassifyAddress(&info->adr, NULL)<=ASCOPE_LAN || len == strlen(buf)) + { + ctx->cb(buf, va("^[%s^], %i players, %i ping", info->name, info->players, info->ping), NULL, ctx); + continue; + } + } + } + } + } +} #endif diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index 07f0c0c1b..ca6c2557f 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -3683,6 +3683,9 @@ void Surf_LightmapMode(void) } if (cl.worldmodel->deluxdata) rgb = true; + + if (cl.worldmodel->terrain) //the terrain code can't deal with extended lightmap formats. + hdr = false; } if (sh_config.texfmt[PTI_E5BGR9] && hdr) diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index d03b85ba0..ebda88ea2 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -1494,6 +1494,28 @@ void Sys_Register_File_Associations_f(void) { Sys_DoFileAssociations(0); } + +static void QDECL Sys_Priority_Changed(cvar_t *var, char *oldval) +{ + HANDLE h = GetCurrentProcess(); + DWORD pc; + + if (var->ival >= 3) + pc = REALTIME_PRIORITY_CLASS; + else if (var->ival >= 2) + pc = HIGH_PRIORITY_CLASS; + else if (var->ival >= 1) + pc = ABOVE_NORMAL_PRIORITY_CLASS; + else if (var->ival >= 0) + pc = NORMAL_PRIORITY_CLASS; + else if (var->ival >= -1) + pc = BELOW_NORMAL_PRIORITY_CLASS; + else + pc = IDLE_PRIORITY_CLASS; + + SetPriorityClass(h, pc); +} +static cvar_t sys_priority = CVARFCD("sys_highpriority", "0", CVAR_NOTFROMSERVER, Sys_Priority_Changed, "Controls the process priority"); /* ================ Sys_Init @@ -1507,6 +1529,8 @@ void Sys_Init (void) Sys_QueryDesktopParameters(); + Cvar_Register(&sys_priority, "System vars"); + #ifndef SERVERONLY Cvar_Register(&sys_disableWinKeys, "System vars"); Cvar_Register(&sys_disableTaskSwitch, "System vars"); diff --git a/engine/client/valid.c b/engine/client/valid.c index 80570dfe5..ae3cb5523 100644 --- a/engine/client/valid.c +++ b/engine/client/valid.c @@ -391,11 +391,13 @@ rulesetrule_t rulesetrules_strict[] = { {"ruleset_allow_in", "0"}, {"r_projection", "0"}, {"gl_shadeq1_name", "*"}, + {"cl_iDrive", "0"}, {NULL} }; rulesetrule_t rulesetrules_nqr[] = { {"ruleset_allow_larger_models", "0"}, + {"ruleset_allow_watervis", "0"}, /*block seeing through turbs, as well as all our cool graphics stuff. apparently we're not allowed.*/ {"ruleset_allow_overlong_sounds", "0"}, {"ruleset_allow_particle_lightning", "0"}, {"ruleset_allow_packet", "0"}, @@ -411,6 +413,7 @@ rulesetrule_t rulesetrules_nqr[] = { {"ruleset_allow_in", "0"}, {"r_projection", "0"}, {"gl_shadeq1_name", "*"}, + {"cl_iDrive", "0"}, {NULL} }; diff --git a/engine/client/wad.c b/engine/client/wad.c index 9b10b6635..155fe0375 100644 --- a/engine/client/wad.c +++ b/engine/client/wad.c @@ -851,26 +851,26 @@ void Mod_ParseInfoFromEntityLump(model_t *wmodel) //actually, this should be in { cvar_t *var = Cvar_FindVar(key+5); if (var && !(var->flags & CVAR_NOTFROMSERVER)) - Cvar_LockFromServer(var, com_token); + Cvar_LockFromServer(var, token); } else if (!strcmp("wateralpha", key)) //override cvars so mappers don't end up hacking cvars and fucking over configs (at least in other engines). { - Cvar_LockFromServer(&r_wateralpha, com_token); + Cvar_LockFromServer(&r_wateralpha, token); Cvar_LockFromServer(&r_waterstyle, "1"); //force vanilla-style water too. } else if (!strcmp("slimealpha", key)) { - Cvar_LockFromServer(&r_slimealpha, com_token); + Cvar_LockFromServer(&r_slimealpha, token); Cvar_LockFromServer(&r_slimestyle, "1"); } else if (!strcmp("lavaalpha", key)) { - Cvar_LockFromServer(&r_lavaalpha, com_token); + Cvar_LockFromServer(&r_lavaalpha, token); Cvar_LockFromServer(&r_lavastyle, "1"); } else if (!strcmp("telealpha", key)) { - Cvar_LockFromServer(&r_telealpha, com_token); + Cvar_LockFromServer(&r_telealpha, token); Cvar_LockFromServer(&r_telestyle, "1"); } else if (!strcmp("skyname", key)) // for HalfLife maps diff --git a/engine/common/cmd.c b/engine/common/cmd.c index 02809f48a..f6fb7deb0 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -811,7 +811,7 @@ void Cmd_Exec_f (void) static int QDECL CompleteExecList (const char *name, qofs_t flags, time_t mtime, void *parm, searchpathfuncs_t *spath) { struct xcommandargcompletioncb_s *ctx = parm; - ctx->cb(name, ctx); + ctx->cb(name, NULL, NULL, ctx); return true; } void Cmd_Exec_c(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx) @@ -868,7 +868,7 @@ static void Key_Alias_c(int argn, const char *partial, struct xcommandargcomplet for (a = cmd_alias ; a ; a=a->next) { if (!Q_strncasecmp(partial,a->name, len)) - ctx->cb(a->name, ctx); + ctx->cb(a->name, a->value, NULL, ctx); } } static void Cmd_ShowAlias_f (void) @@ -2183,107 +2183,193 @@ const char *Cmd_Describe (const char *cmd_name) Cmd_CompleteCommand ============ */ -typedef struct { - int matchnum; - qboolean allowcutdown; - qboolean cutdown; - char result[256]; - const char *desc; -} match_t; -void Cmd_CompleteCheck(const char *check, match_t *match, const char *desc) //compare cumulative strings and join the result -{ - if (*match->result) - { - char *r; - if (match->allowcutdown) - { - for(r = match->result; *r == *check && *r; r++, check++) - ; - *r = '\0'; - match->cutdown = true; - if (match->matchnum > 0) - match->matchnum--; - } - else if (match->matchnum > 0) - { - strcpy(match->result, check); - match->desc = desc; - match->matchnum--; - } - } - else - { - if (match->matchnum > 0) - match->matchnum--; - strcpy(match->result, check); - match->desc = desc; - } -} -struct cmdargcompletionctx_s + + +struct cmdargcompletion_ctx_s { struct xcommandargcompletioncb_s cb; cmd_function_t *cmd; const char *prefix; size_t prefixlen; - match_t *match; + qboolean quoted; + cmd_completion_t *res; const char *desc; }; -void Cmd_CompleteCheckArg(const char *value, struct xcommandargcompletioncb_s *vctx) //compare cumulative strings and join the result +static fte_inline int Q_tolower(char c) { - struct cmdargcompletionctx_s *ctx = (struct cmdargcompletionctx_s*)vctx; - match_t *match = ctx->match; - const char *desc = ctx->desc; + if (c >= 'a' && c <= 'z') + c -= ('a' - 'A'); + return c; +} +void Cmd_Complete_CheckArg(const char *value, const char *desc, const char *repl, struct xcommandargcompletioncb_s *vctx) //compare cumulative strings and join the result +{ + struct cmdargcompletion_ctx_s *ctx = (struct cmdargcompletion_ctx_s*)vctx; + cmd_completion_t *res = ctx->res; + char *text; - if (ctx->prefixlen >= countof(match->result)-1) - return; //don't allow overflows. + const char *c; + char *p; + char quoted[8192]; - if (*match->result) + if (!desc) //if no arg desc, use the command's. + desc = ctx->desc; + + if (strchr(value, ' ') || strchr(value, '\t') || strchr(value, '\"') || strchr(value, '\r') || strchr(value, '\n')) { - char *r; - const char *check; - if (match->allowcutdown) - { - for(r = match->result, check=ctx->prefix; check < ctx->prefix+ctx->prefixlen && *r == *check && *r; r++, check++) - ; - if (check == ctx->prefix+ctx->prefixlen) - { - for(check=value; *r == *check && *r; r++, check++) - ; - } - *r = '\0'; - match->cutdown = true; - if (match->matchnum > 0) - match->matchnum--; - } - else if (match->matchnum > 0) - { - memcpy(match->result, ctx->prefix, ctx->prefixlen); - Q_strncpyz(match->result+ctx->prefixlen, value, sizeof(match->result)-ctx->prefixlen); - match->desc = desc; - match->matchnum--; - } + if (/*ctx->prefix[ctx->prefixlen] &&*/ !ctx->quoted) //FIXME... Figure out some way to insert quotes earlier in the completion without it bugging out + return; + } + + if (ctx->quoted) + { + value = COM_QuotedString(value, quoted, sizeof(quoted), false); + value++; + } + + if (!res->guessed) + { + text = BZ_Malloc(ctx->prefixlen + strlen(value) + 1); + memcpy(text, ctx->prefix, ctx->prefixlen); + strcpy(text+ctx->prefixlen, value); + res->guessed = text; } else { - if (match->matchnum > 0) - match->matchnum--; - memcpy(match->result, ctx->prefix, ctx->prefixlen); - Q_strncpyz(match->result+ctx->prefixlen, value, sizeof(match->result)-ctx->prefixlen); - match->desc = desc; + for (p = res->guessed, c = ctx->prefix; *p && c < ctx->prefix+ctx->prefixlen; p++, c++) + { + if (Q_tolower(*p) != Q_tolower(*c)) + { + *p = 0; + break; + } + } + if (c == ctx->prefix+ctx->prefixlen) + for (c = value; *p; p++, c++) + { + if (Q_tolower(*p) != Q_tolower(*c)) + { + *p = 0; + break; + } + if (!*c) + break; + } } + + + if (res->num == countof(res->completions)) + { + res->extra++; + return; //no more space for more options + } + + text = BZ_Malloc(ctx->prefixlen + strlen(value) + 1); + memcpy(text, ctx->prefix, ctx->prefixlen); + strcpy(text+ctx->prefixlen, value); + + if (repl) + { + p = BZ_Malloc(ctx->prefixlen + strlen(repl) + 2); + memcpy(p, ctx->prefix, ctx->prefixlen); + strcpy(p+ctx->prefixlen, repl); + if (value == quoted+1) + Q_strcat(p, "\""); + repl = p; + } + + res->completions[res->num].text_alloced = true; + res->completions[res->num].text = text; + res->completions[res->num].desc_alloced = true; + res->completions[res->num].desc = Z_StrDup(desc); + res->completions[res->num].repl = repl; + res->num++; } -char *Cmd_CompleteCommand (const char *partial, qboolean fullonly, qboolean caseinsens, int matchnum, const char **descptr) + +void Cmd_Complete_Check(const char *check, cmd_completion_t *res, const char *desc) //compare cumulative strings and join the result +{ + const char *c; + char *p; + if (!res->guessed) + res->guessed = Z_StrDup(check); + else for (p = res->guessed, c = check; *p; p++, c++) + { //we need to do this stuff here because we're not always tracking all of them. + if (Q_tolower(*p) != Q_tolower(*c)) + { + *p = 0; + break; + } + + if (!*c) + break; + } + + if (res->num == countof(res->completions)) + { + res->extra++; + return; //no more space for more options + } + + res->completions[res->num].text_alloced = false; + res->completions[res->num].text = check; + res->completions[res->num].desc_alloced = false; + res->completions[res->num].desc = desc; + res->completions[res->num].repl = NULL; + res->num++; +} +void Cmd_Complete_End(cmd_completion_t *c) +{ + size_t u; + for (u = 0; u < c->num; u++) + { + if (c->completions[u].text_alloced) + Z_Free((char*)c->completions[u].text); + c->completions[u].text_alloced = false; + c->completions[u].text = NULL; + + if (c->completions[u].desc_alloced) + Z_Free((char*)c->completions[u].desc); + c->completions[u].desc_alloced = false; + c->completions[u].desc = NULL; + + c->completions[u].repl = NULL; + } + c->num = 0; + c->extra = 0; + Z_Free(c->guessed); + c->guessed = NULL; + Z_Free(c->partial); + c->partial = NULL; +} +int QDECL Cmd_Complete_Sort(const void *a, const void *b) +{ //FIXME: its possible that they're equal (eg: filesystem searches). we should strip one in that case, but gah. + const struct cmd_completion_opt_s *c1 = a, *c2 = b; + return strcmp(c1->text, c2->text); +} +cmd_completion_t *Cmd_Complete(const char *partial, qboolean caseinsens) { extern cvar_group_t *cvar_groups; cmd_function_t *cmd; int len; cmdalias_t *a; - static match_t match; - cvar_group_t *grp; cvar_t *cvar; const char *sp; + qboolean quoted = false; + + static cmd_completion_t c; + + if (!partial) + { + Cmd_Complete_End(&c); + return NULL; + } + + if ((c.partial && !strcmp(partial, c.partial)) && c.caseinsens == caseinsens) + return &c; //still valid. + Cmd_Complete_End(&c); + c.partial = Z_StrDup(partial); + c.caseinsens = caseinsens; for (sp = partial; *sp; sp++) { @@ -2295,89 +2381,118 @@ char *Cmd_CompleteCommand (const char *partial, qboolean fullonly, qboolean case { while (*sp == ' ' || *sp == '\t') sp++; + //try to handle quotes + if (*sp == '\\' && sp[1] == '\"') + { + sp+=2; + quoted = true; + } + else if (*sp == '\"') + { + sp++; + quoted = true; + } } else sp = NULL; - if (descptr) - *descptr = NULL; - - if (!len) - return NULL; - - if (matchnum == -1) - len++; - - match.allowcutdown = !fullonly?true:false; - match.cutdown = false; - match.desc = NULL; - if (matchnum) - match.matchnum = matchnum; - else - match.matchnum = 0; - - strcpy(match.result, ""); - - // check for partial match - if (caseinsens) + if (len) { - for (cmd=cmd_functions ; cmd ; cmd=cmd->next) - if (!Q_strncasecmp (partial,cmd->name, len) && (matchnum == -1 || !partial[len] || strlen(cmd->name) == len)) - { - if (sp && cmd->argcompletion) + if (caseinsens) + { + for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + if (!Q_strncasecmp (partial,cmd->name, len) && (!partial[len] || strlen(cmd->name) == len)) { - struct cmdargcompletionctx_s ctx; - ctx.cb.cb = Cmd_CompleteCheckArg; - ctx.cmd = cmd; - ctx.prefix = partial; - ctx.prefixlen = sp-partial; - ctx.match = &match; - ctx.desc = cmd->description; - cmd->argcompletion(1, sp, &ctx.cb); + if (sp && cmd->argcompletion) + { + struct cmdargcompletion_ctx_s ctx; + ctx.cb.cb = Cmd_Complete_CheckArg; + ctx.cmd = cmd; + ctx.prefix = partial; + ctx.prefixlen = sp-partial; + ctx.res = &c; + ctx.desc = cmd->description; + ctx.quoted = quoted; + cmd->argcompletion(1, sp, &ctx.cb); + } + else + Cmd_Complete_Check(cmd->name, &c, cmd->description); } - else - Cmd_CompleteCheck(cmd->name, &match, cmd->description); + for (a=cmd_alias ; a ; a=a->next) + if (!Q_strncasecmp (partial, a->name, len) && (!partial[len] || strlen(a->name) == len)) + Cmd_Complete_Check(a->name, &c, a->value); + for (grp=cvar_groups ; grp ; grp=grp->next) + for (cvar=grp->cvars ; cvar ; cvar=cvar->next) + { + if (!Q_strncasecmp (partial,cvar->name, len) && (!partial[len] || strlen(cvar->name) == len)) + Cmd_Complete_Check(cvar->name, &c, cvar->description); + if (cvar->name2 && !Q_strncasecmp (partial,cvar->name2, len) && (!partial[len] || strlen(cvar->name2) == len)) + Cmd_Complete_Check(cvar->name2, &c, cvar->description); } - for (a=cmd_alias ; a ; a=a->next) - if (!Q_strncasecmp (partial, a->name, len) && (matchnum == -1 || !partial[len] || strlen(a->name) == len)) - Cmd_CompleteCheck(a->name, &match, a->value); - for (grp=cvar_groups ; grp ; grp=grp->next) - for (cvar=grp->cvars ; cvar ; cvar=cvar->next) - { - if (!Q_strncasecmp (partial,cvar->name, len) && (matchnum == -1 || !partial[len] || strlen(cvar->name) == len)) - Cmd_CompleteCheck(cvar->name, &match, cvar->description); - if (cvar->name2 && !Q_strncasecmp (partial,cvar->name2, len) && (matchnum == -1 || !partial[len] || strlen(cvar->name2) == len)) - Cmd_CompleteCheck(cvar->name2, &match, cvar->description); - } + } + else + { + for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + if (!Q_strncmp (partial,cmd->name, len) && (!partial[len] || strlen(cmd->name) == len)) + Cmd_Complete_Check(cmd->name, &c, cmd->description); + for (a=cmd_alias ; a ; a=a->next) + if (!Q_strncmp (partial, a->name, len) && (!partial[len] || strlen(a->name) == len)) + Cmd_Complete_Check(a->name, &c, ""); + for (grp=cvar_groups ; grp ; grp=grp->next) + for (cvar=grp->cvars ; cvar ; cvar=cvar->next) + { + if (!Q_strncmp (partial,cvar->name, len) && (!partial[len] || strlen(cvar->name) == len)) + Cmd_Complete_Check(cvar->name, &c, cvar->description); + if (cvar->name2 && !Q_strncmp (partial,cvar->name2, len) && (!partial[len] || strlen(cvar->name2) == len)) + Cmd_Complete_Check(cvar->name2, &c, cvar->description); + } + } + } + + //quickly sort the completions. this is primarily so that the first item is the shortest, but whatever. + qsort(c.completions, c.num, sizeof(c.completions[0]), Cmd_Complete_Sort); + return &c; +} + +char *Cmd_CompleteCommand (const char *partial, qboolean fullonly, qboolean caseinsens, int matchnum, const char **descptr) +{ + cmd_completion_t *c = Cmd_Complete(partial, caseinsens); + const char *text = NULL, *desc = NULL; + + if (matchnum < 0) + { //completes only if there's an EXACT match. + for (matchnum = 0; matchnum < c->num; matchnum++) + { + if (!strcmp(partial, c->completions[matchnum].text)) + { + text = c->completions[matchnum].text; + desc = c->completions[matchnum].desc; + break; + } + } + } + else if (!matchnum) + { //returns the longest-common-denominator of all the matches + text = c->guessed; + desc = ((c->num==1)?c->completions[matchnum].desc:NULL); } else { - for (cmd=cmd_functions ; cmd ; cmd=cmd->next) - if (!Q_strncmp (partial,cmd->name, len) && (matchnum == -1 || !partial[len] || strlen(cmd->name) == len)) - Cmd_CompleteCheck(cmd->name, &match, cmd->description); - for (a=cmd_alias ; a ; a=a->next) - if (!Q_strncmp (partial, a->name, len) && (matchnum == -1 || !partial[len] || strlen(a->name) == len)) - Cmd_CompleteCheck(a->name, &match, ""); - for (grp=cvar_groups ; grp ; grp=grp->next) - for (cvar=grp->cvars ; cvar ; cvar=cvar->next) + matchnum--; + if (matchnum < c->num) { - if (!Q_strncmp (partial,cvar->name, len) && (matchnum == -1 || !partial[len] || strlen(cvar->name) == len)) - Cmd_CompleteCheck(cvar->name, &match, cvar->description); - if (cvar->name2 && !Q_strncmp (partial,cvar->name2, len) && (matchnum == -1 || !partial[len] || strlen(cvar->name2) == len)) - Cmd_CompleteCheck(cvar->name2, &match, cvar->description); + text = c->completions[matchnum].text; + desc = c->completions[matchnum].desc; } } - if (match.matchnum>0) - return NULL; - if (!*match.result) - return NULL; if (descptr) - *descptr = match.desc; - return match.result; + *descptr = desc; + return (char*)text; } + //lists commands, also prints restriction level void Cmd_List_f (void) { diff --git a/engine/common/cmd.h b/engine/common/cmd.h index c4e37bef1..8fef7576b 100644 --- a/engine/common/cmd.h +++ b/engine/common/cmd.h @@ -73,7 +73,8 @@ then searches for a command or variable that matches the first token. typedef void (*xcommand_t) (void); struct xcommandargcompletioncb_s { - void(*cb)(const char *arg, struct xcommandargcompletioncb_s *ctx); + //if repl is specified, then that is the text that will be used if this is the sole autocomplete, to complete using strings that are not actually valid. + void(*cb)(const char *arg, const char *desc, const char *repl, struct xcommandargcompletioncb_s *ctx); //private stuff follows. }; typedef void (*xcommandargcompletion_t)(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx); @@ -102,6 +103,23 @@ char *Cmd_AliasExist(const char *name, int restrictionlevel); const char *Cmd_Describe (const char *cmd_name); +typedef struct +{ + char *guessed; //this is the COMPLETED partial. + char *partial; //the requested string that we completed + qboolean caseinsens; + size_t num, extra; //valid count, and ommitted count (if we were too lazy to find more) + struct cmd_completion_opt_s { + qboolean text_alloced:1; + qboolean desc_alloced:1; + const char *text; + const char *repl; //used for sole matches + const char *desc; + } completions[50]; +} cmd_completion_t; +cmd_completion_t *Cmd_Complete(const char *partial, qboolean caseinsens); //calculates and caches info. + +//these should probably be removed some time char *Cmd_CompleteCommand (const char *partial, qboolean fullonly, qboolean caseinsens, int matchnum, const char **descptr); qboolean Cmd_IsCommand (const char *line); // attempts to match a partial command for automatic command line completion diff --git a/engine/common/common.c b/engine/common/common.c index 8cef62396..566a7ee76 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -480,6 +480,12 @@ char *Q_strlwr(char *s) return ret; } +static char fte_inline Q_tolower(char c) +{ + if (c >= 'A' && c <= 'Z') + return c-'A'+'a'; + return c; +} int wildcmp(const char *wild, const char *string) { /* @@ -507,7 +513,7 @@ int wildcmp(const char *wild, const char *string) return true; string++; } - else if ((*wild == *string) || (*wild == '?')) + else if ((Q_tolower(*wild) == Q_tolower(*string)) || (*wild == '?')) { //this char matches wild++; diff --git a/engine/common/common.h b/engine/common/common.h index bac2dcd15..20931eb52 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -611,6 +611,7 @@ void FS_UnloadPackFiles(void); void FS_ReloadPackFiles(void); char *FSQ3_GenerateClientPacksList(char *buffer, int maxlen, int basechecksum); void FS_PureMode(int mode, char *purenamelist, char *purecrclist, char *refnamelist, char *refcrclist, int seed); //implies an fs_restart. ref package names are optional, for q3 where pure names don't contain usable paths +qboolean FS_PureOkay(void); //recursively tries to open files until it can get a zip. vfsfile_t *CL_OpenFileInPackage(searchpathfuncs_t *search, char *name); diff --git a/engine/common/fs.c b/engine/common/fs.c index 067da7198..b65274ce5 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -3524,6 +3524,79 @@ void FS_PureMode(int puremode, char *purenamelist, char *purecrclist, char *refn } } +qboolean FS_PureOkay(void) +{ + //returns true if all pure packages that we're meant to need could load. + //if they couldn't then they won't override things, or the game will just be completely screwed due to having absolutely no game data + if (fs_puremode == 1 && fs_purenames && *fs_purenames && fs_purecrcs && *fs_purecrcs) + { + char crctok[64]; + char nametok[MAX_QPATH]; + char nametok2[MAX_QPATH]; + searchpath_t *sp = com_purepaths; + char *names = fs_purenames, *pname; + char *crcs = fs_purecrcs; + int crc; + qboolean required; + + while(names && crcs) + { + crcs = COM_ParseOut(crcs, crctok, sizeof(crctok)); + names = COM_ParseOut(names, nametok, sizeof(nametok)); + + crc = strtoul(crctok, NULL, 0); + if (!crc) + continue; + + pname = nametok; + + if (fs_refnames && fs_refcrcs) + { //q3 is annoying as hell + int crc2; + char *rc = fs_refcrcs; + char *rn = fs_refnames; + pname = ""; + for (; rc && rn; ) + { + rc = COM_ParseOut(rc, crctok, sizeof(crctok)); + rn = COM_ParseOut(rn, nametok2, sizeof(nametok2)); + crc2 = strtoul(crctok, NULL, 0); + if (crc2 == crc) + { + COM_DefaultExtension(nametok2, ".pk3", sizeof(nametok2)); + pname = nametok2; + break; + } + } + } + required = *pname == '*'; + if (*pname == '*') // * means that its 'referenced' (read: actually useful) thus should be downloaded, which is not relevent here. + { + required = true; + pname++; + } + else + required = false; + + if (sp && sp->crc_check == crc) + { + sp = sp->nextpure; + continue; + } + else if (!required) //if its not referenced, then its not needed, and we probably didn't bother to download it. this might be an issue with sv_pure 1, but that has its own issues. + continue; + else //if (!sp) + { + Con_Printf("Pure package %s:%i missing\n", pname, crc); + return false; + } + } + return true; + } + + return true; +} + char *FSQ3_GenerateClientPacksList(char *buffer, int maxlen, int basechecksum) { //this is for q3 compatibility. @@ -3854,7 +3927,7 @@ void FS_ReloadPackFilesFlags(unsigned int reloadflags) } if (!sp) - Con_DPrintf("Pure crc %i wasn't found\n", crc); + Con_DPrintf("Pure package %s:%i wasn't found\n", pname, crc); } } } diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index f6ecdc537..d95a57cd6 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -1168,7 +1168,6 @@ size_t NET_StringToAdr2 (const char *s, int defaultport, netadr_t *a, size_t num if (!strncmp (s, "tcp://", 6)) { //make sure that the rest of the address is a valid ip address (4 or 6) - if (!NET_StringToSockaddr (s+6, defaultport, &sadr[0], NULL, NULL)) { a->type = NA_INVALID; @@ -1182,7 +1181,6 @@ size_t NET_StringToAdr2 (const char *s, int defaultport, netadr_t *a, size_t num if (!strncmp (s, "ws://", 5)) { //make sure that the rest of the address is a valid ip address (4 or 6) - if (!NET_StringToSockaddr (s+5, defaultport, &sadr[0], NULL, NULL)) { a->type = NA_INVALID; @@ -1195,8 +1193,10 @@ size_t NET_StringToAdr2 (const char *s, int defaultport, netadr_t *a, size_t num } if (!strncmp (s, "wss://", 6)) { +#ifndef HAVE_SSL + return false; +#else //make sure that the rest of the address is a valid ip address (4 or 6) - if (!NET_StringToSockaddr (s+6, defaultport, &sadr[0], NULL, NULL)) { a->type = NA_INVALID; @@ -1206,29 +1206,14 @@ size_t NET_StringToAdr2 (const char *s, int defaultport, netadr_t *a, size_t num SockadrToNetadr (&sadr[0], a); a->prot = NP_WSS; return true; - } - if (!strncmp (s, "dtls://", 7)) - { -#ifdef HAVE_DTLS - //make sure that the rest of the address is a valid ip address (4 or 6) - - if (!NET_StringToSockaddr (s+7, defaultport, &sadr[0], NULL, NULL)) - { - a->type = NA_INVALID; - return false; - } - - SockadrToNetadr (&sadr[0], a); - a->prot = NP_DTLS; - return true; -#else - return false; #endif } if (!strncmp (s, "tls://", 6)) { +#ifndef HAVE_SSL + return false; +#else //make sure that the rest of the address is a valid ip address (4 or 6) - if (!NET_StringToSockaddr (s+6, defaultport, &sadr[0], NULL, NULL)) { a->type = NA_INVALID; @@ -1238,8 +1223,26 @@ size_t NET_StringToAdr2 (const char *s, int defaultport, netadr_t *a, size_t num SockadrToNetadr (&sadr[0], a); a->prot = NP_TLS; return true; +#endif } #endif + if (!strncmp (s, "dtls://", 7)) + { +#ifndef HAVE_DTLS + return false; +#else + //make sure that the rest of the address is a valid ip address (4 or 6) + if (!NET_StringToSockaddr (s+7, defaultport, &sadr[0], NULL, NULL)) + { + a->type = NA_INVALID; + return false; + } + + SockadrToNetadr (&sadr[0], a); + a->prot = NP_DTLS; + return true; +#endif + } #ifdef IRCCONNECT if (!strncmp (s, "irc://", 6)) { diff --git a/engine/common/pmove.c b/engine/common/pmove.c index f029eec3a..cacfbc78c 100644 --- a/engine/common/pmove.c +++ b/engine/common/pmove.c @@ -1132,9 +1132,11 @@ PM_CheckWaterJump */ void PM_CheckWaterJump (void) { - vec3_t spot; - int cont; + vec3_t spot, spot2; +// int cont; vec3_t flatforward; + trace_t tr; + vec3_t oldmin, oldmax; if (pmove.waterjumptime>0) return; @@ -1151,6 +1153,37 @@ void PM_CheckWaterJump (void) flatforward[2] = 0; VectorNormalize (flatforward); +#if 1 //NQ does a traceline, which gives more permissive results. This is required for various maps that have awkward water jumps. + VectorCopy(pmove.player_mins, oldmin); + VectorCopy(pmove.player_maxs, oldmax); + VectorCopy(pmove.origin, spot); + spot[2] += 8 + 24+pmove.player_mins[2]; //hexen2 fix. calculated from the normal bottom of bbox + VectorMA (spot, 24, flatforward, spot2); + tr = PM_TraceLine(spot, spot2); + VectorCopy(oldmin, pmove.player_mins); + VectorCopy(oldmax, pmove.player_maxs); + if (tr.fraction == 1) //(possibly) give up if open at waist + { //NQ bug workaround: NQ does waterjump checks inside prethink, and THEN sets waterlevel after. + //The player then moves to where waterlevel SHOULD be 3, except you're still allowed to waterjump because of last frame. + //Which is horrible buggy framerate-dependant behaviour... + //so lets just try again 2qu up. + //This'll cause slight prediction issues with other qw engines, and maybe some newly bugged maps, but those maps were probably already buggy with a low enough nq framerate. + spot[2] += 2; + spot2[2] += 2; + tr = PM_TraceLine(spot, spot2); + VectorCopy(oldmin, pmove.player_mins); + VectorCopy(oldmax, pmove.player_maxs); + if (tr.fraction == 1) //give up if open at waist + return; + } + spot[2] += 24; + spot2[2] += 24; + tr = PM_TraceLine(spot, spot2); + VectorCopy(oldmin, pmove.player_mins); + VectorCopy(oldmax, pmove.player_maxs); + if (tr.fraction < 1) //give up if blocked at eye + return; +#else VectorMA (pmove.origin, 24, flatforward, spot); spot[2] += 8 + 24+pmove.player_mins[2]; //hexen2 fix. calculated from the normal bottom of bbox cont = PM_PointContents (spot); @@ -1160,6 +1193,7 @@ void PM_CheckWaterJump (void) cont = PM_PointContents (spot); if (cont != FTECONTENTS_EMPTY) return; +#endif // jump out of water VectorScale (flatforward, 50, pmove.velocity); pmove.velocity[2] = 310; diff --git a/engine/d3d/d3d_backend.c b/engine/d3d/d3d_backend.c index 15076441d..a4ff89c70 100644 --- a/engine/d3d/d3d_backend.c +++ b/engine/d3d/d3d_backend.c @@ -818,7 +818,7 @@ static void SelectPassTexture(unsigned int tu, shaderpass_t *pass) { default: case T_GEN_DIFFUSE: - if (shaderstate.curtexnums->base) + if (TEXLOADED(shaderstate.curtexnums->base)) BindTexture(tu, shaderstate.curtexnums->base); else BindTexture(tu, missing_texture); @@ -2049,6 +2049,13 @@ static void BE_ApplyUniforms(program_t *prog, int permu) IDirect3DDevice9_SetVertexShaderConstantF(pD3DDev9, h, mvp, 4); } break; + case SP_M_MODELVIEW: + { + float mv[16]; + Matrix4_Multiply(r_refdef.m_view, shaderstate.m_model, mv); + IDirect3DDevice9_SetVertexShaderConstantF(pD3DDev9, h, mv, 4); + } + break; case SP_LIGHTPOSITION: { @@ -2130,7 +2137,6 @@ static void BE_ApplyUniforms(program_t *prog, int permu) break; case SP_M_ENTBONES: - case SP_M_MODELVIEW: case SP_E_VLSCALE: case SP_E_ORIGIN: case SP_E_GLOWMOD: @@ -2177,9 +2183,9 @@ static void BE_RenderMeshProgram(shader_t *s, unsigned int vertbase, unsigned in return; } #endif - if (TEXVALID(shaderstate.curtexnums->bump) && p->permu[perm|PERMUTATION_BUMPMAP].h.loaded) + if (TEXLOADED(shaderstate.curtexnums->bump) && p->permu[perm|PERMUTATION_BUMPMAP].h.loaded) perm |= PERMUTATION_BUMPMAP; - if (TEXVALID(shaderstate.curtexnums->fullbright) && p->permu[perm|PERMUTATION_FULLBRIGHT].h.loaded) + if (TEXLOADED(shaderstate.curtexnums->fullbright) && p->permu[perm|PERMUTATION_FULLBRIGHT].h.loaded) perm |= PERMUTATION_FULLBRIGHT; if (p->permu[perm|PERMUTATION_UPPERLOWER].h.loaded && (TEXLOADED(shaderstate.curtexnums->upperoverlay) || TEXLOADED(shaderstate.curtexnums->loweroverlay))) perm |= PERMUTATION_UPPERLOWER; diff --git a/engine/d3d/d3d_image.c b/engine/d3d/d3d_image.c index 3846dea16..671c8c849 100644 --- a/engine/d3d/d3d_image.c +++ b/engine/d3d/d3d_image.c @@ -146,16 +146,29 @@ qboolean D3D9_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mip else if (mips->type == PTI_2D) { IDirect3DTexture9 *dt; - if (FAILED(IDirect3DDevice9_CreateTexture(pD3DDev9, mips->mip[0].width, mips->mip[0].height, mips->mipcount, 0, fmt, D3DPOOL_MANAGED, &dt, NULL))) + int mipcount = mips->mipcount; + for (i = 1; i < mipcount; i++) + { //OpenGL and Direct3D have different interpretations of mipmap sizes. + //OpenGL rounds up, direct3D rounds down. (d3d:3->1, gl:3->2) + //so if the mips are incompatible, just drop the smaller ones. + if (mips->mip[i].width != max(1,(mips->mip[i-1].width)>>1) || + mips->mip[i].height != max(1,(mips->mip[i-1].height)>>1)) + { + mipcount = i; + break; + } + } + + if (FAILED(IDirect3DDevice9_CreateTexture(pD3DDev9, mips->mip[0].width, mips->mip[0].height, mipcount, 0, fmt, D3DPOOL_MANAGED, &dt, NULL))) return false; dbt = (IDirect3DBaseTexture9*)dt; - for (i = 0; i < mips->mipcount; i++) + for (i = 0; i < mipcount; i++) { IDirect3DTexture9_GetLevelDesc(dt, i, &desc); if (mips->mip[i].height != desc.Height || mips->mip[i].width != desc.Width) - { + { //we got the above mipcount clamping wrong! IDirect3DTexture9_Release(dt); return false; } diff --git a/engine/d3d/d3d_shader.c b/engine/d3d/d3d_shader.c index 046e1231f..f34439085 100644 --- a/engine/d3d/d3d_shader.c +++ b/engine/d3d/d3d_shader.c @@ -180,7 +180,7 @@ static HRESULT STDMETHODCALLTYPE myID3DXIncludeVtbl_Open(myID3DXInclude *cls, D3 "float3 fog3(float3 regularcolour, float distance)" "{" - "float z = w_fogdensity * -distance;\n" + "float z = w_fogdensity * distance;\n" "z = max(0.0,z-w_fogdepthbias);\n" "if (r_fog_exp2)\n" "z *= z;\n" @@ -190,7 +190,7 @@ static HRESULT STDMETHODCALLTYPE myID3DXIncludeVtbl_Open(myID3DXInclude *cls, D3 "}\n" "float3 fog3additive(float3 regularcolour, float distance)" "{" - "float z = w_fogdensity * -distance;\n" + "float z = w_fogdensity * distance;\n" "z = max(0.0,z-w_fogdepthbias);\n" "if (r_fog_exp2)\n" "z *= z;\n" @@ -204,7 +204,7 @@ static HRESULT STDMETHODCALLTYPE myID3DXIncludeVtbl_Open(myID3DXInclude *cls, D3 "}\n" "float4 fog4additive(float4 regularcolour, float distance)" "{" - "float z = w_fogdensity * -distance;\n" + "float z = w_fogdensity * distance;\n" "z = max(0.0,z-w_fogdepthbias);\n" "if (r_fog_exp2)\n" "z *= z;\n" @@ -214,7 +214,7 @@ static HRESULT STDMETHODCALLTYPE myID3DXIncludeVtbl_Open(myID3DXInclude *cls, D3 "}\n" "float4 fog4blend(float4 regularcolour, float distance)" "{" - "float z = w_fogdensity * -distance;\n" + "float z = w_fogdensity * distance;\n" "z = max(0.0,z-w_fogdepthbias);\n" "if (r_fog_exp2)\n" "z *= z;\n" @@ -223,12 +223,11 @@ static HRESULT STDMETHODCALLTYPE myID3DXIncludeVtbl_Open(myID3DXInclude *cls, D3 "return regularcolour * float4(1.0, 1.0, 1.0, fac);\n" "}\n" "#else\n" - /*don't use macros for this - mesa bugs out*/ - "float3 fog3(float3 regularcolour, float4 fragcoord) { return regularcolour; }\n" - "float3 fog3additive(float3 regularcolour, float4 fragcoord) { return regularcolour; }\n" - "float4 fog4(float4 regularcolour, float4 fragcoord) { return regularcolour; }\n" - "float4 fog4additive(float4 regularcolour, float4 fragcoord) { return regularcolour; }\n" - "float4 fog4blend(float4 regularcolour, float4 fragcoord) { return regularcolour; }\n" + "float3 fog3(float3 regularcolour, float distance) { return regularcolour; }\n" + "float3 fog3additive(float3 regularcolour, float distance) { return regularcolour; }\n" + "float4 fog4(float4 regularcolour, float distance) { return regularcolour; }\n" + "float4 fog4additive(float4 regularcolour, float distance) { return regularcolour; }\n" + "float4 fog4blend(float4 regularcolour, float distance) { return regularcolour; }\n" "#endif\n" "#endif\n" ; @@ -580,7 +579,7 @@ void D3D9Shader_Init(void) sh_config.progpath = shaderlib?"hlsl/%s.hlsl":NULL; sh_config.shadernamefmt = "%s_hlsl9"; - sh_config.progs_supported = !!shaderlib; + sh_config.progs_supported = !!shaderlib && d3d9_hlsl.ival; sh_config.progs_required = false; sh_config.pDeleteProg = D3D9Shader_DeleteProg; diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index 6d5c5c997..282a6e78e 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -1525,6 +1525,30 @@ void GLBE_Shutdown(void) BZ_Free(shaderstate.wbatches); shaderstate.wbatches = NULL; shaderstate.maxwbatches = 0; + + //on vid_reload, the gl drivers might have various things bound that have since been destroyed/etc + //so reset that state to avoid any issues with state + /*shaderstate.sourcevbo = &shaderstate.dummyvbo; + memset(shaderstate.sourcevbo, 0, sizeof(*shaderstate.sourcevbo)); + shaderstate.pendingcolourvbo = 0; + shaderstate.pendingcolourpointer = NULL; + shaderstate.pendingvertexvbo = 0; + shaderstate.pendingvertexpointer = NULL; + for (u = 0; u < SHADER_TMU_MAX; u++) + { + shaderstate.pendingtexcoordparts[u] = 0; + shaderstate.pendingtexcoordvbo[u] = 0; + shaderstate.pendingtexcoordpointer[u] = NULL; + }*/ + if (sh_config.progs_supported) + BE_ApplyAttributes(0, (1u<= 3.0 && gl_config_nofixedfunc) diff --git a/engine/gl/gl_heightmap.c b/engine/gl/gl_heightmap.c index 2669f2a0a..8a299dcc8 100644 --- a/engine/gl/gl_heightmap.c +++ b/engine/gl/gl_heightmap.c @@ -5643,7 +5643,8 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e) default: Sys_Error("Bad lightmap_fmt\n"); break; - case TF_BGRA32: + case PTI_BGRA8: + case PTI_BGRX8: for (t = 0; t < br->faces[j].lmextents[1]; t++) { for (s = 0; s < br->faces[j].lmextents[0]; s++) @@ -5657,7 +5658,8 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e) out += (lm->width - br->faces[j].lmextents[0]) * 4; } break; - /*case TF_RGBA32: + case PTI_RGBA8: + case PTI_RGBX8: for (t = 0; t < br->faces[j].lmextents[1]; t++) { for (s = 0; s < br->faces[j].lmextents[0]; s++) @@ -5670,8 +5672,8 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e) } out += (lm->width - br->faces[j].lmextents[0]) * 4; } - break;*/ - /*case TF_BGR24: + break; + case PTI_BGR8: for (t = 0; t < br->faces[j].lmextents[1]; t++) { for (s = 0; s < br->faces[j].lmextents[0]; s++) @@ -5683,8 +5685,8 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e) } out += (lm->width - br->faces[j].lmextents[0]) * 3; } - break;*/ - case TF_RGB24: + break; + case PTI_RGB8: for (t = 0; t < br->faces[j].lmextents[1]; t++) { for (s = 0; s < br->faces[j].lmextents[0]; s++) @@ -5697,6 +5699,51 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e) out += (lm->width - br->faces[j].lmextents[0]) * 3; } break; + + + case PTI_A2BGR10: + for (t = 0; t < br->faces[j].lmextents[1]; t++) + { + for (s = 0; s < br->faces[j].lmextents[0]; s++) + { + *(unsigned int*)out = (0x3<<30) | (in[2]<<22) | (in[1]<<12) | (in[0]<<2); + out+=4; + in+=3; + } + out += (lm->width - br->faces[j].lmextents[0]) * 4; + } + break; + /*case PTI_E5BGR9: + for (t = 0; t < br->faces[j].lmextents[1]; t++) + { + for (s = 0; s < br->faces[j].lmextents[0]; s++) + { + *(unsigned int*)out = Surf_PackE5BRG9(in[0], in[1], in[2], 8); + out+=4; + in+=3; + } + out += (lm->width - br->faces[j].lmextents[0]) * 4; + } + break;*/ + case PTI_L8: + for (t = 0; t < br->faces[j].lmextents[1]; t++) + { + for (s = 0; s < br->faces[j].lmextents[0]; s++) + { + *out++ = max(max(in[0], in[1]), in[2]); + in+=3; + } + out += (lm->width - br->faces[j].lmextents[0]); + } + break; + case PTI_RGBA16F: + case PTI_RGBA32F: + case PTI_RGB565: + case PTI_RGBA4444: + case PTI_RGBA5551: + case PTI_ARGB4444: + case PTI_ARGB1555: + break; } } } @@ -5966,6 +6013,7 @@ static brushes_t *Terr_Brush_Insert(model_t *model, heightmap_t *hm, brushes_t * out->selected = false; out->contents = brush->contents; out->axialplanes = 0; + out->patch = NULL; out->planes = BZ_Malloc((sizeof(*out->planes)+sizeof(*out->faces)) * brush->numplanes); out->faces = (void*)(out->planes+brush->numplanes); diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index acc35369d..7242d6458 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -1014,6 +1014,22 @@ static void Shader_SurfaceParm ( shader_t *shader, shaderpass_t *pass, char **pt shader->flags |= SHADER_NOMARKS; //wrong, but whatever. else if ( !Q_stricmp( token, "nomarks" ) ) shader->flags |= SHADER_NOMARKS; + + //forceshader type things inherit certain textures from the original material + //however, that original material might not need those textures and thus won't have them loaded, which breaks replacement. + //these provide a way to override that. + else if (!Q_stricmp( token, "hasdiffuse")) + shader->flags |= SHADER_HASDIFFUSE; + else if (!Q_stricmp( token, "hasnormalmap")) + shader->flags |= SHADER_HASNORMALMAP; + else if (!Q_stricmp( token, "hasgloss")) + shader->flags |= SHADER_HASGLOSS; + else if (!Q_stricmp( token, "hasfullbright")) + shader->flags |= SHADER_HASFULLBRIGHT; + else if (!Q_stricmp( token, "haspaletted")) + shader->flags |= SHADER_HASPALETTED; + else if (!Q_stricmp(token, "hastop") || !Q_stricmp(token, "hasbottom") || !Q_stricmp(token, "hastopbottom")) + shader->flags |= SHADER_HASTOPBOTTOM; } static void Shader_Sort ( shader_t *shader, shaderpass_t *pass, char **ptr ) @@ -5918,7 +5934,7 @@ void Shader_DefaultBSPLM(const char *shortname, shader_t *s, const void *args) "}\n" ); } - if (!builtin && ((sh_config.progs_supported && qrenderer == QR_OPENGL) || sh_config.progs_required)) + if (!builtin && ((sh_config.progs_supported && (qrenderer == QR_OPENGL||qrenderer == QR_DIRECT3D9)) || sh_config.progs_required)) { builtin = ( "{\n" @@ -6111,38 +6127,43 @@ char *Shader_DefaultBSPWater(shader_t *s, const char *shortname, char *buffer, s "surfaceparm nodraw\n" "surfaceparm nodlight\n" "surfaceparm nomarks\n" + "surfaceparm hasdiffuse\n" "}\n" ); case -2: //regular with r_wateralpha forced off. return ( "{\n" - "program defaultwarp\n" "{\n" + "program defaultwarp\n" "map $diffuse\n" "tcmod turb 0.02 0.1 0.5 0.1\n" "}\n" "surfaceparm nodlight\n" "surfaceparm nomarks\n" + "surfaceparm hasdiffuse\n" "}\n" ); case 0: //fastturb return ( "{\n" -// "program defaultfill\n" "{\n" +// "program defaultfill\n" "map $whiteimage\n" "rgbgen srgb $r_fastturbcolour\n" "}\n" "surfaceparm nodlight\n" "surfaceparm nomarks\n" + "surfaceparm hasdiffuse\n" "}\n" ); default: case 1: //vanilla style Q_snprintfz(buffer, buffersize, "{\n" - "program defaultwarp%s\n" + "surfaceparm nodlight\n" + "surfaceparm nomarks\n" "{\n" + "program defaultwarp%s\n" "map $diffuse\n" "tcmod turb 0.02 0.1 0.5 0.1\n" "if %g < 1\n" @@ -6150,8 +6171,7 @@ char *Shader_DefaultBSPWater(shader_t *s, const char *shortname, char *buffer, s "blendfunc gl_src_alpha gl_one_minus_src_alpha\n" "endif\n" "}\n" - "surfaceparm nodlight\n" - "surfaceparm nomarks\n" + "surfaceparm hasdiffuse\n" "}\n" , explicitalpha?"":va("#ALPHA=%g",alpha), alpha, alpha); return buffer; @@ -6161,18 +6181,13 @@ char *Shader_DefaultBSPWater(shader_t *s, const char *shortname, char *buffer, s "surfaceparm nodlight\n" "surfaceparm nomarks\n" "{\n" + "program altwater#FRESNEL=4\n" "map $refraction\n" - "}\n" - "{\n" "map $null\n"//$reflection - "}\n" - "{\n" "map $null\n"//$ripplemap - "}\n" - "{\n" "map $null\n"//$refractiondepth "}\n" - "program altwater#FRESNEL=4\n" + "surfaceparm hasdiffuse\n" "}\n" ); case 3: //reflections @@ -6181,18 +6196,13 @@ char *Shader_DefaultBSPWater(shader_t *s, const char *shortname, char *buffer, s "surfaceparm nodlight\n" "surfaceparm nomarks\n" "{\n" + "program altwater#REFLECT#FRESNEL=4\n" "map $refraction\n" - "}\n" - "{\n" "map $reflection\n" - "}\n" - "{\n" "map $null\n"//$ripplemap - "}\n" - "{\n" "map $null\n"//$refractiondepth "}\n" - "program altwater#REFLECT#FRESNEL=4\n" + "surfaceparm hasdiffuse\n" "}\n" ); case 4: //ripples @@ -6201,18 +6211,13 @@ char *Shader_DefaultBSPWater(shader_t *s, const char *shortname, char *buffer, s "surfaceparm nodlight\n" "surfaceparm nomarks\n" "{\n" + "program altwater#RIPPLEMAP#FRESNEL=4\n" "map $refraction\n" - "}\n" - "{\n" "map $null\n"//$reflection - "}\n" - "{\n" "map $ripplemap\n" - "}\n" - "{\n" "map $null\n"//$refractiondepth "}\n" - "program altwater#RIPPLEMAP#FRESNEL=4\n" + "surfaceparm hasdiffuse\n" "}\n" ); case 5: //ripples+reflections @@ -6221,18 +6226,13 @@ char *Shader_DefaultBSPWater(shader_t *s, const char *shortname, char *buffer, s "surfaceparm nodlight\n" "surfaceparm nomarks\n" "{\n" + "program altwater#REFLECT#RIPPLEMAP#FRESNEL=4\n" "map $refraction\n" - "}\n" - "{\n" "map $reflection\n" - "}\n" - "{\n" "map $ripplemap\n" - "}\n" - "{\n" "map $null\n"//$refractiondepth "}\n" - "program altwater#REFLECT#RIPPLEMAP#FRESNEL=4\n" + "surfaceparm hasdiffuse\n" "}\n" ); } @@ -6377,42 +6377,48 @@ void Shader_DefaultBSPQ1(const char *shortname, shader_t *s, const void *args) if (!builtin && *shortname == '{') { /*alpha test*/ - /*FIXME: use defaultwall#ALPHA=0.666 or so*/ - builtin = ( - "{\n" - /* "if $deluxmap\n" - "{\n" - "map $normalmap\n" - "tcgen base\n" - "}\n" - "{\n" - "map $deluxmap\n" - "tcgen lightmap\n" - "}\n" - "endif\n"*/ + if (sh_config.progs_supported) + builtin = ( "{\n" - "map $diffuse\n" - "tcgen base\n" - "alphafunc ge128\n" + "fte_program defaultwall#MASK=0.666#MASKLT\n" "}\n" -// "if $lightmap\n" + ); + else + builtin = ( + "{\n" + /* "if $deluxmap\n" + "{\n" + "map $normalmap\n" + "tcgen base\n" + "}\n" + "{\n" + "map $deluxmap\n" + "tcgen lightmap\n" + "}\n" + "endif\n"*/ "{\n" - "map $lightmap\n" - "if gl_overbright > 1\n" - "blendfunc gl_dst_color gl_src_color\n" //scale it up twice. will probably still get clamped, but what can you do - "else\n" - "blendfunc gl_dst_color gl_zero\n" - "endif\n" + "map $diffuse\n" + "tcgen base\n" + "alphafunc ge128\n" + "}\n" + // "if $lightmap\n" + "{\n" + "map $lightmap\n" + "if gl_overbright > 1\n" + "blendfunc gl_dst_color gl_src_color\n" //scale it up twice. will probably still get clamped, but what can you do + "else\n" + "blendfunc gl_dst_color gl_zero\n" + "endif\n" + "depthfunc equal\n" + "}\n" + // "endif\n" + "{\n" + "map $fullbright\n" + "blendfunc add\n" "depthfunc equal\n" "}\n" -// "endif\n" - "{\n" - "map $fullbright\n" - "blendfunc add\n" - "depthfunc equal\n" "}\n" - "}\n" - ); + ); } /*Hack: note that halflife would normally expect you to use rendermode/renderampt*/ @@ -6610,7 +6616,7 @@ void Shader_Default2D(const char *shortname, shader_t *s, const void *genargs) "nomipmaps\n" "program default2d#PREMUL\n" "{\n" - "map $diffuse\n" + "clampmap $diffuse\n" "blendfunc gl_one gl_one_minus_src_alpha\n" "}\n" "sort additive\n" diff --git a/engine/gl/r_bishaders.h b/engine/gl/r_bishaders.h index acac005db..e6f211460 100644 --- a/engine/gl/r_bishaders.h +++ b/engine/gl/r_bishaders.h @@ -6048,6 +6048,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "if (gl_FragColor.a >= MASK)\n" "discard;\n" "#endif\n" +"gl_FragColor.a = 1.0; //alpha blending AND alpha testing usually looks stupid, plus it screws up our fog.\n" "#endif\n" //and finally hide it all if we're fogged. @@ -6062,7 +6063,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #ifdef VKQUAKE {QR_VULKAN, -1, "defaultwall", "\xFF\x53\x50\x56\x01\x00\x00\x00\x9C\x1F\x00\x00\x01\x00\x00\x00\x2B\x00\x00\x00\x2C\x00\x00\x00\xA6\x00\x00\x00\xD4\x00\x00\x00" -"\x10\x15\x00\x00\xE4\x15\x00\x00\x18\x48\x00\x00\x01\x00\x66\x31\x72\x5F\x67\x6C\x73\x6C\x5F\x6F\x66\x66\x73\x65\x74\x6D\x61\x70" +"\x10\x15\x00\x00\xE4\x15\x00\x00\x38\x48\x00\x00\x01\x00\x66\x31\x72\x5F\x67\x6C\x73\x6C\x5F\x6F\x66\x66\x73\x65\x74\x6D\x61\x70" "\x70\x69\x6E\x67\x00\x00\x00\x00\x00\x01\x01\x66\x31\x72\x5F\x67\x6C\x73\x6C\x5F\x6F\x66\x66\x73\x65\x74\x6D\x61\x70\x70\x69\x6E" "\x67\x5F\x73\x63\x61\x6C\x65\x00\x3D\x23\xD7\x0A\x01\x02\x66\x31\x67\x6C\x5F\x73\x70\x65\x63\x75\x6C\x61\x72\x00\x3E\x99\x99\x9A" "\x01\x03\x62\x31\x72\x5F\x66\x6F\x67\x5F\x65\x78\x70\x32\x00\x00\x00\x00\x00\x01\x04\x42\x31\x76\x65\x72\x74\x65\x78\x6C\x69\x74" @@ -6236,7 +6237,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "\x81\x00\x05\x00\x06\x00\x00\x00\x31\x00\x00\x00\x2D\x00\x00\x00\x30\x00\x00\x00\x88\x00\x05\x00\x06\x00\x00\x00\x33\x00\x00\x00" "\x31\x00\x00\x00\x32\x00\x00\x00\x41\x00\x05\x00\x26\x00\x00\x00\x34\x00\x00\x00\x0C\x00\x00\x00\x2B\x00\x00\x00\x3E\x00\x03\x00" "\x34\x00\x00\x00\x33\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00\x35\x00\x00\x00\x0C\x00\x00\x00\xFE\x00\x02\x00\x35\x00\x00\x00" -"\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x01\x00\x08\x00\xDD\x02\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00" +"\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x01\x00\x08\x00\xDE\x02\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00" "\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00" "\x01\x00\x00\x00\x0F\x00\x0C\x00\x04\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x3F\x00\x00\x00\x97\x01\x00\x00" "\x9F\x01\x00\x00\xA8\x01\x00\x00\xCF\x01\x00\x00\xDD\x01\x00\x00\x4C\x02\x00\x00\x10\x00\x03\x00\x04\x00\x00\x00\x07\x00\x00\x00" @@ -6292,16 +6293,16 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "\x66\x6C\x65\x63\x74\x6D\x61\x73\x6B\x00\x00\x00\x05\x00\x06\x00\x71\x02\x00\x00\x73\x5F\x72\x65\x66\x6C\x65\x63\x74\x63\x75\x62" "\x65\x00\x00\x00\x05\x00\x03\x00\x81\x02\x00\x00\x70\x61\x6C\x00\x05\x00\x05\x00\x82\x02\x00\x00\x73\x5F\x70\x61\x6C\x65\x74\x74" "\x65\x64\x00\x00\x05\x00\x04\x00\x8B\x02\x00\x00\x73\x5F\x74\x30\x00\x00\x00\x00\x05\x00\x06\x00\xB3\x02\x00\x00\x73\x5F\x66\x75" -"\x6C\x6C\x62\x72\x69\x67\x68\x74\x00\x00\x00\x00\x05\x00\x04\x00\xD7\x02\x00\x00\x70\x61\x72\x61\x6D\x00\x00\x00\x05\x00\x05\x00" -"\xDA\x02\x00\x00\x6C\x69\x67\x68\x74\x62\x6C\x6F\x63\x6B\x00\x00\x06\x00\x07\x00\xDA\x02\x00\x00\x00\x00\x00\x00\x6C\x5F\x63\x75" -"\x62\x65\x6D\x61\x74\x72\x69\x78\x00\x00\x00\x00\x06\x00\x07\x00\xDA\x02\x00\x00\x01\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x70" -"\x6F\x73\x69\x74\x69\x6F\x6E\x00\x06\x00\x05\x00\xDA\x02\x00\x00\x02\x00\x00\x00\x6C\x70\x61\x64\x31\x00\x00\x00\x06\x00\x07\x00" -"\xDA\x02\x00\x00\x03\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x63\x6F\x6C\x6F\x75\x72\x00\x00\x00\x06\x00\x05\x00\xDA\x02\x00\x00" -"\x04\x00\x00\x00\x6C\x70\x61\x64\x32\x00\x00\x00\x06\x00\x08\x00\xDA\x02\x00\x00\x05\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x63" -"\x6F\x6C\x6F\x75\x72\x73\x63\x61\x6C\x65\x00\x00\x06\x00\x07\x00\xDA\x02\x00\x00\x06\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x72" -"\x61\x64\x69\x75\x73\x00\x00\x00\x06\x00\x07\x00\xDA\x02\x00\x00\x07\x00\x00\x00\x6C\x5F\x73\x68\x61\x64\x6F\x77\x6D\x61\x70\x70" -"\x72\x6F\x6A\x00\x06\x00\x08\x00\xDA\x02\x00\x00\x08\x00\x00\x00\x6C\x5F\x73\x68\x61\x64\x6F\x77\x6D\x61\x70\x73\x63\x61\x6C\x65" -"\x00\x00\x00\x00\x06\x00\x05\x00\xDA\x02\x00\x00\x09\x00\x00\x00\x6C\x70\x61\x64\x33\x00\x00\x00\x05\x00\x03\x00\xDC\x02\x00\x00" +"\x6C\x6C\x62\x72\x69\x67\x68\x74\x00\x00\x00\x00\x05\x00\x04\x00\xD8\x02\x00\x00\x70\x61\x72\x61\x6D\x00\x00\x00\x05\x00\x05\x00" +"\xDB\x02\x00\x00\x6C\x69\x67\x68\x74\x62\x6C\x6F\x63\x6B\x00\x00\x06\x00\x07\x00\xDB\x02\x00\x00\x00\x00\x00\x00\x6C\x5F\x63\x75" +"\x62\x65\x6D\x61\x74\x72\x69\x78\x00\x00\x00\x00\x06\x00\x07\x00\xDB\x02\x00\x00\x01\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x70" +"\x6F\x73\x69\x74\x69\x6F\x6E\x00\x06\x00\x05\x00\xDB\x02\x00\x00\x02\x00\x00\x00\x6C\x70\x61\x64\x31\x00\x00\x00\x06\x00\x07\x00" +"\xDB\x02\x00\x00\x03\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x63\x6F\x6C\x6F\x75\x72\x00\x00\x00\x06\x00\x05\x00\xDB\x02\x00\x00" +"\x04\x00\x00\x00\x6C\x70\x61\x64\x32\x00\x00\x00\x06\x00\x08\x00\xDB\x02\x00\x00\x05\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x63" +"\x6F\x6C\x6F\x75\x72\x73\x63\x61\x6C\x65\x00\x00\x06\x00\x07\x00\xDB\x02\x00\x00\x06\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x72" +"\x61\x64\x69\x75\x73\x00\x00\x00\x06\x00\x07\x00\xDB\x02\x00\x00\x07\x00\x00\x00\x6C\x5F\x73\x68\x61\x64\x6F\x77\x6D\x61\x70\x70" +"\x72\x6F\x6A\x00\x06\x00\x08\x00\xDB\x02\x00\x00\x08\x00\x00\x00\x6C\x5F\x73\x68\x61\x64\x6F\x77\x6D\x61\x70\x73\x63\x61\x6C\x65" +"\x00\x00\x00\x00\x06\x00\x05\x00\xDB\x02\x00\x00\x09\x00\x00\x00\x6C\x70\x61\x64\x33\x00\x00\x00\x05\x00\x03\x00\xDD\x02\x00\x00" "\x00\x00\x00\x00\x47\x00\x04\x00\x28\x00\x00\x00\x01\x00\x00\x00\x15\x00\x00\x00\x47\x00\x04\x00\x36\x00\x00\x00\x06\x00\x00\x00" "\x10\x00\x00\x00\x48\x00\x04\x00\x37\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x48\x00\x05\x00\x37\x00\x00\x00\x00\x00\x00\x00" "\x23\x00\x00\x00\x00\x00\x00\x00\x48\x00\x05\x00\x37\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x10\x00\x00\x00\x48\x00\x04\x00" @@ -6341,15 +6342,15 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "\x22\x00\x00\x00\x00\x00\x00\x00\x47\x00\x04\x00\x8B\x02\x00\x00\x21\x00\x00\x00\x0B\x00\x00\x00\x47\x00\x04\x00\xAF\x02\x00\x00" "\x01\x00\x00\x00\x11\x00\x00\x00\x47\x00\x04\x00\xB3\x02\x00\x00\x22\x00\x00\x00\x00\x00\x00\x00\x47\x00\x04\x00\xB3\x02\x00\x00" "\x21\x00\x00\x00\x05\x00\x00\x00\x47\x00\x04\x00\xC2\x02\x00\x00\x01\x00\x00\x00\x06\x01\x00\x00\x47\x00\x04\x00\xC6\x02\x00\x00" -"\x01\x00\x00\x00\x07\x01\x00\x00\x48\x00\x04\x00\xDA\x02\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x48\x00\x05\x00\xDA\x02\x00\x00" -"\x00\x00\x00\x00\x23\x00\x00\x00\x00\x00\x00\x00\x48\x00\x05\x00\xDA\x02\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x10\x00\x00\x00" -"\x48\x00\x05\x00\xDA\x02\x00\x00\x01\x00\x00\x00\x23\x00\x00\x00\x40\x00\x00\x00\x48\x00\x05\x00\xDA\x02\x00\x00\x02\x00\x00\x00" -"\x23\x00\x00\x00\x4C\x00\x00\x00\x48\x00\x05\x00\xDA\x02\x00\x00\x03\x00\x00\x00\x23\x00\x00\x00\x50\x00\x00\x00\x48\x00\x05\x00" -"\xDA\x02\x00\x00\x04\x00\x00\x00\x23\x00\x00\x00\x5C\x00\x00\x00\x48\x00\x05\x00\xDA\x02\x00\x00\x05\x00\x00\x00\x23\x00\x00\x00" -"\x60\x00\x00\x00\x48\x00\x05\x00\xDA\x02\x00\x00\x06\x00\x00\x00\x23\x00\x00\x00\x6C\x00\x00\x00\x48\x00\x05\x00\xDA\x02\x00\x00" -"\x07\x00\x00\x00\x23\x00\x00\x00\x70\x00\x00\x00\x48\x00\x05\x00\xDA\x02\x00\x00\x08\x00\x00\x00\x23\x00\x00\x00\x80\x00\x00\x00" -"\x48\x00\x05\x00\xDA\x02\x00\x00\x09\x00\x00\x00\x23\x00\x00\x00\x88\x00\x00\x00\x47\x00\x03\x00\xDA\x02\x00\x00\x02\x00\x00\x00" -"\x47\x00\x04\x00\xDC\x02\x00\x00\x22\x00\x00\x00\x00\x00\x00\x00\x47\x00\x04\x00\xDC\x02\x00\x00\x21\x00\x00\x00\x01\x00\x00\x00" +"\x01\x00\x00\x00\x07\x01\x00\x00\x48\x00\x04\x00\xDB\x02\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x48\x00\x05\x00\xDB\x02\x00\x00" +"\x00\x00\x00\x00\x23\x00\x00\x00\x00\x00\x00\x00\x48\x00\x05\x00\xDB\x02\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x10\x00\x00\x00" +"\x48\x00\x05\x00\xDB\x02\x00\x00\x01\x00\x00\x00\x23\x00\x00\x00\x40\x00\x00\x00\x48\x00\x05\x00\xDB\x02\x00\x00\x02\x00\x00\x00" +"\x23\x00\x00\x00\x4C\x00\x00\x00\x48\x00\x05\x00\xDB\x02\x00\x00\x03\x00\x00\x00\x23\x00\x00\x00\x50\x00\x00\x00\x48\x00\x05\x00" +"\xDB\x02\x00\x00\x04\x00\x00\x00\x23\x00\x00\x00\x5C\x00\x00\x00\x48\x00\x05\x00\xDB\x02\x00\x00\x05\x00\x00\x00\x23\x00\x00\x00" +"\x60\x00\x00\x00\x48\x00\x05\x00\xDB\x02\x00\x00\x06\x00\x00\x00\x23\x00\x00\x00\x6C\x00\x00\x00\x48\x00\x05\x00\xDB\x02\x00\x00" +"\x07\x00\x00\x00\x23\x00\x00\x00\x70\x00\x00\x00\x48\x00\x05\x00\xDB\x02\x00\x00\x08\x00\x00\x00\x23\x00\x00\x00\x80\x00\x00\x00" +"\x48\x00\x05\x00\xDB\x02\x00\x00\x09\x00\x00\x00\x23\x00\x00\x00\x88\x00\x00\x00\x47\x00\x03\x00\xDB\x02\x00\x00\x02\x00\x00\x00" +"\x47\x00\x04\x00\xDD\x02\x00\x00\x22\x00\x00\x00\x00\x00\x00\x00\x47\x00\x04\x00\xDD\x02\x00\x00\x21\x00\x00\x00\x01\x00\x00\x00" "\x13\x00\x02\x00\x02\x00\x00\x00\x21\x00\x03\x00\x03\x00\x00\x00\x02\x00\x00\x00\x16\x00\x03\x00\x06\x00\x00\x00\x20\x00\x00\x00" "\x17\x00\x04\x00\x07\x00\x00\x00\x06\x00\x00\x00\x03\x00\x00\x00\x20\x00\x04\x00\x08\x00\x00\x00\x07\x00\x00\x00\x07\x00\x00\x00" "\x21\x00\x04\x00\x09\x00\x00\x00\x07\x00\x00\x00\x08\x00\x00\x00\x17\x00\x04\x00\x10\x00\x00\x00\x06\x00\x00\x00\x04\x00\x00\x00" @@ -6403,9 +6404,9 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "\x94\x02\x00\x00\x03\x00\x00\x00\x06\x00\x00\x00\x32\x00\x04\x00\x27\x00\x00\x00\xAF\x02\x00\x00\x11\x00\x00\x00\x3B\x00\x04\x00" "\x9C\x01\x00\x00\xB3\x02\x00\x00\x00\x00\x00\x00\x2B\x00\x04\x00\x27\x00\x00\x00\xBE\x02\x00\x00\x12\x00\x00\x00\x32\x00\x04\x00" "\x06\x00\x00\x00\xC2\x02\x00\x00\x00\x00\x83\x43\x32\x00\x04\x00\x27\x00\x00\x00\xC6\x02\x00\x00\x07\x01\x00\x00\x1E\x00\x0C\x00" -"\xDA\x02\x00\x00\x33\x00\x00\x00\x07\x00\x00\x00\x06\x00\x00\x00\x07\x00\x00\x00\x06\x00\x00\x00\x07\x00\x00\x00\x06\x00\x00\x00" -"\x10\x00\x00\x00\x1F\x00\x00\x00\x1F\x00\x00\x00\x20\x00\x04\x00\xDB\x02\x00\x00\x02\x00\x00\x00\xDA\x02\x00\x00\x3B\x00\x04\x00" -"\xDB\x02\x00\x00\xDC\x02\x00\x00\x02\x00\x00\x00\x36\x00\x05\x00\x02\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00" +"\xDB\x02\x00\x00\x33\x00\x00\x00\x07\x00\x00\x00\x06\x00\x00\x00\x07\x00\x00\x00\x06\x00\x00\x00\x07\x00\x00\x00\x06\x00\x00\x00" +"\x10\x00\x00\x00\x1F\x00\x00\x00\x1F\x00\x00\x00\x20\x00\x04\x00\xDC\x02\x00\x00\x02\x00\x00\x00\xDB\x02\x00\x00\x3B\x00\x04\x00" +"\xDC\x02\x00\x00\xDD\x02\x00\x00\x02\x00\x00\x00\x36\x00\x05\x00\x02\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00" "\xF8\x00\x02\x00\x05\x00\x00\x00\x3B\x00\x04\x00\x20\x00\x00\x00\x95\x01\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x1E\x00\x00\x00" "\xA0\x01\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x20\x00\x00\x00\xA2\x01\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x08\x00\x00\x00" "\xA4\x01\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x08\x00\x00\x00\xBA\x01\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x08\x00\x00\x00" @@ -6413,7 +6414,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "\xF9\x01\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x11\x00\x00\x00\x12\x02\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x08\x00\x00\x00" "\x19\x02\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x31\x00\x00\x00\x2A\x02\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x08\x00\x00\x00" "\x42\x02\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x31\x00\x00\x00\x81\x02\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x11\x00\x00\x00" -"\xD7\x02\x00\x00\x07\x00\x00\x00\x3D\x00\x04\x00\x1F\x00\x00\x00\x98\x01\x00\x00\x97\x01\x00\x00\x3E\x00\x03\x00\x95\x01\x00\x00" +"\xD8\x02\x00\x00\x07\x00\x00\x00\x3D\x00\x04\x00\x1F\x00\x00\x00\x98\x01\x00\x00\x97\x01\x00\x00\x3E\x00\x03\x00\x95\x01\x00\x00" "\x98\x01\x00\x00\xBA\x00\x05\x00\x2A\x00\x00\x00\x99\x01\x00\x00\x65\x01\x00\x00\x49\x00\x00\x00\xF7\x00\x03\x00\x9B\x01\x00\x00" "\x00\x00\x00\x00\xFA\x00\x04\x00\x99\x01\x00\x00\x9A\x01\x00\x00\x9B\x01\x00\x00\xF8\x00\x02\x00\x9A\x01\x00\x00\x3D\x00\x04\x00" "\x1D\x00\x00\x00\xA1\x01\x00\x00\x9D\x01\x00\x00\x3E\x00\x03\x00\xA0\x01\x00\x00\xA1\x01\x00\x00\x3D\x00\x04\x00\x1F\x00\x00\x00" @@ -6593,9 +6594,10 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "\x45\x00\x00\x00\x3D\x00\x04\x00\x06\x00\x00\x00\xD2\x02\x00\x00\xD1\x02\x00\x00\xBE\x00\x05\x00\x2A\x00\x00\x00\xD3\x02\x00\x00" "\xD2\x02\x00\x00\xC2\x02\x00\x00\xF7\x00\x03\x00\xD5\x02\x00\x00\x00\x00\x00\x00\xFA\x00\x04\x00\xD3\x02\x00\x00\xD4\x02\x00\x00" "\xD5\x02\x00\x00\xF8\x00\x02\x00\xD4\x02\x00\x00\xFC\x00\x01\x00\xF8\x00\x02\x00\xD5\x02\x00\x00\xF9\x00\x02\x00\xC9\x02\x00\x00" -"\xF8\x00\x02\x00\xC9\x02\x00\x00\xF9\x00\x02\x00\xC5\x02\x00\x00\xF8\x00\x02\x00\xC5\x02\x00\x00\x3D\x00\x04\x00\x10\x00\x00\x00" -"\xD8\x02\x00\x00\xA8\x01\x00\x00\x3E\x00\x03\x00\xD7\x02\x00\x00\xD8\x02\x00\x00\x39\x00\x05\x00\x10\x00\x00\x00\xD9\x02\x00\x00" -"\x14\x00\x00\x00\xD7\x02\x00\x00\x3E\x00\x03\x00\xA8\x01\x00\x00\xD9\x02\x00\x00\xFD\x00\x01\x00\x38\x00\x01\x00\x36\x00\x05\x00" +"\xF8\x00\x02\x00\xC9\x02\x00\x00\x41\x00\x05\x00\x94\x02\x00\x00\xD7\x02\x00\x00\xA8\x01\x00\x00\x45\x00\x00\x00\x3E\x00\x03\x00" +"\xD7\x02\x00\x00\x5D\x00\x00\x00\xF9\x00\x02\x00\xC5\x02\x00\x00\xF8\x00\x02\x00\xC5\x02\x00\x00\x3D\x00\x04\x00\x10\x00\x00\x00" +"\xD9\x02\x00\x00\xA8\x01\x00\x00\x3E\x00\x03\x00\xD8\x02\x00\x00\xD9\x02\x00\x00\x39\x00\x05\x00\x10\x00\x00\x00\xDA\x02\x00\x00" +"\x14\x00\x00\x00\xD8\x02\x00\x00\x3E\x00\x03\x00\xA8\x01\x00\x00\xDA\x02\x00\x00\xFD\x00\x01\x00\x38\x00\x01\x00\x36\x00\x05\x00" "\x07\x00\x00\x00\x0B\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x37\x00\x03\x00\x08\x00\x00\x00\x0A\x00\x00\x00\xF8\x00\x02\x00" "\x0C\x00\x00\x00\x3B\x00\x04\x00\x31\x00\x00\x00\x32\x00\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x31\x00\x00\x00\x57\x00\x00\x00" "\x07\x00\x00\x00\xAB\x00\x05\x00\x2A\x00\x00\x00\x2B\x00\x00\x00\x28\x00\x00\x00\x29\x00\x00\x00\xA8\x00\x04\x00\x2A\x00\x00\x00" @@ -6814,6 +6816,288 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "\xFE\x00\x02\x00\x90\x01\x00\x00\xF8\x00\x02\x00\x68\x01\x00\x00\xF9\x00\x02\x00\x12\x01\x00\x00\xF8\x00\x02\x00\x12\x01\x00\x00" "\x3D\x00\x04\x00\x1F\x00\x00\x00\x92\x01\x00\x00\x23\x00\x00\x00\xFE\x00\x02\x00\x92\x01\x00\x00\x38\x00\x01\x00"}, #endif +#ifdef D3D9QUAKE +{QR_DIRECT3D9, 9, "defaultwall", +//!!ver 100 150 +//!!permu DELUXE +"!!permu FULLBRIGHT\n" +"!!permu FOG\n" +//!!permu LIGHTSTYLED +//!!permu BUMP +//!!permu SPECULAR +//!!permu REFLECTCUBEMASK +//!!cvarf r_glsl_offsetmapping_scale +//!!cvardf r_tessellation_level=5 +//!!samps diffuse lightmap specular normalmap fullbright reflectmask reflectcube paletted lightmap1 lightmap2 lightmap3 +"!!samps diffuse fullbright lightmap\n" + +//#include "sys/defs.h" +"#define vec4 float4\n" +"#define vec3 float3\n" +"#define vec2 float2\n" +"#define texture2D tex2D\n" +"#define mat3 float3x3\n" +"#define mat4 float4x4\n" +"struct a2v\n" +"{\n" +"vec4 v_position : POSITION;\n" +"vec2 v_texcoord : TEXCOORD0;\n" +"vec2 v_lmcoord : TEXCOORD1;\n" +"};\n" +"struct v2f\n" +"{\n" +"#ifndef FRAGMENT_SHADER\n" +"vec4 pos: POSITION;\n" +"#endif\n" + +"#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK) || defined(FOG)\n" +"vec3 eyevector : TEXCOORD4;\n" +"#endif\n" + +"#if defined(REFLECTCUBEMASK) || defined(BUMPMODELSPACE)\n" +"mat3 invsurface : TEXCOORD5;\n" +"#endif\n" + +"vec4 tclm : TEXCOORD0;\n" +"vec4 vc : COLOR0;\n" +"#ifndef VERTEXLIT\n" +"#ifdef LIGHTSTYLED\n" +//we could use an offset, but that would still need to be per-surface which would break batches +//fixme: merge attributes? +"vec2 lm1 : TEXCOORD1, lm2 : TEXCOORD2, lm3 : TEXCOORD3;\n" +"#endif\n" +"#endif\n" +"};\n" + +//this is what normally draws all of your walls, even with rtlights disabled +//note that the '286' preset uses drawflat_walls instead. + +"#include \"sys/fog.h\"\n" + +"#ifdef VERTEX_SHADER\n" +"float4x4 m_modelviewprojection;\n" +"float4x4 m_modelview;\n" +"vec3 e_eyepos;\n" +"vec4 e_lmscale;\n" +"v2f main (a2v inp)\n" +"{\n" +"v2f outp;\n" + +"#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK)\n" +"vec3 eyeminusvertex = e_eyepos - inp.v_position.xyz;\n" +"outp.eyevector.x = dot(eyeminusvertex, inp.v_svector.xyz);\n" +"outp.eyevector.y = dot(eyeminusvertex, inp.v_tvector.xyz);\n" +"outp.eyevector.z = dot(eyeminusvertex, inp.v_normal.xyz);\n" +"#elif defined(FOG)\n" +"outp.eyevector = mul(m_modelview, inp.v_position);\n" +"#endif\n" +"#if defined(REFLECTCUBEMASK) || defined(BUMPMODELSPACE)\n" +"outp.invsurface[0] = inp.v_svector;\n" +"outp.invsurface[1] = inp.v_tvector;\n" +"outp.invsurface[2] = inp.v_normal;\n" +"#endif\n" +"outp.tclm.xy = inp.v_texcoord;\n" +"#ifdef FLOW\n" +// outp.tclm.x += e_time * -0.5; +"#endif\n" +"#ifdef VERTEXLIT\n" +"#ifdef LIGHTSTYLED\n" +//FIXME, only one colour. +"outp.vc = inp.v_colour * e_lmscale[0];\n" +"#else\n" +"outp.vc = inp.v_colour * e_lmscale;\n" +"#endif\n" +"#else\n" +"outp.vc = e_lmscale;\n" +"outp.tclm.zw = inp.v_lmcoord;\n" +"#ifdef LIGHTSTYLED\n" +"outp.lm1 = inp.v_lmcoord2;\n" +"outp.lm2 = inp.v_lmcoord3;\n" +"outp.lm3 = inp.v_lmcoord4;\n" +"#endif\n" +"#endif\n" +"outp.pos = mul(m_modelviewprojection, inp.v_position);\n" + +"return outp;\n" +"}\n" +"#endif\n" + + + + + + + + + + +"#ifdef FRAGMENT_SHADER\n" +"sampler s_diffuse : register(s0);\n" +//sampler s_normalmap; +//sampler s_specular; +//sampler s_upper; +//sampler s_lower; +"sampler s_fullbright : register(s1);\n" +//sampler s_paletted; +//sampler s_reflectcube; +//sampler s_reflectmask; +"sampler s_lightmap : register(s2);\n" +//sampler s_deluxmap; + + +//samplers +"#define s_colourmap s_t0\n" +//sampler2D s_colourmap; + +//vec4 e_lmscale; +"vec4 e_colourident;\n" + +"#ifdef OFFSETMAPPING\n" +"#include \"sys/offsetmapping.h\"\n" +"#endif\n" +"vec4 main (v2f inp) : COLOR0\n" +"{\n" +"vec4 gl_FragColor;\n" +"#define tc (inp.tclm.xy)\n" +"#define lm0 (inp.tclm.zw)\n" + + +//adjust texture coords for offsetmapping +"#ifdef OFFSETMAPPING\n" +"vec2 tcoffsetmap = offsetmap(s_normalmap, tc, eyevector);\n" +"#define tc tcoffsetmap\n" +"#endif\n" + +"#if defined(EIGHTBIT) && !defined(LIGHTSTYLED)\n" +//optional: round the lightmap coords to ensure all pixels within a texel have different lighting values either. it just looks wrong otherwise. +//don't bother if its lightstyled, such cases will have unpredictable correlations anyway. +//FIXME: this rounding is likely not correct with respect to software rendering. oh well. +"#if __VERSION__ >= 130\n" +"vec2 lmsize = vec2(textureSize(s_lightmap0, 0));\n" +"#else\n" +"#define lmsize vec2(128.0,2048.0)\n" +"#endif\n" +"#define texelstolightmap (16.0)\n" +"vec2 lmcoord0 = floor(lm0 * lmsize*texelstolightmap)/(lmsize*texelstolightmap);\n" +"#define lm0 lmcoord0\n" +"#endif\n" + + +//yay, regular texture! +"gl_FragColor = texture2D(s_diffuse, tc);\n" + +"#if defined(BUMP) && (defined(DELUXE) || defined(SPECULAR) || defined(REFLECTCUBEMASK))\n" +"vec3 norm = normalize(texture2D(s_normalmap, tc).rgb - 0.5);\n" +"#elif defined(SPECULAR) || defined(DELUXE) || defined(REFLECTCUBEMASK)\n" +"vec3 norm = vec3(0, 0, 1); //specular lighting expects this to exist.\n" +"#endif\n" + +//modulate that by the lightmap(s) including deluxemap(s) +"#ifdef VERTEXLIT\n" +"#error foobar\n" +"#ifdef LIGHTSTYLED\n" +"vec3 lightmaps = vc.rgb;\n" +"#else\n" +"vec3 lightmaps = vc.rgb;\n" +"#endif\n" +"#define delux vec3(0.0,0.0,1.0)\n" +"#else\n" +"#ifdef LIGHTSTYLED\n" +"#error foobar\n" +"#define delux vec3(0.0,0.0,1.0)\n" +"vec3 lightmaps;\n" +"#ifdef DELUXE\n" +"lightmaps = texture2D(s_lightmap0, lm0).rgb * e_lmscale[0].rgb * dot(norm, 2.0*texture2D(s_deluxmap0, lm0).rgb-0.5);\n" +"lightmaps += texture2D(s_lightmap1, lm1).rgb * e_lmscale[1].rgb * dot(norm, 2.0*texture2D(s_deluxmap1, lm1).rgb-0.5);\n" +"lightmaps += texture2D(s_lightmap2, lm2).rgb * e_lmscale[2].rgb * dot(norm, 2.0*texture2D(s_deluxmap2, lm2).rgb-0.5);\n" +"lightmaps += texture2D(s_lightmap3, lm3).rgb * e_lmscale[3].rgb * dot(norm, 2.0*texture2D(s_deluxmap3, lm3).rgb-0.5);\n" +"#else\n" +"lightmaps = texture2D(s_lightmap0, lm0).rgb * e_lmscale[0].rgb;\n" +"lightmaps += texture2D(s_lightmap1, lm1).rgb * e_lmscale[1].rgb;\n" +"lightmaps += texture2D(s_lightmap2, lm2).rgb * e_lmscale[2].rgb;\n" +"lightmaps += texture2D(s_lightmap3, lm3).rgb * e_lmscale[3].rgb;\n" +"#endif\n" +"#else\n" +"vec3 lightmaps = texture2D(s_lightmap, lm0).rgb;\n" +//modulate by the bumpmap dot light +"#ifdef DELUXE\n" +"#error foobar\n" +"vec3 delux = (texture2D(s_deluxmap, lm0).rgb-0.5);\n" +"#ifdef BUMPMODELSPACE\n" +"delux = normalize(delux*invsurface);\n" +"#else\n" +"lightmaps *= 2.0 / max(0.25, delux.z); //counter the darkening from deluxmaps\n" +"#endif\n" +"lightmaps *= dot(norm, delux);\n" +"#else\n" +"#define delux vec3(0.0,0.0,1.0)\n" +"#endif\n" +"#endif\n" +"lightmaps *= inp.vc.rgb;\n" +"#endif\n" + +//add in specular, if applicable. +"#ifdef SPECULAR\n" +"vec4 specs = texture2D(s_specular, tc);\n" +"vec3 halfdir = normalize(normalize(eyevector) + delux); //this norm should be the deluxemap info instead\n" +"float spec = pow(max(dot(halfdir, norm), 0.0), FTE_SPECULAR_EXPONENT * specs.a);\n" +"spec *= FTE_SPECULAR_MULTIPLIER;\n" +//NOTE: rtlights tend to have a *4 scaler here to over-emphasise the effect because it looks cool. +//As not all maps will have deluxemapping, and the double-cos from the light util makes everything far too dark anyway, +//we default to something that is not garish when the light value is directly infront of every single pixel. +//we can justify this difference due to the rtlight editor etc showing the *4. +"gl_FragColor.rgb += spec * specs.rgb;\n" +"#endif\n" + +"#ifdef REFLECTCUBEMASK\n" +"vec3 rtc = reflect(normalize(-eyevector), norm);\n" +"rtc = rtc.x*invsurface[0] + rtc.y*invsurface[1] + rtc.z*invsurface[2];\n" +"rtc = (m_model * vec4(rtc.xyz,0.0)).xyz;\n" +"gl_FragColor.rgb += texture2D(s_reflectmask, tc).rgb * textureCube(s_reflectcube, rtc).rgb;\n" +"#endif\n" + +"#ifdef EIGHTBIT //FIXME: with this extra flag, half the permutations are redundant.\n" +"lightmaps *= 0.5; //counter the fact that the colourmap contains overbright values and logically ranges from 0 to 2 intead of to 1.\n" +"float pal = texture2D(s_paletted, tc).r; //the palette index. hopefully not interpolated.\n" +"lightmaps -= 1.0 / 128.0; //software rendering appears to round down, so make sure we favour the lower values instead of rounding to the nearest\n" +"gl_FragColor.r = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.r)).r; //do 3 lookups. this is to cope with lit files, would be a waste to not support those.\n" +"gl_FragColor.g = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.g)).g; //its not very softwarey, but re-palettizing is ugly.\n" +"gl_FragColor.b = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.b)).b; //without lits, it should be identical.\n" +"#else\n" +//now we have our diffuse+specular terms, modulate by lightmap values. +"gl_FragColor.rgb *= lightmaps.rgb;\n" + +//add on the fullbright +"#ifdef FULLBRIGHT\n" +"vec4 fb = texture2D(s_fullbright, tc);\n" +"gl_FragColor.rgb += fb.rgb*fb.a;\n" +"#endif\n" +"#endif\n" + +//entity modifiers +"gl_FragColor = gl_FragColor * e_colourident;\n" + +"#if defined(MASK)\n" +"#if defined(MASKLT)\n" +"if (gl_FragColor.a < MASK)\n" +"discard;\n" +"#else\n" +"if (gl_FragColor.a >= MASK)\n" +"discard;\n" +"#endif\n" +"gl_FragColor.a = 1.0; //alpha blending AND alpha testing usually looks stupid, plus it screws up our fog.\n" +"#endif\n" + +//and finally hide it all if we're fogged. +"#ifdef FOG\n" +"gl_FragColor = fog4(gl_FragColor, length(inp.eyevector));\n" +"#endif\n" +"return gl_FragColor;\n" +"}\n" +"#endif\n" + +}, +#endif #ifdef D3D11QUAKE {QR_DIRECT3D11, 11, "defaultwall", "!!samps diffuse fullbright lightmap\n" diff --git a/engine/qclib/qcc.h b/engine/qclib/qcc.h index d93a3afc1..8cdee095e 100644 --- a/engine/qclib/qcc.h +++ b/engine/qclib/qcc.h @@ -774,6 +774,7 @@ enum { WARN_IMPLICITCONVERSION, WARN_EXTRAPRECACHE, WARN_NOTPRECACHED, + WARN_NONPORTABLEFILENAME, WARN_DEADCODE, WARN_UNREACHABLECODE, WARN_NOTSTANDARDBEHAVIOUR, diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index a65837ac1..bcc75dd55 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -4384,6 +4384,8 @@ void QCC_PrecacheSound (const char *n, int ch) precache_sound[i].block = ch; return; } + if (strchr(n, '\\')) + QCC_PR_ParseWarning(WARN_NONPORTABLEFILENAME, "backslashes in path names are non-portable - %s", n); if (numsounds == QCC_MAX_SOUNDS) return; // QCC_Error ("PrecacheSound: numsounds == MAX_SOUNDS"); @@ -4412,6 +4414,8 @@ void QCC_PrecacheModel (const char *n, int ch) } return; } + if (strchr(n, '\\')) + QCC_PR_ParseWarning(WARN_NONPORTABLEFILENAME, "backslashes in path names are non-portable - %s", n); if (nummodels == QCC_MAX_MODELS) return; // QCC_Error ("PrecacheModels: nummodels == MAX_MODELS"); @@ -4437,6 +4441,8 @@ void QCC_SetModel (const char *n) precache_model[i].used++; return; } + if (strchr(n, '\\')) + QCC_PR_ParseWarning(WARN_NONPORTABLEFILENAME, "backslashes in path names are non-portable - %s", n); if (nummodels == QCC_MAX_MODELS) return; strcpy (precache_model[i].name, n); @@ -4459,6 +4465,8 @@ void QCC_SoundUsed (const char *n) precache_sound[i].used++; return; } + if (strchr(n, '\\')) + QCC_PR_ParseWarning(WARN_NONPORTABLEFILENAME, "backslashes in path names are non-portable - %s", n); if (numsounds == QCC_MAX_SOUNDS) return; strcpy (precache_sound[i].name, n); @@ -4479,6 +4487,8 @@ void QCC_PrecacheTexture (const char *n, int ch) for (i=0 ; iname = (float *)PR_FindGlobal(svprogfuncs, #name, 0, NULL); if (need && !(pr_globals)->name) {static float fallback##name; (pr_globals)->name = &fallback##name; if (!muted) Con_DPrintf("Could not find \""#name"\" export in progs\n");} #define globalint(need,name) (pr_globals)->name = (int *)PR_FindGlobal(svprogfuncs, #name, 0, NULL); if (need && !(pr_globals)->name) {static int fallback##name; (pr_globals)->name = &fallback##name; if (!muted) Con_DPrintf("Could not find \""#name"\" export in progs\n");} #define globalstring(need,name) (pr_globals)->name = (int *)PR_FindGlobal(svprogfuncs, #name, 0, NULL); if (need && !(pr_globals)->name) {static string_t fallback##name; (pr_globals)->name = &fallback##name; if (!muted) Con_DPrintf("Could not find \""#name"\" export in progs\n");} diff --git a/engine/server/pr_lua.c b/engine/server/pr_lua.c index 52259a17e..7d78deefb 100644 --- a/engine/server/pr_lua.c +++ b/engine/server/pr_lua.c @@ -5,6 +5,8 @@ #include "pr_common.h" #include "hash.h" +#define LUA_MALLOC_TAG 0x55780128 + #define luagloballist \ globalentity (true, self) \ globalentity (true, other) \ @@ -83,7 +85,7 @@ luaextragloballist typedef struct { int type; - quintptr_t offset; + qintptr_t offset; char *name; bucket_t buck; } luafld_t; @@ -2218,7 +2220,7 @@ static int bi_lua_pairs (lua_State *L) { static int bi_lua_objerror (lua_State *L) { - SV_Error("objerror: %s\n", lua_tostring(L, 1)); + Con_Printf("\n"); lua_pushedict(L, lua.edicttable[lua.globals.self]); lua_pushnil(L); @@ -2230,11 +2232,11 @@ static int bi_lua_objerror (lua_State *L) { int i; const void *ud = lua_topointer(L, -2); - for (i = 0; i < countof(lua.entflds); i++) - if (lua.entflds[i].offset == (quintptr_t)ud) + for (i = 0; i < lua.numflds; i++) + if (lua.entflds[i].offset == (qintptr_t)ud) break; - if (i == countof(lua.entflds)) + if (i == lua.numflds) Con_Printf("%21s:", lua_typename(L, lua_type(L, -2))); else Con_Printf("%21s:", lua.entflds[i].name); @@ -2260,6 +2262,8 @@ static int bi_lua_objerror (lua_State *L) } lua_pop(L, 1); + + Con_Printf("objerror: %s\n", lua_tostring(L, 1)); return 0; } static int bi_lua_error (lua_State *L) @@ -2788,7 +2792,6 @@ static const char *Lua_ParseEdict (pubprogfuncs_t *progfuncs, const char *data, } */ cont: - fld = Hash_GetInsensitive(&lua.entityfields, keyname); if (fld && fld->type == ev_float) lua_pushnumber(L, atof(token)); @@ -2809,6 +2812,13 @@ cont: e++; lua_pushvector(L, x, y, z); } + else if (fld && fld->type == ev_function) + lua_getglobal(L, token); //functions are nameless, except for how they're invoked. so this is only for evil mods... + else if (fld && fld->type == ev_entity) + { + int num = atoi(token); + lua_pushedict(L, EDICT_NUM_UB((&lua.progfuncs), num)); + } else lua_pushstring(L, token); lua_setfield(L, -2, keyname); @@ -2942,7 +2952,7 @@ char *QDECL Lua_AddString(pubprogfuncs_t *prinst, const char *val, int minlength int len = strlen(val)+1; if (len < minlength) len = minlength; - ptr = Z_TagMalloc(len, 0x55780128); + ptr = Z_TagMalloc(len, LUA_MALLOC_TAG); strcpy(ptr, val); return ptr; } @@ -3215,6 +3225,8 @@ void PDECL Lua_CloseProgs(pubprogfuncs_t *inst) lua.maxedicts = 0; memset(&lua, 0, sizeof(lua)); + + Z_FreeTags(LUA_MALLOC_TAG); } static void QDECL Lua_Get_FrameState(world_t *w, wedict_t *ent, framestate_t *fstate) diff --git a/engine/server/savegame.c b/engine/server/savegame.c index 4b8884a81..ccae6b290 100644 --- a/engine/server/savegame.c +++ b/engine/server/savegame.c @@ -1413,7 +1413,7 @@ static int QDECL CompleteSaveList (const char *name, qofs_t flags, time_t mtime, if (l >= 9 && !Q_strcasecmp(trimmed+l-9, "/info.fsv")) { trimmed[l-9] = 0; - ctx->cb(trimmed, ctx); + ctx->cb(trimmed, NULL, NULL, ctx); } return true; } @@ -1422,7 +1422,7 @@ static int QDECL CompleteSaveListLegacy (const char *name, qofs_t flags, time_t struct xcommandargcompletioncb_s *ctx = parm; char stripped[64]; COM_StripExtension(name, stripped, sizeof(stripped)); - ctx->cb(stripped, ctx); + ctx->cb(stripped, NULL, NULL, ctx); return true; } void SV_Savegame_c(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx) diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index d55b0329c..9765394bf 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -411,7 +411,7 @@ static int QDECL CompleteMapList (const char *name, qofs_t flags, time_t mtime, return true; COM_StripExtension(name+5, stripped, sizeof(stripped)); - ctx->cb(stripped, ctx); + ctx->cb(stripped, NULL, NULL, ctx); return true; } static int QDECL CompleteMapListExt (const char *name, qofs_t flags, time_t mtime, void *parm, searchpathfuncs_t *spath) @@ -420,7 +420,7 @@ static int QDECL CompleteMapListExt (const char *name, qofs_t flags, time_t mtim if (name[5] == 'b' && name[6] == '_') //skip box models return true; - ctx->cb(name+5, ctx); + ctx->cb(name+5, NULL, NULL, ctx); return true; } static void SV_Map_c(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx) diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index d5af188a3..fb39e7334 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -132,7 +132,7 @@ cvar_t pext_ezquake_nochunks = CVARD("pext_ezquake_nochunks", "0", "Prevents ezq cvar_t sv_gamespeed = CVARAF("sv_gamespeed", "1", "slowmo", 0); cvar_t sv_csqcdebug = CVAR("sv_csqcdebug", "0"); cvar_t sv_csqc_progname = CVAR("sv_csqc_progname", "csprogs.dat"); -cvar_t pausable = CVAR("pausable", "1"); +cvar_t pausable = CVAR("pausable", ""); cvar_t sv_banproxies = CVARD("sv_banproxies", "0", "If enabled, anyone connecting via known proxy software will be refused entry. This should aid with blocking aimbots, but is only reliable for certain public proxies."); cvar_t sv_specprint = CVARD("sv_specprint", "3", "Bitfield that controls which player events spectators see when tracking that player.\n&1: spectators will see centerprints.\n&2: spectators will see sprints (pickup messages etc).\n&4: spectators will receive console commands, this is potentially risky.\nIndividual spectators can use 'setinfo sp foo' to limit this setting."); diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index 601213469..7f70efa7f 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -2225,7 +2225,7 @@ void WPhys_RunEntity (world_t *w, wedict_t *ent) else gravitydir = w->g.defaultgravitydir; - if (!WPhys_CheckWater (w, ent) && ! ((int)ent->v->flags & FL_WATERJUMP) ) + if (!WPhys_CheckWater (w, ent) && ! ((int)ent->v->flags & FL_WATERJUMP) ) //Vanilla Bug: the QC checks waterlevel inside PlayerPreThink, with waterlevel from a different position from the origin. WPhys_AddGravity (w, ent, gravitydir); WPhys_CheckStuck (w, ent); diff --git a/engine/server/sv_sys_unix.c b/engine/server/sv_sys_unix.c index 4d9a99ddc..7e8bd3b2a 100644 --- a/engine/server/sv_sys_unix.c +++ b/engine/server/sv_sys_unix.c @@ -728,7 +728,7 @@ static int Sys_CheckChRoot(void) const char *newhome; getresuid(&ruid, &euid, &suid); - printf("ruid %u, euid %u, suid %u\n", ruid, euid, suid); +// printf("ruid %u, euid %u, suid %u\n", ruid, euid, suid); if (!euid && ruid != euid) { //if we're running SUID-root then assume the admin set it up that way in order to use chroot without making any libraries available inside the jail. //however, chroot needs a certain level of sandboxing to prevent somehow running suid programs with eg a custom /etc/passwd, etc. @@ -775,7 +775,7 @@ static int Sys_CheckChRoot(void) //SSL_InitGlobal(true); //make sure we load our public cert from outside the sandbox. an exploit might still be able to find it in memory though. FIXME: disabled in case this reads from somewhere bad - we're still root. #endif - printf("Changing to root: \"%s\"\n", newroot); + printf("Changing root dir to \"%s\"\n", newroot); if (chroot(newroot)) { printf("chroot call failed\n"); diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index c41969d19..78e20654d 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -4007,7 +4007,12 @@ SV_Pause_f */ void SV_Pause_f (void) { - if (!pausable.value) + int maypause; + if (!*pausable.string) + maypause = !deathmatch.ival; + else + maypause = pausable.ival; + if (!maypause) { SV_ClientTPrintf (host_client, PRINT_HIGH, "Can't pause. Not allowed\n"); return; diff --git a/engine/shaders/glsl/defaultwall.glsl b/engine/shaders/glsl/defaultwall.glsl index c0412e2a6..5f5353056 100644 --- a/engine/shaders/glsl/defaultwall.glsl +++ b/engine/shaders/glsl/defaultwall.glsl @@ -352,6 +352,7 @@ void main () if (gl_FragColor.a >= MASK) discard; #endif + gl_FragColor.a = 1.0; //alpha blending AND alpha testing usually looks stupid, plus it screws up our fog. #endif //and finally hide it all if we're fogged. diff --git a/engine/shaders/vulkan/defaultwall.glsl b/engine/shaders/vulkan/defaultwall.glsl index 1d62d296e..28e63b817 100644 --- a/engine/shaders/vulkan/defaultwall.glsl +++ b/engine/shaders/vulkan/defaultwall.glsl @@ -200,6 +200,7 @@ void main () if (gl_FragColor.a >= arg_mask) discard; } + gl_FragColor.a = 1.0; } //and finally hide it all if we're fogged.