diff --git a/engine/client/cl_cam.c b/engine/client/cl_cam.c index 99cda1bb..50893606 100644 --- a/engine/client/cl_cam.c +++ b/engine/client/cl_cam.c @@ -47,6 +47,7 @@ char cl_spectatorgroup[] = "Spectator Tracking"; cvar_t cl_hightrack = SCVAR("cl_hightrack", "0"); cvar_t cl_chasecam = SCVAR("cl_chasecam", "1"); +cvar_t cl_selfcam = SCVAR("cl_selfcam", "1"); //cvar_t cl_camera_maxpitch = {"cl_camera_maxpitch", "10" }; //cvar_t cl_camera_maxyaw = {"cl_camera_maxyaw", "30" }; @@ -57,6 +58,8 @@ double cam_lastviewtime[MAX_SPLITS]; int spec_track[MAX_SPLITS]; // player# of who we are tracking int autocam[MAX_SPLITS]; +int selfcam=1; + void vectoangles(vec3_t vec, vec3_t ang) { float forward; @@ -72,12 +75,12 @@ void vectoangles(vec3_t vec, vec3_t ang) } else { - yaw = (int) (atan2(vec[1], vec[0]) * 180 / M_PI); + yaw = /*(int)*/ (atan2(vec[1], vec[0]) * 180 / M_PI); if (yaw < 0) yaw += 360; forward = sqrt (vec[0]*vec[0] + vec[1]*vec[1]); - pitch = (int) (atan2(vec[2], forward) * 180 / M_PI); + pitch = /*(int)*/ (atan2(vec[2], forward) * 180 / M_PI); if (pitch < 0) pitch += 360; } @@ -95,12 +98,18 @@ static float vlen(vec3_t v) // returns true if weapon model should be drawn in camera mode qboolean Cam_DrawViewModel(int pnum) { - if (!cl.spectator) - return true; - - if (autocam[pnum] && locked[pnum] && cl_chasecam.value) - return true; - return false; + if (cl.spectator) + { + if (autocam[pnum] && locked[pnum] && cl_chasecam.value) + return true; + return false; + } + else + { + if (selfcam == 1) + return true; + return false; + } } // returns true if we should draw this player, we don't if we are chase camming @@ -108,9 +117,18 @@ qboolean Cam_DrawPlayer(int pnum, int playernum) { // if (playernum == cl.playernum[pnum]) // return false; - if (cl.spectator && autocam[pnum] && locked[pnum] && (cl_chasecam.value||scr_chatmode==2) && - spec_track[pnum] == playernum && r_secondaryview != 2) - return false; + if (cl.spectator) + { + if (autocam[pnum] && locked[pnum] && (cl_chasecam.value||scr_chatmode==2) && + spec_track[pnum] == playernum && r_secondaryview != 2) + return false; + } + else + { + if (selfcam == 1) + if (playernum == (cl.viewentity[pnum]?cl.viewentity[pnum]-1:(cl.playernum[pnum]))) + return false; + } return true; } @@ -174,7 +192,7 @@ extern vec3_t player_mins; extern vec3_t player_maxs; // Returns distance or 9999 if invalid for some reason -static float Cam_TryFlyby(player_state_t *self, player_state_t *player, vec3_t vec, qboolean checkvis) +static float Cam_TryFlyby(vec3_t selforigin, vec3_t playerorigin, vec3_t vec, qboolean checkvis) { vec3_t v; trace_t trace; @@ -189,23 +207,23 @@ static float Cam_TryFlyby(player_state_t *self, player_state_t *player, vec3_t v // v[0] = -v[0]; VectorCopy (v, pmove.angles); VectorNormalize(vec); - VectorMA(player->origin, 800, vec, v); + VectorMA(playerorigin, 800, vec, v); // v is endpos // fake a player move - trace = Cam_DoTrace(player->origin, v); + trace = Cam_DoTrace(playerorigin, v); if (/*trace.inopen ||*/ trace.inwater) return 9999; VectorCopy(trace.endpos, vec); - VectorSubtract(trace.endpos, player->origin, v); + VectorSubtract(trace.endpos, playerorigin, v); len = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); if (len < 32 || len > 800) return 9999; if (checkvis) { - VectorSubtract(trace.endpos, self->origin, v); + VectorSubtract(trace.endpos, selforigin, v); len = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); - trace = Cam_DoTrace(self->origin, vec); + trace = Cam_DoTrace(selforigin, vec); if (trace.fraction != 1 || trace.inwater) return 9999; } @@ -213,30 +231,30 @@ static float Cam_TryFlyby(player_state_t *self, player_state_t *player, vec3_t v } // Is player visible? -static qboolean Cam_IsVisible(player_state_t *player, vec3_t vec) +static qboolean Cam_IsVisible(vec3_t playerorigin, vec3_t vec) { trace_t trace; vec3_t v; float d; - trace = Cam_DoTrace(player->origin, vec); + trace = Cam_DoTrace(playerorigin, vec); if (trace.fraction != 1 || /*trace.inopen ||*/ trace.inwater) return false; // check distance, don't let the player get too far away or too close - VectorSubtract(player->origin, vec, v); + VectorSubtract(playerorigin, vec, v); d = vlen(v); if (d < 16) return false; return true; } -static qboolean InitFlyby(int pnum, player_state_t *self, player_state_t *player, int checkvis) +static qboolean InitFlyby(int pnum, vec3_t selforigin, vec3_t playerorigin, vec3_t playerviewangles, int checkvis) { float f, max; vec3_t vec, vec2; vec3_t forward, right, up; - VectorCopy(player->viewangles, vec); + VectorCopy(playerviewangles, vec); vec[0] = 0; AngleVectors (vec, forward, right, up); // for (i = 0; i < 3; i++) @@ -245,78 +263,78 @@ static qboolean InitFlyby(int pnum, player_state_t *self, player_state_t *player max = 1000; VectorAdd(forward, up, vec2); VectorAdd(vec2, right, vec2); - if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max) + if ((f = Cam_TryFlyby(selforigin, playerorigin, vec2, checkvis)) < max) { max = f; VectorCopy(vec2, vec); } VectorAdd(forward, up, vec2); VectorSubtract(vec2, right, vec2); - if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max) + if ((f = Cam_TryFlyby(selforigin, playerorigin, vec2, checkvis)) < max) { max = f; VectorCopy(vec2, vec); } VectorAdd(forward, right, vec2); - if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max) + if ((f = Cam_TryFlyby(selforigin, playerorigin, vec2, checkvis)) < max) { max = f; VectorCopy(vec2, vec); } VectorSubtract(forward, right, vec2); - if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max) + if ((f = Cam_TryFlyby(selforigin, playerorigin, vec2, checkvis)) < max) { max = f; VectorCopy(vec2, vec); } VectorAdd(forward, up, vec2); - if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max) + if ((f = Cam_TryFlyby(selforigin, playerorigin, vec2, checkvis)) < max) { max = f; VectorCopy(vec2, vec); } VectorSubtract(forward, up, vec2); - if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max) + if ((f = Cam_TryFlyby(selforigin, playerorigin, vec2, checkvis)) < max) { max = f; VectorCopy(vec2, vec); } VectorAdd(up, right, vec2); VectorSubtract(vec2, forward, vec2); - if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max) + if ((f = Cam_TryFlyby(selforigin, playerorigin, vec2, checkvis)) < max) { max = f; VectorCopy(vec2, vec); } VectorSubtract(up, right, vec2); VectorSubtract(vec2, forward, vec2); - if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max) + if ((f = Cam_TryFlyby(selforigin, playerorigin, vec2, checkvis)) < max) { max = f; VectorCopy(vec2, vec); } // invert VectorNegate(forward, vec2); - if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max) + if ((f = Cam_TryFlyby(selforigin, playerorigin, vec2, checkvis)) < max) { max = f; VectorCopy(vec2, vec); } VectorCopy(forward, vec2); - if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max) + if ((f = Cam_TryFlyby(selforigin, playerorigin, vec2, checkvis)) < max) { max = f; VectorCopy(vec2, vec); } // invert VectorNegate(right, vec2); - if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max) + if ((f = Cam_TryFlyby(selforigin, playerorigin, vec2, checkvis)) < max) { max = f; VectorCopy(vec2, vec); } VectorCopy(right, vec2); - if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max) + if ((f = Cam_TryFlyby(selforigin, playerorigin, vec2, checkvis)) < max) { max = f; VectorCopy(vec2, vec); @@ -358,6 +376,57 @@ static void Cam_CheckHighTarget(int pnum) Cam_Unlock(pnum); } +void Cam_SelfTrack(int pnum) +{ + vec3_t vec; + if (!cl.worldmodel || cl.worldmodel->needload) + return; + + if (selfcam == 1) + { //view-from-eyes + } + else + { + if (selfcam == 2) + { //fixme: + vec3_t forward, right, up; + trace_t tr; + AngleVectors(r_refdef.viewangles, forward, right, up); + VectorMA(cl.simorg[pnum], -128, forward, desired_position[pnum]); + tr = Cam_DoTrace(cl.simorg[pnum], desired_position[pnum]); + VectorCopy(tr.endpos, desired_position[pnum]); + } + else + { //view from a random wall + if (!locked[pnum] || !Cam_IsVisible(cl.simorg[pnum], desired_position[pnum])) + { + if (!locked[pnum] || realtime - cam_lastviewtime[pnum] > 0.1) + { + if (!InitFlyby(pnum, desired_position[pnum], cl.simorg[pnum], cl.simangles[pnum], true)) + InitFlyby(pnum, desired_position[pnum], cl.simorg[pnum], cl.simangles[pnum], false); + cam_lastviewtime[pnum] = realtime; + } + } + else + { + cam_lastviewtime[pnum] = realtime; + } + + //tracking failed. + if (!locked[pnum]) + return; + } + + + // move there locally immediately + VectorCopy(desired_position[pnum], r_refdef.vieworg); + + VectorSubtract(cl.simorg[pnum], desired_position[pnum], vec); + vectoangles(vec, r_refdef.viewangles); + r_refdef.viewangles[0] = -r_refdef.viewangles[0]; + } +} + // ZOID // // Take over the user controls and track a player. @@ -392,12 +461,12 @@ void Cam_Track(int pnum, usercmd_t *cmd) player = frame->playerstate + spec_track[pnum]; self = frame->playerstate + cl.playernum[pnum]; - if (!locked[pnum] || !Cam_IsVisible(player, desired_position[pnum])) + if (!locked[pnum] || !Cam_IsVisible(player->origin, desired_position[pnum])) { if (!locked[pnum] || realtime - cam_lastviewtime[pnum] > 0.1) { - if (!InitFlyby(pnum, self, player, true)) - InitFlyby(pnum, self, player, false); + if (!InitFlyby(pnum, self->origin, player->origin, player->viewangles, true)) + InitFlyby(pnum, self->origin, player->origin, player->viewangles, false); cam_lastviewtime[pnum] = realtime; } } @@ -737,6 +806,7 @@ void CL_InitCam(void) Cvar_Register (&cl_chasecam, cl_spectatorgroup); // Cvar_Register (&cl_camera_maxpitch, cl_spectatorgroup); // Cvar_Register (&cl_camera_maxyaw, cl_spectatorgroup); +// Cvar_Register (&cl_selfcam, cl_spectatorgroup); Cmd_AddCommand("track", Cam_Track_f); Cmd_AddCommand("track1", Cam_Track1_f); diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index dd716730..e24bfd1c 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -147,7 +147,7 @@ void CL_WriteDemoMessage (sizebuf_t *msg) VFS_FLUSH (cls.demofile); } -unsigned char unreaddata[16]; +unsigned char unreaddata[4096]; int unreadcount; int readdemobytes(void *data, int len) { @@ -159,9 +159,17 @@ int readdemobytes(void *data, int len) if (unreadcount) { if (len > unreadcount) - Sys_Error("Demo playback unread the wrong number of bytes\n"); + { + //this can only happen when the remaining 'unread' buffer from the initial qtv stream is part-way used up. + i = VFS_READ(cls.demofile, unreaddata+unreadcount, len - unreadcount); + unreadcount += i; + + if (len > unreadcount) + return 0; + } unreadcount -= len; - memcpy(data, unreaddata+unreadcount, len); + memcpy(data, unreaddata, len); + memmove(unreaddata, unreaddata+len, unreadcount); return len; } @@ -170,7 +178,8 @@ int readdemobytes(void *data, int len) } void unreadbytes(int count, void *data) { - memcpy(unreaddata+unreadcount, data, count); + memmove(unreaddata+count, unreaddata, unreadcount); + memcpy(unreaddata, data, count); unreadcount += count; } @@ -1373,8 +1382,210 @@ void CL_PlayDemo(char *demoname) TP_ExecTrigger ("f_demostart"); } +void CL_QTVPlay (vfsfile_t *newf) +{ + CL_Disconnect_f (); + + cls.demofile = newf; + + unreadcount = 0; //just in case + + cls.demoplayback = DPB_MVD; + cls.findtrack = true; + + cls.state = ca_demostart; + net_message.packing = SZ_RAWBYTES; + Netchan_Setup (NS_CLIENT, &cls.netchan, net_from, 0); + realtime = -10; + cl.gametime = -10; + cl.gametimemark = realtime; + + Con_Printf("Buffering for ten seconds\n"); + + cls.netchan.last_received=realtime; + + cls.protocol = CP_QUAKEWORLD; + TP_ExecTrigger ("f_demostart"); +} + +char qtvrequestbuffer[4096]; +int qtvrequestsize; +vfsfile_t *qtvrequest; + +void CL_QTVPoll (void) +{ + char *s, *e, *colon; + int len; + qboolean error = false; + + if (!qtvrequest) + return; + + for(;;) + { + len = VFS_READ(qtvrequest, qtvrequestbuffer+qtvrequestsize, (sizeof(qtvrequestbuffer) - qtvrequestsize -1 > 0)?1:0); + if (len <= 0) + break; + qtvrequestsize += len; + } + qtvrequestbuffer[qtvrequestsize] = '\0'; + if (!qtvrequestsize) + return; + + //make sure it's a compleate chunk. + for (s = qtvrequestbuffer; *s; s++) + { + if (s[0] == '\n' && s[1] == '\n') + break; + } + if (!*s) + return; + s = qtvrequestbuffer; + for (e = s; *e; ) + { + if (*e == '\n') + { + *e = '\0'; + colon = strchr(s, ':'); + if (colon) + { + *colon++ = '\0'; + if (!strcmp(s, "PERROR")) + { //printable error + Con_Printf("QTV:\n%s\n", colon); + error = true; + } + else if (!strcmp(s, "ADEMO")) + { //printable error + Con_Printf("Demo%s is available\n", colon); + error = true; //not really an error, but meh + } + else if (!strcmp(s, "ASOURCE")) + { //printable error + Con_Printf("Source%s is available\n", colon); + error = true; + } + } + else + { + } + //from e to s, we have a line + s = e+1; + } + e++; + } + + if (!error) + { + CL_QTVPlay(qtvrequest); + qtvrequest = NULL; + unreadbytes(qtvrequestsize - (e-qtvrequestbuffer), e); + return; + } + + VFS_CLOSE(qtvrequest); + qtvrequest = NULL; + qtvrequestsize = 0; +} + void CL_QTVPlay_f (void) { + qboolean raw=0; + char *connrequest; + vfsfile_t *newf; + char *host; + + connrequest = Cmd_Argv(1); + + if (*connrequest == '#') + { + char buffer[1024]; + char *s; + FILE *f; + f = fopen(connrequest+1, "rt"); + if (!f) + return; + while (!feof(f)) + { + fgets(buffer, sizeof(buffer)-1, f); + if (!strncmp(buffer, "Stream=", 7) || !strncmp(buffer, "Stream:", 7)) + { + for (s = buffer + strlen(buffer)-1; s >= buffer; s--) + { + if (*s == '\r' || *s == '\n') + *s = 0; + else + break; + } + s = buffer+8; + while(*s && *s <= ' ') + s++; + Cbuf_AddText(va("qtvplay \"%s\"\n", s), Cmd_ExecLevel); + break; + } + } + fclose(f); + return; + } + + host = connrequest; + + connrequest = strchr(connrequest, '@'); + if (connrequest) + host = connrequest+1; + newf = FS_OpenTCP(host); + + if (!newf) + { + Con_Printf("Couldn't connect to proxy\n"); + return; + } + + host = connrequest = Cmd_Argv(1); + connrequest = strchr(connrequest, '@'); + if (connrequest) + *connrequest = '\0'; + else + host = NULL; + + connrequest = "QTV\n" + "VERSION: 1\n"; + VFS_WRITE(newf, connrequest, strlen(connrequest)); + if (raw) + { + connrequest = "RAW: 1\n"; + VFS_WRITE(newf, connrequest, strlen(connrequest)); + } + if (host) + { + connrequest = "SOURCE: "; + VFS_WRITE(newf, connrequest, strlen(connrequest)); + connrequest = host; + VFS_WRITE(newf, connrequest, strlen(connrequest)); + connrequest = "\n"; + } + + VFS_WRITE(newf, connrequest, strlen(connrequest)); + connrequest = "\n"; + VFS_WRITE(newf, connrequest, strlen(connrequest)); + + if (raw) + { + CL_QTVPlay(newf); + } + else + { + if (qtvrequest) + VFS_CLOSE(qtvrequest); + qtvrequest = newf; + qtvrequestsize = 0; + } +} + +/* +void CL_QTVPlay_f (void) +{ + char *connrequest; vfsfile_t *newf; newf = FS_OpenTCP(Cmd_Argv(1)); @@ -1384,6 +1595,15 @@ void CL_QTVPlay_f (void) return; } + connrequest = "QTV\n" + "VERSION: 1\n" + "RAW: 1\n"; + VFS_WRITE(newf, connrequest, strlen(connrequest)); + connrequest = "SOURCE: file:test.mvd\n"; + VFS_WRITE(newf, connrequest, strlen(connrequest)); + connrequest = "\n"; + VFS_WRITE(newf, connrequest, strlen(connrequest)); + CL_Disconnect_f (); cls.demofile = newf; @@ -1407,6 +1627,57 @@ void CL_QTVPlay_f (void) cls.protocol = CP_QUAKEWORLD; TP_ExecTrigger ("f_demostart"); } +*/ + +void CL_QTVList_f (void) +{ + char *connrequest; + vfsfile_t *newf; + newf = FS_OpenTCP(Cmd_Argv(1)); + + if (!newf) + { + Con_Printf("Couldn't connect to proxy\n"); + return; + } + + connrequest = "QTV\n" + "VERSION: 1\n"; + VFS_WRITE(newf, connrequest, strlen(connrequest)); + connrequest = "SOURCELIST\n"; + VFS_WRITE(newf, connrequest, strlen(connrequest)); + connrequest = "\n"; + VFS_WRITE(newf, connrequest, strlen(connrequest)); + + if (qtvrequest) + VFS_CLOSE(qtvrequest); + qtvrequest = newf; + qtvrequestsize = 0; + + /* + CL_Disconnect_f (); + + cls.demofile = newf; + + unreadcount = 0; //just in case + + cls.demoplayback = DPB_MVD; + cls.findtrack = true; + + cls.state = ca_demostart; + net_message.packing = SZ_RAWBYTES; + Netchan_Setup (NS_CLIENT, &cls.netchan, net_from, 0); + realtime = 0; + cl.gametime = 0; + cl.gametimemark = realtime; + + Con_Printf("Querying proxy\n"); + + cls.netchan.last_received=realtime; + + cls.protocol = CP_QUAKEWORLD; + TP_ExecTrigger ("f_demostart");*/ +} /* ==================== diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index bd39f5c1..31217486 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -1179,7 +1179,7 @@ void CL_SendCmd (float frametime) } // if we are spectator, try autocam - if (cl.spectator) + // if (cl.spectator) Cam_Track(plnum, &independantphysics[plnum]); Cam_FinishMove(plnum, &independantphysics[plnum]); independantphysics[plnum].msec = msecstouse; diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index c2fcd1d1..53fd759b 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -28,7 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "cl_ignore.h" #if defined(_WIN32) && !defined(MINGW) && defined(RGLQUAKE) -#define WINAVI +//#define WINAVI #endif // callbacks @@ -1659,6 +1659,7 @@ void CL_Packet_f (void) return; } + if (Cmd_FromGamecode()) //some mvd servers stuffcmd a packet command which lets them know which ip the client is from. { //unfortunatly, 50% of servers are badly configured. if (adr.type == NA_IP) @@ -1708,6 +1709,14 @@ void CL_Packet_f (void) #else NET_SendPacket (NS_CLIENT, out-send, send, adr); #endif + + + if (Cmd_FromGamecode()) + { + //realip + Cmd_TokenizeString(in, false, false); + cls.realip_ident = atoi(Cmd_Argv(2)); + } } @@ -1826,10 +1835,14 @@ drop to full console */ void CL_Changing_f (void) { + char *mapname = Cmd_Argv(1); if (cls.downloadqw) // don't change when downloading return; - SCR_BeginLoadingPlaque(); + if (*mapname) + SCR_ImageName(mapname); + else + SCR_BeginLoadingPlaque(); S_StopAllSounds (true); cl.intermission = 0; @@ -1907,6 +1920,36 @@ void CL_ConnectionlessPacket (void) c = MSG_ReadByte (); + // ping from somewhere + if (c == A2A_PING) + { + char data[256]; + + data[0] = 0xff; + data[1] = 0xff; + data[2] = 0xff; + data[3] = 0xff; + data[4] = A2A_ACK; + data[5] = 0; + + if (!cls.state || !NET_CompareAdr(cls.netchan.remote_address, net_from)) + { + Con_TPrintf (TL_ST_COLON, NET_AdrToString (net_from)); + Con_TPrintf (TLC_A2A_PING); + } + else + { + //ack needs two parameters to work with realip properly. + //firstly it needs an auth message, so it can't be spoofed. + //secondly, it needs a copy of the realip ident, so you can't report a different player's client (you would need access to thier ip). + data[5] = ' '; + sprintf(data+6, "%i %i", atoi(MSG_ReadString()), cls.realip_ident); + } + + NET_SendPacket (NS_CLIENT, 6, &data, net_from); + return; + } + if (cls.demoplayback == DPB_NONE) Con_TPrintf (TL_ST_COLON, NET_AdrToString (net_from)); // Con_DPrintf ("%s", net_message.data + 4); @@ -2196,25 +2239,6 @@ client_connect: //fixme: make function return; } - - // ping from somewhere - if (c == A2A_PING) - { - char data[6]; - - Con_TPrintf (TLC_A2A_PING); - - data[0] = 0xff; - data[1] = 0xff; - data[2] = 0xff; - data[3] = 0xff; - data[4] = A2A_ACK; - data[5] = 0; - - NET_SendPacket (NS_CLIENT, 6, &data, net_from); - return; - } - //happens in demos if (c == svc_disconnect && cls.demoplayback != DPB_NONE) { @@ -2802,7 +2826,8 @@ void CL_Init (void) Cmd_AddCommand ("rerecord", CL_ReRecord_f); Cmd_AddCommand ("stop", CL_Stop_f); Cmd_AddCommand ("playdemo", CL_PlayDemo_f); - Cmd_AddCommand ("playqtv", CL_QTVPlay_f); + Cmd_AddCommand ("qtvplay", CL_QTVPlay_f); + Cmd_AddCommand ("qtvlist", CL_QTVList_f); Cmd_AddCommand ("demo_jump", CL_DemoJump_f); Cmd_AddCommand ("timedemo", CL_TimeDemo_f); @@ -3014,7 +3039,7 @@ Runs all active servers */ #if defined(WINAVI) && !defined(NOMEDIA) extern float recordavi_frametime; -extern qboolean recordingdemo; +qboolean Media_Capturing(); #endif extern cvar_t cl_netfps; @@ -3039,7 +3064,7 @@ void Host_Frame (double time) realframetime = time; #if defined(WINAVI) && !defined(NOMEDIA) - if (cls.demoplayback && recordingdemo && recordavi_frametime>0.01) + if (cls.demoplayback && Media_Capturing() && recordavi_frametime>0.01) { realframetime = time = recordavi_frametime; } @@ -3053,6 +3078,7 @@ void Host_Frame (double time) SV_Frame(); RSpeedEnd(RSPEED_SERVER); #endif + if (cl.gamespeed<0.1) cl.gamespeed = 1; time *= cl.gamespeed; @@ -3232,6 +3258,9 @@ void Host_Frame (double time) Cbuf_Execute (); CL_RequestNextDownload(); + + + CL_QTVPoll(); } static void simple_crypt(char *buf, int len) diff --git a/engine/client/cl_master.h b/engine/client/cl_master.h index 69e7f227..953966d7 100644 --- a/engine/client/cl_master.h +++ b/engine/client/cl_master.h @@ -6,7 +6,7 @@ #define SS_KEEPINFO 16 #define SS_DARKPLACES 32 #define SS_QUAKE3 64 -#define SS_QTV 128 +#define SS_PROXY 128 //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. diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index d71b215d..06d26a84 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -2760,11 +2760,11 @@ void CL_NewTranslation (int slot) #ifdef RGLQUAKE if (qrenderer == QR_OPENGL) { //gl doesn't need to do anything except prevent the sys_error below. + return; } - else #endif #ifdef SWQUAKE - if (qrenderer == QR_SOFTWARE) + if (qrenderer == QR_SOFTWARE) { top = player->topcolor; bottom = player->bottomcolor; @@ -2806,10 +2806,9 @@ void CL_NewTranslation (int slot) D_DereferenceRemap(player->palremap); player->palremap = D_GetPaletteRemap(255, 255, 255, false, true, top, bottom); } + return; } - else #endif - Sys_Error("Bad rendering method in CL_NewTranslation"); } /* diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index c7358f00..fd6d5bb8 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -695,6 +695,8 @@ void CL_PredictMovePNum (int pnum) #ifdef Q2CLIENT if (cls.protocol == CP_QUAKE2) { + if (!cl.worldmodel || cl.worldmodel->needload) + return; cl.crouch[pnum] = 0; CLQ2_PredictMovement(); return; diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index 3805174f..78e753b8 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -1372,7 +1372,7 @@ void SCR_DrawLoading (void) } if (COM_FDepthFile("gfx/loading.lmp", true) < COM_FDepthFile("gfx/menu/loading.lmp", true)) - { + { //quake files int sizex, x, y; pic = Draw_SafeCachePic ("gfx/loading.lmp"); @@ -1410,7 +1410,7 @@ void SCR_DrawLoading (void) } } else - { + { //hexen2 files pic = Draw_SafeCachePic ("gfx/menu/loading.lmp"); if (pic) { @@ -1449,6 +1449,9 @@ void SCR_DrawLoading (void) Draw_Fill (offset+42, 97+5, count, 1, 168); } } + + SCR_SetUpToDrawConsole(); + SCR_DrawConsole(!!*levelshotname); } void SCR_BeginLoadingPlaque (void) @@ -1513,6 +1516,7 @@ void SCR_ImageName (char *mapname) GL_EndRendering(); scr_drawloading = false; + scr_disabled_time = Sys_DoubleTime(); //realtime tends to change... Hmmm.... scr_disabled_for_loading = true; #endif @@ -1540,42 +1544,45 @@ void SCR_SetUpToDrawConsole (void) return; // never a console with loading plaque // decide on the height of the console - if (cls.state != ca_active && !Media_PlayingFullScreen() -#ifdef TEXTEDITOR - && !editoractive -#endif -#ifdef VM_UI - && !UI_MenuState() -#endif - ) + if (!scr_disabled_for_loading) { - scr_conlines = vid.height; // full screen - scr_con_current = scr_conlines; - scr_con_forcedraw = true; - } - else if (key_dest == key_console || scr_chatmode) - { - scr_conlines = vid.height*scr_consize.value; // half screen - if (scr_conlines < 32) - scr_conlines = 32; //prevent total loss of console. - else if (scr_conlines>vid.height) - scr_conlines = vid.height; - } - else - scr_conlines = 0; // none visible - - if (scr_conlines < scr_con_current) - { - scr_con_current -= scr_conspeed.value*host_frametime; - if (scr_conlines > scr_con_current) + if (cls.state != ca_active && !Media_PlayingFullScreen() + #ifdef TEXTEDITOR + && !editoractive + #endif + #ifdef VM_UI + && !UI_MenuState() + #endif + ) + { + scr_conlines = vid.height; // full screen scr_con_current = scr_conlines; + scr_con_forcedraw = true; + } + else if (key_dest == key_console || scr_chatmode) + { + scr_conlines = vid.height*scr_consize.value; // half screen + if (scr_conlines < 32) + scr_conlines = 32; //prevent total loss of console. + else if (scr_conlines>vid.height) + scr_conlines = vid.height; + } + else + scr_conlines = 0; // none visible - } - else if (scr_conlines > scr_con_current) - { - scr_con_current += scr_conspeed.value*host_frametime; if (scr_conlines < scr_con_current) - scr_con_current = scr_conlines; + { + scr_con_current -= scr_conspeed.value*host_frametime; + if (scr_conlines > scr_con_current) + scr_con_current = scr_conlines; + + } + else if (scr_conlines > scr_con_current) + { + scr_con_current += scr_conspeed.value*host_frametime; + if (scr_conlines < scr_con_current) + scr_con_current = scr_conlines; + } } if (scr_con_current>vid.height) diff --git a/engine/client/cl_ui.c b/engine/client/cl_ui.c index 9be98185..53470ccf 100644 --- a/engine/client/cl_ui.c +++ b/engine/client/cl_ui.c @@ -1679,10 +1679,18 @@ qboolean UI_KeyPress(int key, qboolean down) { if (key == K_ESCAPE && down) { + if (Media_PlayingFullScreen()) + { + Media_PlayFilm(""); + } + if (cls.state) - return VM_Call(uivm, UI_SET_ACTIVE_MENU, 2)>0; + VM_Call(uivm, UI_SET_ACTIVE_MENU, 2)>0; else - return VM_Call(uivm, UI_SET_ACTIVE_MENU, 1)>0; + VM_Call(uivm, UI_SET_ACTIVE_MENU, 1)>0; + + scr_conlines = 0; + return true; } return false; } @@ -1693,12 +1701,12 @@ qboolean UI_KeyPress(int key, qboolean down) key |= 1024; /*result = */VM_Call(uivm, UI_KEY_EVENT, key, down); - +/* if (!keycatcher && !cls.state && key == K_ESCAPE && down) { M_Menu_Main_f(); return true; - } + }*/ return true; diff --git a/engine/client/client.h b/engine/client/client.h index 0c975233..8d24865b 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -306,6 +306,8 @@ typedef struct int framecount; + int realip_ident; + // network stuff netchan_t netchan; float lastarbiatarypackettime; //used to mark when packets were sent to prevent mvdsv servers from causing us to disconnect. @@ -751,6 +753,7 @@ void CL_Record_f (void); void CL_ReRecord_f (void); void CL_PlayDemo_f (void); void CL_QTVPlay_f (void); +void CL_QTVList_f (void); void CL_DemoJump_f(void); void CL_ProgressDemoTime(void); void CL_TimeDemo_f (void); diff --git a/engine/client/m_master.c b/engine/client/m_master.c index 76509993..6b8ac2ea 100644 --- a/engine/client/m_master.c +++ b/engine/client/m_master.c @@ -407,7 +407,7 @@ void M_DrawServerList(void) colour = COLOR_BLUE; else if (server->special & SS_NETQUAKE) colour = COLOR_GREY; - else if (server->special & SS_QTV) + else if (server->special & SS_PROXY) colour = COLOR_MAGENTA; else colour = COLOR_WHITE; @@ -982,7 +982,8 @@ typedef enum { ST_QUAKE2, ST_QUAKE3, ST_NETQUAKE, - ST_FTEQTV, + ST_QTV, + ST_PROXY, ST_FAVORITE, MAX_SERVERTYPES } servertypes_t; @@ -1001,6 +1002,8 @@ float serverbackcolor[MAX_SERVERTYPES * 2][3] = {0.24, 0.16, 0.04}, {0.10, 0.05, 0.10}, // FTEQTV {0.20, 0.10, 0.20}, + {0.10, 0.05, 0.10}, // qizmo + {0.20, 0.10, 0.20}, {0.01, 0.13, 0.13}, // Favorite {0.02, 0.26, 0.26} }; @@ -1013,6 +1016,7 @@ float serverhighlight[MAX_SERVERTYPES][3] = {0.20, 0.20, 0.60}, // Quake 3 {0.40, 0.40, 0.25}, // NetQuake {0.45, 0.20, 0.45}, // FTEQTV + {0.45, 0.20, 0.45}, // qizmo {0.10, 0.60, 0.60} // Favorite }; @@ -1020,8 +1024,13 @@ servertypes_t flagstoservertype(int flags) { if (flags & SS_FAVORITE) return ST_FAVORITE; - if (flags & SS_QTV) - return ST_FTEQTV; + if (flags & SS_PROXY) + { + if (flags & SS_FTESERVER) + return ST_QTV; + else + return ST_PROXY; + } if (flags & SS_FTESERVER) return ST_FTESERVER; if ((flags & SS_NETQUAKE) || (flags & SS_DARKPLACES)) @@ -1055,6 +1064,10 @@ void SL_ServerDraw (int x, int y, menucustom_t *ths, menu_t *menu) } else if (thisone == info->scrollpos + (mousecursor_y-16)/8 && mousecursor_x < x) Draw_FillRGB(0, y, ths->common.width, 8, (sin(realtime*4.4)*0.25)+0.5, (sin(realtime*4.4)*0.25)+0.5, 0.08); + else if (selectedserver.inuse && NET_CompareAdr(si->adr, selectedserver.adr)) + { + Draw_FillRGB(0, y, ths->common.width, 8, ((sin(realtime*4.4)*0.25)+0.5) * 0.5, ((sin(realtime*4.4)*0.25)+0.5)*0.5, 0.08*0.5); + } else { Draw_FillRGB(0, y, ths->common.width, 8, @@ -1088,9 +1101,15 @@ qboolean SL_ServerKey (menucustom_t *ths, menu_t *menu, int key) oldselection = info->selectedpos; info->selectedpos = info->scrollpos + (mousecursor_y-16)/8; server = Master_SortedServer(info->selectedpos); + +// selectedserver.inuse = true; +// SListOptionChanged(server); + if (server) { snprintf(info->mappic->picturename, 32, "levelshots/%s", server->map); + if (!Draw_SafeCachePic(info->mappic->picturename)) + snprintf(info->mappic->picturename, 32, "levelshots/nomap"); } else { @@ -1185,9 +1204,15 @@ qboolean SL_Key (int key, menu_t *menu) { serverinfo_t *server; server = Master_SortedServer(info->selectedpos); + +// selectedserver.inuse = true; +// SListOptionChanged(server); + if (server) { snprintf(info->mappic->picturename, 32, "levelshots/%s", server->map); + if (!Draw_SafeCachePic(info->mappic->picturename)) + snprintf(info->mappic->picturename, 32, "levelshots/nomap"); } else { @@ -1207,6 +1232,23 @@ qboolean SL_Key (int key, menu_t *menu) return true; } +void SL_ServerPlayer (int x, int y, menucustom_t *ths, menu_t *menu) +{ + if (selectedserver.inuse) + { + if (selectedserver.detail) + if ((int)ths->data < selectedserver.detail->numplayers) + { + int i = (int)ths->data; + Draw_Fill (x, y, 28, 4, Sbar_ColorForMap(selectedserver.detail->players[i].topc)); + Draw_Fill (x, y+4, 28, 4, Sbar_ColorForMap(selectedserver.detail->players[i].botc)); + NM_PrintWhite (x, y, va("%3i", selectedserver.detail->players[i].frags)); + + Draw_FunStringLen (x+28, y, selectedserver.detail->players[i].name, 12); + } + } +} + void SL_SliderDraw (int x, int y, menucustom_t *ths, menu_t *menu) { serverlist_t *info = (serverlist_t*)(menu + 1); @@ -1368,7 +1410,7 @@ qboolean SL_DoRefresh (menuoption_t *opt, menu_t *menu, int key) void M_Menu_ServerList2_f(void) { - int i, y; + int i, y, x; menu_t *menu; menucustom_t *cust; serverlist_t *info; @@ -1412,6 +1454,19 @@ void M_Menu_ServerList2_f(void) } menu->dontexpand = true; + i = 0; + for (x = 256; x < vid.width-64; x += 128) + { + for (y = vid.height-64+8; y < vid.height; y += 8, i++) + { + cust = MC_AddCustom(menu, x+16, y, (void*)i); + cust->draw = SL_ServerPlayer; + cust->key = NULL; + cust->common.height = 8; + cust->common.width = 0; + } + } + MC_AddCheckBox(menu, 0, vid.height - 64+8*1, "Ping ", &sb_showping, 1); MC_AddCheckBox(menu, 0, vid.height - 64+8*2, "Address ", &sb_showaddress, 1); MC_AddCheckBox(menu, 0, vid.height - 64+8*3, "Map ", &sb_showmap, 1); diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index 272b87d2..c2d2a8e1 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -767,7 +767,7 @@ char *Media_NextTrack(void) //Avi files are specific to windows. Bit of a bummer really. #if defined(_WIN32) && !defined(__GNUC__) -#define WINAVI +//#define WINAVI #endif @@ -1447,7 +1447,8 @@ void Media_PlayFilm_f (void) -#if defined(RGLQUAKE) && defined(WINAVI) +#if defined(RGLQUAKE) +#if defined(WINAVI) #define WINAVIRECORDING PAVIFILE recordavi_file; #define recordavi_video_stream (recordavi_codec_fourcc?recordavi_compressed_video_stream:recordavi_uncompressed_video_stream) @@ -1456,6 +1457,9 @@ PAVISTREAM recordavi_compressed_video_stream; PAVISTREAM recordavi_uncompressed_audio_stream; WAVEFORMATEX recordavi_wave_format; unsigned long recordavi_codec_fourcc; +#endif + +soundcardinfo_t *capture_fakesounddevice; int recordavi_video_frame_counter; int recordavi_audio_frame_counter; float recordavi_frametime; @@ -1464,12 +1468,19 @@ float recordavi_audiotime; int capturesize; int capturewidth; char *capturevideomem; -short *captureaudiomem; +//short *captureaudiomem; int captureaudiosamples; -captureframe; +int captureframe; +qboolean capturepaused; cvar_t capturerate = SCVAR("capturerate", "15"); +#if defined(WINAVI) cvar_t capturecodec = SCVAR("capturecodec", "divx"); +#else +cvar_t capturecodec = SCVAR("capturecodec", "tga"); +#endif cvar_t capturesound = SCVAR("capturesound", "1"); +cvar_t capturesoundchannels = SCVAR("capturesoundchannels", "1"); +cvar_t capturesoundbits = SCVAR("capturesoundbits", "8"); cvar_t capturemessage = SCVAR("capturemessage", ""); qboolean recordingdemo; enum { @@ -1479,28 +1490,47 @@ enum { } capturetype; char capturefilenameprefix[MAX_QPATH]; +qboolean Media_Capturing (void) +{ + if (!capturetype) + return false; + return true; +} + +void Media_CapturePause_f (void) +{ + capturepaused = !capturepaused; +} + qboolean Media_PausedDemo (void) { //capturedemo doesn't record any frames when the console is visible //but that's okay, as we don't load any demo frames either. - if (recordingdemo) - if (scr_con_current > 0 || !cl.validsequence) + if (cls.demoplayback && Media_Capturing() || capturepaused) + if (scr_con_current > 0 || !cl.validsequence || capturepaused) return true; return false; } void Media_RecordFrame (void) { - HRESULT hr; - char *framebuffer = capturevideomem; - qbyte temp; - int i, c; - if (!capturetype) return; if (Media_PausedDemo()) + { + int y = vid.height -32-16; + if (y < scr_con_current) y = scr_con_current; + if (y > vid.height-8) + y = vid.height-8; + qglColor4f(1, 0, 0, sin(realtime*4)/4+0.75); + qglEnable(GL_BLEND); + qglDisable(GL_ALPHA_TEST); + GL_TexEnv(GL_MODULATE); + qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + Draw_String((strlen(capturemessage.string)+1)*8, y, "PAUSED"); return; + } if (cls.findtrack) return; //skip until we're tracking the right player. @@ -1532,23 +1562,36 @@ void Media_RecordFrame (void) switch (capturetype) { +#if defined(WINAVI) case CT_AVI: - //ask gl for it - qglReadPixels (glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE, framebuffer ); - - // swap rgb to bgr - c = glwidth*glheight*3; - for (i=0 ; i 0) - { - return; - } - - if (captureaudiosamples > recordavi_wave_format.nSamplesPerSec) - captureaudiosamples = 0; //doh, this WILL cause a bit of wierd sound... - - memcpy(captureaudiomem+captureaudiosamples*2, sample_buffer, samples*2); - - captureaudiosamples+=samples/2; - - samps = captureaudiosamples;//recordavi_wave_format.nSamplesPerSec*recordavi_frametime; - - if (samps < recordavi_wave_format.nSamplesPerSec*recordavi_frametime) - return; //not enough - wouldn't make a frame - samps=recordavi_wave_format.nSamplesPerSec*recordavi_frametime; - - //time for annother frame? - if (recordavi_audiotime > realtime) - return; - recordavi_audiotime += recordavi_frametime; - - captureaudiosamples-=samps; - - - hr = AVIStreamWrite(recordavi_uncompressed_audio_stream, recordavi_audio_frame_counter++, 1, captureaudiomem, samps*recordavi_wave_format.nBlockAlign, AVIIF_KEYFRAME, NULL, NULL); - if (FAILED(hr)) Con_Printf("Recoring error\n"); -//save excess for later. - memmove(captureaudiomem, captureaudiomem+samps*2, captureaudiosamples*4); - } + +static void *MSD_Lock (soundcardinfo_t *sc) +{ + return sc->sn.buffer; +} +static void MSD_Unlock (soundcardinfo_t *sc, void *buffer) +{ +} + +static int MSD_GetDMAPos(soundcardinfo_t *sc) +{ + int s; + + s = captureframe*(snd_speed*recordavi_frametime); + + +// s >>= (sc->sn.samplebits/8) - 1; + s *= sc->sn.numchannels; + return s; +} + +static void MSD_Submit(soundcardinfo_t *sc) +{ + //Fixme: support outputting to wav + //http://www.borg.com/~jglatt/tech/wave.htm + + + int lastpos; + int newpos; + int samplestosubmit; + int partialsamplestosubmit; + int offset; + int bytespersample; + + lastpos = sc->snd_completed; + newpos = sc->paintedtime; + + samplestosubmit = newpos - lastpos; + if (samplestosubmit < (snd_speed*recordavi_frametime)) + return; + + bytespersample = sc->sn.numchannels*sc->sn.samplebits/8; + + sc->snd_completed = newpos; + offset = (lastpos % (sc->sn.samples/sc->sn.numchannels)); + + //we could just use a buffer size equal to the number of samples in each frame + //but that isn't as robust when it comes to floating point imprecisions + //namly: that it would loose a sample each frame with most framerates. + + switch (capturetype) + { +#if defined(WINAVI) + case CT_AVI: + if ((sc->snd_completed % (sc->sn.samples/sc->sn.numchannels)) < offset) + { + //wraped, two chunks to send + partialsamplestosubmit = ((sc->sn.samples/sc->sn.numchannels)) - offset; + AVIStreamWrite(recordavi_uncompressed_audio_stream, recordavi_audio_frame_counter++, 1, sc->sn.buffer+offset*bytespersample, partialsamplestosubmit*bytespersample, AVIIF_KEYFRAME, NULL, NULL); + samplestosubmit -= partialsamplestosubmit; + offset = 0; + } + AVIStreamWrite(recordavi_uncompressed_audio_stream, recordavi_audio_frame_counter++, 1, sc->sn.buffer+offset*bytespersample, samplestosubmit*bytespersample, AVIIF_KEYFRAME, NULL, NULL); + break; +#endif + } +} + +static void MSD_Shutdown (soundcardinfo_t *sc) +{ + Z_Free(sc->sn.buffer); + capture_fakesounddevice = NULL; +} + +void Media_InitFakeSoundDevice (int channels, int samplebits) +{ + soundcardinfo_t *sc; + + if (capture_fakesounddevice) + return; + + sc = Z_Malloc(sizeof(soundcardinfo_t)); + + sc->snd_sent = 0; + sc->snd_completed = 0; + + sc->sn.samples = snd_speed*0.5; + sc->sn.speed = snd_speed; + sc->sn.samplebits = samplebits; + sc->sn.samplepos = 0; + sc->sn.numchannels = channels; + sc->inactive_sound = true; + + sc->sn.buffer = (unsigned char *) BZ_Malloc(sc->sn.samples*sc->sn.numchannels*(sc->sn.samplebits/8)); + + + sc->Lock = MSD_Lock; + sc->Unlock = MSD_Unlock; + sc->SetWaterDistortion = MSD_SetUnderWater; + sc->Submit = MSD_Submit; + sc->Shutdown = MSD_Shutdown; + sc->GetDMAPos = MSD_GetDMAPos; + + sc->next = sndcardinfo; + sndcardinfo = sc; + + capture_fakesounddevice = sc; + + S_DefaultSpeakerConfiguration(sc); +} + + + void Media_StopRecordFilm_f (void) { +#if defined(WINAVI) if (recordavi_uncompressed_video_stream) AVIStreamRelease(recordavi_uncompressed_video_stream); if (recordavi_compressed_video_stream) AVIStreamRelease(recordavi_compressed_video_stream); if (recordavi_uncompressed_audio_stream) AVIStreamRelease(recordavi_uncompressed_audio_stream); if (recordavi_file) AVIFileRelease(recordavi_file); - if (capturevideomem) BZ_Free(capturevideomem); - if (captureaudiomem) BZ_Free(captureaudiomem); - recordavi_uncompressed_video_stream=NULL; recordavi_compressed_video_stream = NULL; recordavi_uncompressed_audio_stream=NULL; recordavi_file = NULL; +#endif + + if (capturevideomem) BZ_Free(capturevideomem); + + if (capture_fakesounddevice) S_ShutdownCard(capture_fakesounddevice); + capturevideomem = NULL; - captureaudiomem=NULL; recordingdemo=false; @@ -1647,11 +1763,6 @@ void Media_StopRecordFilm_f (void) void Media_RecordFilm_f (void) { char *fourcc = capturecodec.string; - char filename[256]; - HRESULT hr; - BITMAPINFOHEADER bitmap_info_header; - AVISTREAMINFO stream_header; - FILE *f; if (Cmd_Argc() != 2) { @@ -1659,14 +1770,9 @@ void Media_RecordFilm_f (void) return; } - if (Cmd_IsInsecure()) //err... don't think so sony. + if (Cmd_IsInsecure()) //err... don't think so sonny. return; - if (!aviinited) - { - aviinited=true; - AVIFileInit(); - } Media_StopRecordFilm_f(); @@ -1681,6 +1787,7 @@ void Media_RecordFilm_f (void) recordavi_frametime = 1/capturerate.value; + captureframe = 0; if (*fourcc) { if (!strcmp(fourcc, "tga") || @@ -1690,24 +1797,46 @@ void Media_RecordFilm_f (void) { capturetype = CT_SCREENSHOT; strcpy(capturefilenameprefix, Cmd_Argv(1)); - captureframe = 0; } else { capturetype = CT_AVI; - recordavi_codec_fourcc = mmioFOURCC(*(fourcc+0), *(fourcc+1), *(fourcc+2), *(fourcc+3)); } } else { - recordavi_codec_fourcc = 0; capturetype = CT_AVI; //uncompressed avi } - - if (capturetype == CT_AVI) + if (capturetype == CT_NONE) { - snprintf(filename, 192, "%s%s", com_gamedir, Cmd_Argv(1)); + + } + else if (capturetype == CT_SCREENSHOT) + { + } +#if defined(WINAVI) + else if (capturetype == CT_AVI) + { + HRESULT hr; + BITMAPINFOHEADER bitmap_info_header; + AVISTREAMINFO stream_header; + FILE *f; + char filename[256]; + + if (strlen(fourcc) == 4) + recordavi_codec_fourcc = mmioFOURCC(*(fourcc+0), *(fourcc+1), *(fourcc+2), *(fourcc+3)); + else + recordavi_codec_fourcc = 0; + + if (!aviinited) + { + aviinited=true; + AVIFileInit(); + } + + + snprintf(filename, 192, "%s%s", com_quakedir, Cmd_Argv(1)); COM_StripExtension(filename, filename, sizeof(filename)); COM_DefaultExtension (filename, ".avi", sizeof(filename)); @@ -1778,13 +1907,18 @@ void Media_RecordFilm_f (void) return; } + if (capturesoundbits.value != 8 && capturesoundbits.value != 16) + Cvar_Set(&capturesoundbits, "8"); + if (capturesoundchannels.value < 1 && capturesoundchannels.value > 6) + Cvar_Set(&capturesoundchannels, "1"); + if (capturesound.value) { memset(&recordavi_wave_format, 0, sizeof(WAVEFORMATEX)); recordavi_wave_format.wFormatTag = WAVE_FORMAT_PCM; - recordavi_wave_format.nChannels = 2; // always stereo in Quake sound engine - recordavi_wave_format.nSamplesPerSec = sndcardinfo->sn.speed; - recordavi_wave_format.wBitsPerSample = 16; // always 16bit in Quake sound engine + recordavi_wave_format.nChannels = capturesoundchannels.value; + recordavi_wave_format.nSamplesPerSec = snd_speed; + recordavi_wave_format.wBitsPerSample = capturesoundbits.value; recordavi_wave_format.nBlockAlign = recordavi_wave_format.wBitsPerSample/8 * recordavi_wave_format.nChannels; recordavi_wave_format.nAvgBytesPerSec = recordavi_wave_format.nSamplesPerSec * recordavi_wave_format.nBlockAlign; recordavi_wave_format.cbSize = 0; @@ -1801,17 +1935,24 @@ void Media_RecordFilm_f (void) hr = AVIStreamSetFormat(recordavi_uncompressed_audio_stream, 0, &recordavi_wave_format, sizeof(WAVEFORMATEX)); if (FAILED(hr)) return; + + Media_InitFakeSoundDevice(recordavi_wave_format.nChannels, recordavi_wave_format.wBitsPerSample); } recordavi_videotime = realtime; recordavi_audiotime = realtime; - if (recordavi_wave_format.nSamplesPerSec) - captureaudiomem = BZ_Malloc(recordavi_wave_format.nSamplesPerSec*2); +// if (recordavi_wave_format.nSamplesPerSec) +// captureaudiomem = BZ_Malloc(recordavi_wave_format.nSamplesPerSec*2); capturevideomem = BZ_Malloc(glwidth*glheight*3); } +#endif + else + { + Con_Printf("That sort of video capturing is not supported in this build\n"); + } } void Media_CaptureDemoEnd(void) { @@ -1842,15 +1983,19 @@ void Media_Init(void) Cmd_AddCommand("music_rewind", Media_Rewind_f); Cmd_AddCommand("music_next", Media_Next_f); -#ifdef WINAVIRECORDING Cmd_AddCommand("capture", Media_RecordFilm_f); Cmd_AddCommand("capturedemo", Media_RecordDemo_f); Cmd_AddCommand("capturestop", Media_StopRecordFilm_f); + Cmd_AddCommand("capturepause", Media_CapturePause_f); Cvar_Register(&capturemessage, "AVI capture controls"); Cvar_Register(&capturesound, "AVI capture controls"); Cvar_Register(&capturerate, "AVI capture controls"); Cvar_Register(&capturecodec, "AVI capture controls"); + +#if defined(WINAVI) + Cvar_Register(&capturesoundbits, "AVI capture controls"); + Cvar_Register(&capturesoundchannels, "AVI capture controls"); #endif #ifdef WINAMP diff --git a/engine/client/m_script.c b/engine/client/m_script.c index 86859666..677d53dd 100644 --- a/engine/client/m_script.c +++ b/engine/client/m_script.c @@ -259,6 +259,7 @@ void M_Script_Init(void) Cmd_AddCommand("menucheck", M_MenuS_CheckBox_f); Cmd_AddCommand("menuslider", M_MenuS_Slider_f); Cmd_AddCommand("menubind", M_MenuS_Bind_f); +// Cmd_AddCommand("menucombo", M_MenuS_Combo_f); Cvar_Register(&menualias, "Scripting"); } diff --git a/engine/client/m_single.c b/engine/client/m_single.c index 4cb6f019..393c049e 100644 --- a/engine/client/m_single.c +++ b/engine/client/m_single.c @@ -352,6 +352,10 @@ int DemoAddItem(char *filename, int size, void *parm) if (extnum == menu->numext) //wasn't on our list of extensions. return true; } + else + { + //directory + } if (menu->maxmatches < menu->nummatches+10) { menu->maxmatches = menu->nummatches+10; @@ -359,7 +363,7 @@ int DemoAddItem(char *filename, int size, void *parm) } for (match = 0; match < menu->nummatches; match++) if (!strcmp(menu->options[match].name, filename)) - return true; + return true; //already got that one Q_strncpyz(menu->options[menu->nummatches].name, filename, sizeof(menu->options[menu->nummatches].name)); menu->options[menu->nummatches].size = size; menu->nummatches++; @@ -430,7 +434,7 @@ void M_Menu_Demos_f (void) info->ext[2] = ".dm2"; info->command[3] = "playdemo"; info->ext[3] = ".mvd"; - //there are also quizmo demos (.qwz) out there... + //there are also qizmo demos (.qwz) out there... //we don't support them, but if we were to ask quizmo to decode them for us, we could do. info->numext = 4; diff --git a/engine/client/net_master.c b/engine/client/net_master.c index 4280ac33..6f36745b 100644 --- a/engine/client/net_master.c +++ b/engine/client/net_master.c @@ -168,17 +168,17 @@ qboolean Master_CompareString(char *a, char *b, slist_test_t rule) case SLIST_TEST_NOTCONTAIN: return !strstr(a, b); case SLIST_TEST_LESSEQUAL: - return strcmp(a, b)<=0; + return stricmp(a, b)<=0; case SLIST_TEST_LESS: - return strcmp(a, b)<0; + return stricmp(a, b)<0; case SLIST_TEST_EQUAL: - return strcmp(a, b)==0; + return stricmp(a, b)==0; case SLIST_TEST_GREATER: - return strcmp(a, b)>0; + return stricmp(a, b)>0; case SLIST_TEST_GREATEREQUAL: - return strcmp(a, b)>=0; + return stricmp(a, b)>=0; case SLIST_TEST_NOTEQUAL: - return strcmp(a, b)!=0; + return stricmp(a, b)!=0; } return false; } @@ -1545,7 +1545,9 @@ int CL_ReadServerInfo(char *msg, int servertype, qboolean favorite) info->fl = atoi(Info_ValueForKey(msg, "fraglimit")); if (*Info_ValueForKey(msg, "*qtv")) - info->special |= SS_QTV; + info->special |= SS_PROXY|SS_FTESERVER; + if (!strcmp(Info_ValueForKey(msg, "*progs"), "666") && !strcmp(Info_ValueForKey(msg, "*version"), "2.91")) + info->special |= SS_PROXY; //qizmo if (servertype == MT_SINGLEQ3 || servertype == MT_SINGLEQ2 || servertype == MT_SINGLEDP) { diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index abdcf149..a786c9f0 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -2559,7 +2559,7 @@ static void PF_cl_runningserver (progfuncs_t *prinst, struct globalvars_s *pr_gl static void PF_cl_getlight (progfuncs_t *prinst, struct globalvars_s *pr_globals) { vec3_t ambient, diffuse, dir; - cl.worldmodel->funcs.LightPointValues(G_VECTOR(OFS_PARM0), ambient, diffuse, dir); + cl.worldmodel->funcs.LightPointValues(cl.worldmodel, G_VECTOR(OFS_PARM0), ambient, diffuse, dir); VectorMA(ambient, 0.5, diffuse, G_VECTOR(OFS_RETURN)); } diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index 58c93b50..6e2e62ee 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -1488,7 +1488,7 @@ void MP_Init (void) } } -void MP_CoreDump(void) +void MP_CoreDump_f(void) { if (!menuprogs) { @@ -1505,9 +1505,16 @@ void MP_CoreDump(void) } } +void MP_Reload_f(void) +{ + MP_Shutdown(); + MP_Init(); +} + void MP_RegisterCvarsAndCmds(void) { - Cmd_AddCommand("coredump_menuqc", MP_CoreDump); + Cmd_AddCommand("coredump_menuqc", MP_CoreDump_f); + Cmd_AddCommand("menuqc_reload", MP_Reload_f); Cvar_Register(&forceqmenu, MENUPROGSGROUP); Cvar_Register(&pr_menuqc_coreonerror, MENUPROGSGROUP); diff --git a/engine/client/r_part.c b/engine/client/r_part.c index 1d183914..76680824 100644 --- a/engine/client/r_part.c +++ b/engine/client/r_part.c @@ -283,6 +283,7 @@ static part_type_t *P_GetParticleType(char *name) { int i; part_type_t *ptype; + part_type_t *oldlist = part_type; for (i = 0; i < numparticletypes; i++) { ptype = &part_type[i]; @@ -295,6 +296,17 @@ static part_type_t *P_GetParticleType(char *name) ptype->assoc=-1; ptype->cliptype = -1; ptype->emit = -1; + + + if (oldlist) + { + part_run_list=NULL; + + for (i = 0; i < numparticletypes; i++) + if (part_type[i].nexttorun) + part_type[i].nexttorun = (part_type_t*)((char*)part_type[i].nexttorun - (char*)oldlist + (char*)part_type); + } + /* Due to BZ_Realloc we can assume all of this anyway ptype->loaded = 0; @@ -4445,13 +4457,13 @@ void DrawParticleTypes (void (*texturedparticles)(particle_t *,part_type_t*), vo } // delete from run list if necessary - if (!type->particles && !type->beams) + if (!type->particles && !type->beams && !type->clippeddecals) { - if (!lastvalidtype) - part_run_list = type->nexttorun; - else - lastvalidtype->nexttorun = type->nexttorun; - type->state &= ~PS_INRUNLIST; +// if (!lastvalidtype) +// part_run_list = type->nexttorun; +// else +// lastvalidtype->nexttorun = type->nexttorun; +// type->state &= ~PS_INRUNLIST; } else lastvalidtype = type; diff --git a/engine/client/render.h b/engine/client/render.h index dd464b7c..aa8a5ad2 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -309,7 +309,6 @@ extern struct model_s *currentmodel; qboolean Media_ShowFilm(void); void Media_CaptureDemoEnd(void); -void Media_RecordAudioFrame (short *sample_buffer, int samples); void Media_RecordFrame (void); qboolean Media_PausedDemo (void); diff --git a/engine/client/snd_directx.c b/engine/client/snd_directx.c index c0d0ab75..da11f6b1 100644 --- a/engine/client/snd_directx.c +++ b/engine/client/snd_directx.c @@ -809,11 +809,8 @@ int DSOUND_InitCard (soundcardinfo_t *sc, int cardnum) dh->pDSBuf->lpVtbl->GetCurrentPosition(dh->pDSBuf, &dh->mmstarttime, &dwWrite); dh->pDSBuf->lpVtbl->Play(dh->pDSBuf, 0, 0, DSBPLAY_LOOPING); - sc->sn.soundalive = true; - sc->sn.splitbuffer = false; sc->sn.samples = dh->gSndBufSize/(sc->sn.samplebits/8); sc->sn.samplepos = 0; - sc->sn.submission_chunk = 1; sc->sn.buffer = NULL; diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c index 4e8db4d3..709cdccd 100644 --- a/engine/client/snd_dma.c +++ b/engine/client/snd_dma.c @@ -90,20 +90,6 @@ cvar_t snd_usemultipledevices = SCVAR("snd_multipledevices", "0"); extern vfsfile_t *rawwritefile; -// ==================================================================== -// User-setable variables -// ==================================================================== - - -// -// Fake dma is a synchronous faking of the DMA progress used for -// isolating performance in the renderer. The fakedma_updates is -// number of times S_Update() is called per second. -// - -qboolean fakedma = false; -int fakedma_updates = 15; - void S_AmbientOff (void) { @@ -137,7 +123,6 @@ void S_SoundInfo_f(void) Con_Printf("%5d samples\n", sc->sn.samples); Con_Printf("%5d samplepos\n", sc->sn.samplepos); Con_Printf("%5d samplebits\n", sc->sn.samplebits); - Con_Printf("%5d submission_chunk\n", sc->sn.submission_chunk); Con_Printf("%5d speed\n", sc->sn.speed); Con_Printf("0x%x dma buffer\n", sc->sn.buffer); Con_Printf("%5d total_channels\n", sc->total_chans); @@ -257,6 +242,56 @@ static int SNDDMA_Init(soundcardinfo_t *sc, int *cardnum, int *drivernum) } } +void S_DefaultSpeakerConfiguration(soundcardinfo_t *sc) +{ + if (sc->sn.numchannels < 3) + { + sc->pitch[0] = 0; + sc->pitch[1] = 0; + sc->dist[0] = 1; + sc->dist[1] = 1; + sc->yaw[0] = 270; + sc->yaw[1] = 90; + } + else if (sc->sn.numchannels < 5) + { + sc->pitch[0] = 0; + sc->pitch[1] = 0; + sc->pitch[2] = 0; + sc->pitch[3] = 0; + sc->dist[0] = 1; + sc->dist[1] = 1; + sc->dist[2] = 1; + sc->dist[3] = 1; + sc->yaw[0] = 315; + sc->yaw[1] = 45; + sc->yaw[2] = 225; + sc->yaw[3] = 135; + } + else + { + sc->pitch[0] = 0; + sc->pitch[1] = 0; + sc->pitch[2] = 0; + sc->pitch[3] = 0; + sc->pitch[4] = 0; + sc->pitch[5] = 0; + sc->dist[0] = 1; + sc->dist[1] = 1; + sc->dist[2] = 1; + sc->dist[3] = 1; + sc->dist[4] = 1; + sc->dist[5] = 1; + sc->yaw[0] = 315; + sc->yaw[1] = 45; + sc->yaw[2] = 0; + sc->yaw[3] = 0; + sc->yaw[4] = 225; + sc->yaw[5] = 135; + } +} + + /* ================ S_Startup @@ -280,95 +315,48 @@ void S_Startup (void) snd_blocked = 0; snd_speed = 0; - if (!fakedma) + for(cardnum = 0, drivernum = 0;;) { - for(cardnum = 0, drivernum = 0;;) + sc = Z_Malloc(sizeof(soundcardinfo_t)); + rc = SNDDMA_Init(sc, &cardnum, &drivernum); + + if (!rc) //error stop { - sc = Z_Malloc(sizeof(soundcardinfo_t)); - rc = SNDDMA_Init(sc, &cardnum, &drivernum); - - if (!rc) //error stop - { - Con_Printf("S_Startup: SNDDMA_Init failed.\n"); - Z_Free(sc); - break; - } - if (rc == 2) //silently stop (no more cards) - { - Z_Free(sc); - break; - } - - if (sc->sn.numchannels < 3) - { - sc->pitch[0] = 0; - sc->pitch[1] = 0; - sc->dist[0] = 1; - sc->dist[1] = 1; - sc->yaw[0] = 270; - sc->yaw[1] = 90; - } - else if (sc->sn.numchannels < 5) - { - sc->pitch[0] = 0; - sc->pitch[1] = 0; - sc->pitch[2] = 0; - sc->pitch[3] = 0; - sc->dist[0] = 1; - sc->dist[1] = 1; - sc->dist[2] = 1; - sc->dist[3] = 1; - sc->yaw[0] = 315; - sc->yaw[1] = 45; - sc->yaw[2] = 225; - sc->yaw[3] = 135; - } - else - { - sc->pitch[0] = 0; - sc->pitch[1] = 0; - sc->pitch[2] = 0; - sc->pitch[3] = 0; - sc->pitch[4] = 0; - sc->pitch[5] = 0; - sc->dist[0] = 1; - sc->dist[1] = 1; - sc->dist[2] = 1; - sc->dist[3] = 1; - sc->dist[4] = 1; - sc->dist[5] = 1; - sc->yaw[0] = 315; - sc->yaw[1] = 45; - sc->yaw[2] = 0; - sc->yaw[3] = 0; - sc->yaw[4] = 225; - sc->yaw[5] = 135; - } - - if (sndcardinfo) - { //if the sample speeds of multiple soundcards do not match, it'll fail. - if (snd_speed != sc->sn.speed) - { - if (!warningmessage) - { - Con_Printf("S_Startup: Ignoring soundcard %s due to mismatched sample speeds.\nTry running Quake with -singlesound to use just the primary soundcard\n", sc->name); - S_ShutdownCard(sc); - warningmessage = true; - } - - Z_Free(sc); - continue; - } - } - else - snd_speed = sc->sn.speed; - - sc->next = sndcardinfo; - sndcardinfo = sc; - - if (!snd_usemultipledevices.value) - break; + Con_Printf("S_Startup: SNDDMA_Init failed.\n"); + Z_Free(sc); + break; } + if (rc == 2) //silently stop (no more cards) + { + Z_Free(sc); + break; + } + + S_DefaultSpeakerConfiguration(sc); + + if (sndcardinfo) + { //if the sample speeds of multiple soundcards do not match, it'll fail. + if (snd_speed != sc->sn.speed) + { + if (!warningmessage) + { + Con_Printf("S_Startup: Ignoring soundcard %s due to mismatched sample speeds.\nTry running Quake with -singlesound to use just the primary soundcard\n", sc->name); + S_ShutdownCard(sc); + warningmessage = true; + } + + Z_Free(sc); + continue; + } + } + else + snd_speed = sc->sn.speed; + + sc->next = sndcardinfo; + sndcardinfo = sc; + + if (!snd_usemultipledevices.value) + break; } sound_started = 1; @@ -557,9 +545,6 @@ void S_Init (void) } Con_DPrintf("\nSound Initialization\n"); -// if (COM_CheckParm("-simsound")) -// fakedma = true; - Cmd_AddCommand("play", S_Play); Cmd_AddCommand("play2", S_Play); Cmd_AddCommand("playvol", S_PlayVol); @@ -656,22 +641,38 @@ void S_Init (void) void S_ShutdownCard(soundcardinfo_t *sc) { + soundcardinfo_t *prev; #if defined(_WIN32) && !defined(NODIRECTX) extern int aimedforguid; aimedforguid = 0; #endif - if (!fakedma) + + if (sndcardinfo == sc) + sndcardinfo = sc->next; + else { - sc->Shutdown(sc); + for (prev = sndcardinfo; prev->next; prev = prev->next) + { + if (prev->next == sc) + prev->next = sc->next; + } } + + sc->Shutdown(sc); + Z_Free(sc); } void S_Shutdown(void) { soundcardinfo_t *sc, *next; +#if defined(_WIN32) && !defined(NODIRECTX) + extern int aimedforguid; + aimedforguid = 0; +#endif + for (sc = sndcardinfo; sc; sc=next) { next = sc->next; - S_ShutdownCard(sc); + sc->Shutdown(sc); Z_Free(sc); sndcardinfo = next; } diff --git a/engine/client/snd_mix.c b/engine/client/snd_mix.c index 45fa8941..8069ce3c 100644 --- a/engine/client/snd_mix.c +++ b/engine/client/snd_mix.c @@ -92,18 +92,6 @@ void S_TransferPaintBuffer(soundcardinfo_t *sc, int endtime) skip += *cskip; cskip += *cskip; } - // Only do this for 1 sound card with 2 channels, because - // this function is hacky - if (sc == sndcardinfo && sc->sn.numchannels == 2) - { - if (out_idx <= startidx) // buffer looped - { - Media_RecordAudioFrame(out + startidx, (sc->sn.samples - startidx) / 2); - Media_RecordAudioFrame(out, out_idx / 2); - } - else - Media_RecordAudioFrame(out + startidx, (out_idx - startidx) / 2); - } } else if (sc->sn.samplebits == 8) { diff --git a/engine/client/snd_win.c b/engine/client/snd_win.c index 3ddea1a9..b5da7be9 100644 --- a/engine/client/snd_win.c +++ b/engine/client/snd_win.c @@ -351,11 +351,8 @@ int WAV_InitCard (soundcardinfo_t *sc, int cardnum) } } - sc->sn.soundalive = true; - sc->sn.splitbuffer = false; sc->sn.samples = wh->gSndBufSize/(sc->sn.samplebits/8); sc->sn.samplepos = 0; - sc->sn.submission_chunk = 1; sc->sn.buffer = (unsigned char *) wh->lpData; diff --git a/engine/client/sound.h b/engine/client/sound.h index 1c398b45..c442a1c1 100644 --- a/engine/client/sound.h +++ b/engine/client/sound.h @@ -65,12 +65,12 @@ typedef struct sfxcache_s typedef struct { - qboolean gamealive; - qboolean soundalive; - qboolean splitbuffer; +// qboolean gamealive; +// qboolean soundalive; +// qboolean splitbuffer; int numchannels; - int samples; // mono samples in buffer - int submission_chunk; // don't mix less than this # + int samples; // mono samples in buffer (individual, non grouped) +// int submission_chunk; // don't mix less than this # int samplepos; // in mono samples int samplebits; int speed; @@ -169,8 +169,6 @@ void SNDVC_MicInput(qbyte *buffer, int samples, int freq, int width); extern int snd_speed; -extern qboolean fakedma; -extern int fakedma_updates; extern vec3_t listener_origin; extern vec3_t listener_forward; extern vec3_t listener_right; @@ -227,8 +225,8 @@ struct soundcardinfo_s { //windows has one defined AFTER directsound qboolean selfpainting; //allow the sound code to call the right functions when it feels the need (not properly supported). int paintedtime; //used in the mixer - int oldsamplepos; //fixme: is this still needed? - int buffers; //used to keep track of buffer wraps for consistant sound + int oldsamplepos; //this is used to track buffer wraps + int buffers; //used to keep track of how many buffer wraps for consistant sound //callbacks void *(*Lock) (soundcardinfo_t *sc); diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index fb2a76f3..4dea3b5d 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -1042,6 +1042,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin static char cwd[1024]; int t; RECT rect; + char *qtvfile = NULL; /* previous instances do not exist in Win32 */ if (hPrevInstance) @@ -1071,12 +1072,26 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin if (*lpCmdLine) { - argv[parms.argc] = lpCmdLine; - parms.argc++; - - while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126))) + if (*lpCmdLine == '\"') + { lpCmdLine++; + argv[parms.argc] = lpCmdLine; + parms.argc++; + + while (*lpCmdLine && *lpCmdLine != '\"') + lpCmdLine++; + } + else + { + argv[parms.argc] = lpCmdLine; + parms.argc++; + + + while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126))) + lpCmdLine++; + } + if (*lpCmdLine) { *lpCmdLine = 0; @@ -1097,10 +1112,29 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin return true; } - - if (!GetCurrentDirectory (sizeof(cwd), cwd)) Sys_Error ("Couldn't determine current directory"); + if (parms.argc >= 2) + { + if (*parms.argv[1] != '-' && *parms.argv[1] != '+') + { + char *e; + + qtvfile = parms.argv[1]; + + + GetModuleFileName(NULL, cwd, sizeof(cwd)-1); + for (e = cwd+strlen(cwd)-1; e >= cwd; e--) + { + if (*e == '/' || *e == '\\') + { + *e = 0; + break; + } + } + + } + } TL_InitLanguages(); //tprints are now allowed @@ -1195,7 +1229,6 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin #endif tevent = CreateEvent(NULL, FALSE, FALSE, NULL); - if (!tevent) Sys_Error ("Couldn't create event"); @@ -1210,6 +1243,9 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin oldtime = Sys_DoubleTime (); + if (qtvfile) + Cbuf_AddText(va("qtvplay \"#%s\"\n", qtvfile), RESTRICT_LOCAL); + //client console should now be initialized. /* main window message loop */ diff --git a/engine/client/valid.c b/engine/client/valid.c index af62ebd4..c0603b4c 100644 --- a/engine/client/valid.c +++ b/engine/client/valid.c @@ -43,12 +43,6 @@ cvar_t allow_f_modified = SCVAR("allow_f_modified", "1"); cvar_t allow_f_skins = SCVAR("allow_f_skins", "1"); cvar_t auth_validateclients = SCVAR("auth_validateclients", "1"); - -void QCRC_AddBlock (unsigned short *crcvalue, qbyte *start, int count) -{ - while (count--) - QCRC_ProcessByte(crcvalue, *start++); -} unsigned short SCRC_GetQueryStateCrc(char *f_query_string) { unsigned short crc; diff --git a/engine/client/view.c b/engine/client/view.c index 47caf45e..3b970d0d 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -1368,6 +1368,7 @@ void V_RenderPlayerViews(int plnum) r_viewchanged = true; #endif + Cam_SelfTrack(plnum); #if defined(FISH) && defined(SWQUAKE) if (ffov.value && cls.allow_fish && qrenderer == QR_SOFTWARE) R_RenderView_fisheye(); diff --git a/engine/common/cmd.c b/engine/common/cmd.c index 96e6d6ce..fdc7fe44 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -1908,6 +1908,7 @@ qboolean is_numeric (const char *c) ((*c == '-' || *c == '+') && (c[1] == '.' || (c[1]>='0' && c[1]<='9'))) || (*c == '.' && (c[1]>='0' && c[1]<='9'))?true:false; } +#define IFPUNCT "(,{})(\':;=!><&|+*/-" const char *If_Token(const char *func, const char **end) { const char *s, *s2; @@ -1916,7 +1917,7 @@ const char *If_Token(const char *func, const char **end) while(*func <= ' ' && *func) func++; - s = COM_ParseToken(func, NULL); + s = COM_ParseToken(func, IFPUNCT); if (*com_token == '(') { @@ -1949,9 +1950,19 @@ const char *If_Token(const char *func, const char **end) else return "true"; } + else if (!strcmp(com_token, "int")) + { + func = If_Token(s, end); + return retfloat(atof(func)); + } + else if (!strcmp(com_token, "strlen")) + { + func = If_Token(s, end); + return retfloat(strlen(func)); + } else if (!strcmp(com_token, "defined")) //functions { - s = COM_ParseToken(s, NULL); + s = COM_ParseToken(s, IFPUNCT); var = Cvar_FindVar(com_token); *end = s; return retstring((var != NULL)?"true":""); @@ -1962,7 +1973,7 @@ const char *If_Token(const char *func, const char **end) } else if (!strcmp(com_token, "vid")) //mostly for use with the menu system. { - s = COM_ParseToken(s, NULL); + s = COM_ParseToken(s, IFPUNCT); #ifndef SERVERONLY if (qrenderer == QR_NONE) s2 = ""; @@ -1993,10 +2004,10 @@ const char *If_Token(const char *func, const char **end) *end = s; - s = COM_ParseToken(s, NULL); + s = COM_ParseToken(s, IFPUNCT); if (!strcmp(com_token, "=")) //comparisions { - func=COM_ParseToken(s, NULL); + func=COM_ParseToken(s, IFPUNCT); if (*com_token == '=') //lol. "=" == "==" return retfloat(!strcmp(s2, If_Token(func, end))); else @@ -2006,7 +2017,7 @@ const char *If_Token(const char *func, const char **end) return retfloat(!strcmp(s2, If_Token(s, end))); if (!strcmp(com_token, "!")) { - func=COM_ParseToken(s, NULL); + func=COM_ParseToken(s, IFPUNCT); if (*com_token == '=') { s = If_Token(func, end); @@ -2024,7 +2035,7 @@ const char *If_Token(const char *func, const char **end) } if (!strcmp(com_token, ">")) { - func=COM_ParseToken(s, NULL); + func=COM_ParseToken(s, IFPUNCT); if (*com_token == '=') return retfloat(atof(s2)>=atof(If_Token(func, end))); else if (*com_token == '<')//vb? @@ -2044,7 +2055,7 @@ const char *If_Token(const char *func, const char **end) } if (!strcmp(com_token, "<")) { - func=COM_ParseToken(s, NULL); + func=COM_ParseToken(s, IFPUNCT); if (*com_token == '=') return retfloat(atof(s2)<=atof(If_Token(func, end))); else if (*com_token == '>')//vb? @@ -2063,17 +2074,33 @@ const char *If_Token(const char *func, const char **end) return retfloat(atof(s2)*atof(If_Token(s, end))); if (!strcmp(com_token, "/")) return retfloat(atof(s2)/atof(If_Token(s, end))); + if (!strcmp(com_token, "%")) + { + level = (int)atof(If_Token(s, end)); + if (level == 0) + return retfloat(0); + else + return retfloat((int)atof(s2)%level); + } if (!strcmp(com_token, "&")) //and { - func=COM_ParseToken(s, NULL); + func=COM_ParseToken(s, IFPUNCT); if (*com_token == '&') return retfloat(*s2&&*If_Token(s, end)); else return retfloat(atoi(s2)&atoi(If_Token(s, end))); } + if (!strcmp(com_token, "div")) //qw262 compatability + return retfloat(atof(s2)/atof(If_Token(s, end))); + if (!strcmp(com_token, "or")) //qw262 compatability + return retfloat(atoi(s2)|atoi(If_Token(s, end))); + if (!strcmp(com_token, "xor")) //qw262 compatability + return retfloat(atoi(s2)^atoi(If_Token(s, end))); + if (!strcmp(com_token, "and")) //qw262 compatability + return retfloat(atoi(s2)&atoi(If_Token(s, end))); if (!strcmp(com_token, "|")) //or { - func=COM_ParseToken(s, NULL); + func=COM_ParseToken(s, IFPUNCT); if (*com_token == '|') { func = If_Token(func, end); @@ -2323,6 +2350,7 @@ void Cmd_set_f(void) const char *end; const char *text; int forceflags = 0; + qboolean docalc; if (Cmd_Argc()<3) { @@ -2330,6 +2358,11 @@ void Cmd_set_f(void) return; } + if (!strcmp(Cmd_Argv(0), "set_calc") || !strcmp(Cmd_Argv(0), "seta_calc")) + docalc = true; + else + docalc = false; + var = Cvar_Get (Cmd_Argv(1), "0", 0, "Custom variables"); if (Cmd_FromGamecode()) //AAHHHH!!! Q2 set command is different @@ -2345,20 +2378,13 @@ void Cmd_set_f(void) } else { + Cmd_ShiftArgs(1, false); text = Cmd_Args(); + if (*text == '\"') //if it's already quoted, dequote it, and ignore trailing stuff, for q2/q3 compatability + text = Cmd_Argv(1); forceflags = 0; - - while(*text <= ' ' && *text) //first whitespace - text++; - while(*text > ' ') //first var - text++; - while(*text <= ' ' && *text) //second whitespace - text++; } - //second var - var = Cvar_FindVar (Cmd_Argv(1)); - mark = If_Token_GetMark(); if (var) @@ -2380,7 +2406,8 @@ void Cmd_set_f(void) } else { - text = If_Token(text, &end); + if (docalc) + text = If_Token(text, &end); Cvar_Set(var, text); var->flags |= CVAR_USERCREATED; @@ -2390,11 +2417,13 @@ void Cmd_set_f(void) } else { - text = If_Token(text, &end); + if (docalc) + text = If_Token(text, &end); if (Cmd_FromGamecode()) { var = Cvar_Get(Cmd_Argv(1), "", 0, "Game variables"); - Cvar_LockFromServer(var, text); + if (var) + Cvar_LockFromServer(var, text); } else var = Cvar_Get(Cmd_Argv(1), text, 0, "User variables"); @@ -2407,7 +2436,6 @@ void Cmd_set_f(void) If_Token_Clear(mark); } - void Cvar_Inc_f (void) { int c; @@ -2589,7 +2617,9 @@ void Cmd_Init (void) // Cmd_AddCommand ("filter", Cmd_Msg_Filter_f); Cmd_AddCommand ("set", Cmd_set_f); + Cmd_AddCommand ("set_calc", Cmd_set_f); Cmd_AddCommand ("seta", Cmd_set_f); + Cmd_AddCommand ("seta_calc", Cmd_set_f); Cmd_AddCommand ("vstr", Cmd_Vstr_f); Cmd_AddCommand ("inc", Cvar_Inc_f); //FIXME: Add seta some time. diff --git a/engine/common/common.c b/engine/common/common.c index d03617a7..743a2dce 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -359,7 +359,7 @@ int wildcmp(char *wild, char *string) { if (*wild == '*') { - if (!*++wild) + if (!*++wild) //a * at the end of the wild string matches anything the checked string has { return 1; } @@ -1560,7 +1560,12 @@ void COM_FileBase (char *in, char *out, int outlen) s2 = in; if (s-s2 < 2) - strcpy (out,"?model?"); + { + if (s == s2) + Q_strncpyz(out, in, outlen); + else + Q_strncpyz(out,"?model?", outlen); + } else { s--; @@ -1946,7 +1951,7 @@ skipwhite: } #define DEFAULT_PUNCTUATION "(,{})(\':;=!><&|+" -const char *COM_ParseToken (const char *data, const char *punctuation) +char *COM_ParseToken (const char *data, const char *punctuation) { int c; int len; @@ -2005,13 +2010,13 @@ skipwhite: if (len >= TOKENSIZE-1) { com_token[len] = '\0'; - return data; + return (char*)data; } c = *data++; if (c=='\"' || !c) { com_token[len] = 0; - return data; + return (char*)data; } com_token[len] = c; len++; @@ -2026,7 +2031,7 @@ skipwhite: com_token[len] = c; len++; com_token[len] = 0; - return data+1; + return (char*)(data+1); } // parse a regular word @@ -2043,7 +2048,7 @@ skipwhite: } while (c>32); com_token[len] = 0; - return data; + return (char*)data; } char *COM_ParseCString (char *data) diff --git a/engine/common/common.h b/engine/common/common.h index b3f133af..41a7cb65 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -237,7 +237,7 @@ extern qboolean com_eof; char *COM_Parse (char *data); char *COM_ParseCString (char *data); char *COM_StringParse (char *data, qboolean expandmacros, qboolean qctokenize); -const char *COM_ParseToken (const char *data, const char *punctuation); +char *COM_ParseToken (const char *data, const char *punctuation); char *COM_TrimString(char *str); diff --git a/engine/common/crc.c b/engine/common/crc.c index a94be160..ea220011 100644 --- a/engine/common/crc.c +++ b/engine/common/crc.c @@ -91,3 +91,8 @@ unsigned short QCRC_Block (qbyte *start, int count) return crc; } +void QCRC_AddBlock (unsigned short *crcvalue, qbyte *start, int count) +{ + while (count--) + QCRC_ProcessByte(crcvalue, *start++); +} \ No newline at end of file diff --git a/engine/common/crc.h b/engine/common/crc.h index 7db046fc..a2b7bfaf 100644 --- a/engine/common/crc.h +++ b/engine/common/crc.h @@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /* crc.h */ void QCRC_Init(unsigned short *crcvalue); +void QCRC_AddBlock (unsigned short *crcvalue, qbyte *start, int count); void QCRC_ProcessByte(unsigned short *crcvalue, qbyte data); unsigned short QCRC_Value(unsigned short crcvalue); unsigned short QCRC_Block (qbyte *start, int count); diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index 1c23baa2..4523fe11 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -3773,7 +3773,7 @@ void Q2BSP_FatPVS (model_t *mod, vec3_t org, qboolean add); qboolean Q2BSP_EdictInFatPVS(model_t *mod, edict_t *ent); void Q2BSP_FindTouchedLeafs(model_t *mod, edict_t *ent); #endif -void GLQ2BSP_LightPointValues(vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir); +void GLQ2BSP_LightPointValues(model_t *mod, vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir); void SWQ2BSP_LightPointValues(vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir); /* diff --git a/engine/common/translate.c b/engine/common/translate.c index c5e058a7..b30018b9 100644 --- a/engine/common/translate.c +++ b/engine/common/translate.c @@ -208,6 +208,7 @@ static char *defaultlanguagetext = "TLC_CHANGINGMAP \"\\nChanging map...\\n\"\n" "TLC_RECONNECTING \"reconnecting...\\n\"\n" "TLC_RECONNECT_NOSERVER \"No server to reconnect to...\\n\"\n" +"TLC_VERSIONST \"%s Build %i\n\"\n" "TL_ST_COLON \"%s: \"\n" "TLC_GOTCONNECTION \"connection\\n\"\n" "TLC_DUPCONNECTION \"Dup connect received. Ignored.\\n\"\n" diff --git a/engine/ftequake/FTEQuake.dev b/engine/ftequake/FTEQuake.dev index 66b130c7..aeaf05bc 100644 --- a/engine/ftequake/FTEQuake.dev +++ b/engine/ftequake/FTEQuake.dev @@ -1,7 +1,7 @@ [Project] FileName=FTEQuake.dev Name=FTEQuake -UnitCount=141 +UnitCount=140 Type=0 Ver=1 ObjFiles="" @@ -211,7 +211,7 @@ BuildCmd= Major=2 Minor=5 Release=5 -Build=72 +Build=74 LanguageID=2057 CharsetID=1252 CompanyName= @@ -1304,16 +1304,6 @@ OverrideBuildCmd=0 BuildCmd= [Unit127] -FileName=..\irc\ircclient.c -CompileCpp=0 -Folder=inet -Compile=1 -Link=1 -Priority=1000 -OverrideBuildCmd=0 -BuildCmd= - -[Unit128] FileName=..\client\pr_menu.c CompileCpp=0 Folder=Client @@ -1323,7 +1313,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit129] +[Unit128] FileName=..\common\plugin.c CompileCpp=0 Folder=Common @@ -1333,7 +1323,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit130] +[Unit129] FileName=..\client\pr_csqc.c CompileCpp=0 Folder=Client @@ -1343,27 +1333,27 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit131] +[Unit130] FileName=..\gl\gl_shader.c +CompileCpp=0 Folder=gl Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= + +[Unit131] +FileName=..\client\m_download.c +Folder=Client +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= CompileCpp=0 [Unit132] -FileName=..\client\m_download.c -CompileCpp=0 -Folder=Client -Compile=1 -Link=1 -Priority=1000 -OverrideBuildCmd=0 -BuildCmd= - -[Unit133] FileName=..\client\snd_directx.c CompileCpp=0 Folder=Client @@ -1373,7 +1363,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit134] +[Unit133] FileName=..\common\fs.c CompileCpp=0 Folder=Common @@ -1383,7 +1373,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit135] +[Unit134] FileName=..\common\log.c CompileCpp=0 Folder=Common @@ -1393,7 +1383,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit136] +[Unit135] FileName=..\gl\gl_heightmap.c CompileCpp=0 Folder=gl @@ -1403,7 +1393,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit137] +[Unit136] FileName=..\client\clq3_parse.c CompileCpp=0 Folder=Client @@ -1413,7 +1403,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit138] +[Unit137] FileName=..\client\cl_cg.c CompileCpp=0 Folder=Client @@ -1423,7 +1413,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit139] +[Unit138] FileName=..\server\svq3_game.c CompileCpp=0 Folder=server @@ -1433,7 +1423,7 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit140] +[Unit139] FileName=..\client\cl_ignore.c CompileCpp=0 Folder=Client @@ -1443,6 +1433,16 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= +[Unit140] +FileName=..\common\q3common.c +CompileCpp=0 +Folder=Common +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + [Unit141] FileName=..\common\q3common.c CompileCpp=0 diff --git a/engine/ftequake/ftequake.dsp b/engine/ftequake/ftequake.dsp index 85ae6363..bf38fbf9 100644 --- a/engine/ftequake/ftequake.dsp +++ b/engine/ftequake/ftequake.dsp @@ -9324,8 +9324,8 @@ SOURCE=..\client\winquake.rc !IF "$(CFG)" == "ftequake - Win32 Release" -# ADD BASE RSC /l 0x809 /i "\ftetgcvs\engine\client" /i "\Projects\fteqw\engine\client" /i "\windows\J\ftetgcvs\engine\client" /i "\ftetgcvs\source\client" /i "\ftetgcvs\temp\client" /i "\ftetgcvs\fte\QW\client" -# ADD RSC /l 0x809 /i "\ftetgcvs\engine\client" /i "\Projects\fteqw\engine\client" /i "\windows\J\ftetgcvs\engine\client" /i "\ftetgcvs\source\client" /i "\ftetgcvs\temp\client" /i "\ftetgcvs\fte\QW\client" /d "MINIMAL" +# ADD BASE RSC /l 0x809 /i "\ftetgcvs\svn\engine\client" /i "\ftetgcvs\engine\client" /i "\Projects\fteqw\engine\client" /i "\windows\J\ftetgcvs\engine\client" /i "\ftetgcvs\source\client" /i "\ftetgcvs\temp\client" /i "\ftetgcvs\fte\QW\client" +# ADD RSC /l 0x809 /i "\ftetgcvs\svn\engine\client" /i "\ftetgcvs\engine\client" /i "\Projects\fteqw\engine\client" /i "\windows\J\ftetgcvs\engine\client" /i "\ftetgcvs\source\client" /i "\ftetgcvs\temp\client" /i "\ftetgcvs\fte\QW\client" /d "MINIMAL" !ELSEIF "$(CFG)" == "ftequake - Win32 Debug" diff --git a/engine/gl/gl_alias.c b/engine/gl/gl_alias.c index c3e96265..f83e142a 100644 --- a/engine/gl/gl_alias.c +++ b/engine/gl/gl_alias.c @@ -1655,9 +1655,9 @@ void R_DrawGAliasModel (entity_t *e) if (!(r_refdef.flags & Q2RDF_NOWORLDMODEL)) { if (e->flags & Q2RF_WEAPONMODEL) - cl.worldmodel->funcs.LightPointValues(r_refdef.vieworg, shadelight, ambientlight, lightdir); + cl.worldmodel->funcs.LightPointValues(cl.worldmodel, r_refdef.vieworg, shadelight, ambientlight, lightdir); else - cl.worldmodel->funcs.LightPointValues(e->origin, shadelight, ambientlight, lightdir); + cl.worldmodel->funcs.LightPointValues(cl.worldmodel, e->origin, shadelight, ambientlight, lightdir); } else { diff --git a/engine/gl/gl_heightmap.c b/engine/gl/gl_heightmap.c index 4de63400..b85ad465 100644 --- a/engine/gl/gl_heightmap.c +++ b/engine/gl/gl_heightmap.c @@ -593,7 +593,7 @@ void Heightmap_FindTouchedLeafs (model_t *mod, edict_t *ent) { } -void Heightmap_LightPointValues (vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir) +void Heightmap_LightPointValues (model_t *mod, vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir) { } void Heightmap_StainNode (mnode_t *node, float *parms) diff --git a/engine/gl/gl_hlmdl.c b/engine/gl/gl_hlmdl.c index 84b177ae..980171c9 100644 --- a/engine/gl/gl_hlmdl.c +++ b/engine/gl/gl_hlmdl.c @@ -525,7 +525,7 @@ void R_DrawHLModel(entity_t *curent) { vec3_t difuse, ambient, ldir; - cl.worldmodel->funcs.LightPointValues(curent->origin, difuse, ambient, ldir); + cl.worldmodel->funcs.LightPointValues(cl.worldmodel, curent->origin, difuse, ambient, ldir); qglColor4f(difuse[0]/255+ambient[0]/255, difuse[1]/255+ambient[1]/255, difuse[2]/255+ambient[2]/255, curent->shaderRGBAf[3]); } diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index bf23ebb9..1e574143 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -2557,7 +2557,7 @@ static void Q1BSP_StainNode (mnode_t *node, float *parms) void Q1BSP_MarkLights (dlight_t *light, int bit, mnode_t *node); qboolean Q1BSP_Trace(model_t *model, int forcehullnum, int frame, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, trace_t *trace); -void GLQ1BSP_LightPointValues(vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir); +void GLQ1BSP_LightPointValues(model_t *model, vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir); /* diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h index 1b770fa4..8de08a56 100644 --- a/engine/gl/gl_model.h +++ b/engine/gl/gl_model.h @@ -48,7 +48,7 @@ typedef struct { qboolean (*EdictInFatPVS) (struct model_s *model, struct edict_s *edict); void (*FindTouchedLeafs_Q1) (struct model_s *model, struct edict_s *ent); //edict system as opposed to q2 game dll system. - void (*LightPointValues) (vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir); + void (*LightPointValues) (struct model_s *model, vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir); void (*StainNode) (struct mnode_s *node, float *parms); void (*MarkLights) (struct dlight_s *light, int bit, struct mnode_s *node); diff --git a/engine/gl/gl_ppl.c b/engine/gl/gl_ppl.c index 1df695fb..0ff49654 100644 --- a/engine/gl/gl_ppl.c +++ b/engine/gl/gl_ppl.c @@ -89,11 +89,11 @@ qboolean PPL_ShouldDraw(void) { if (currententity->flags & Q2RF_EXTERNALMODEL) return false; - if (currententity->keynum == (cl.viewentity[r_refdef.currentplayernum]?cl.viewentity[r_refdef.currentplayernum]:(cl.playernum[r_refdef.currentplayernum]+1))) - return false; +// if (currententity->keynum == (cl.viewentity[r_refdef.currentplayernum]?cl.viewentity[r_refdef.currentplayernum]:(cl.playernum[r_refdef.currentplayernum]+1))) +// return false; // if (cl.viewentity[r_refdef.currentplayernum] && currententity->keynum == cl.viewentity[r_refdef.currentplayernum]) // continue; - if (!Cam_DrawPlayer(0, currententity->keynum-1)) + if (!Cam_DrawPlayer(r_refdef.currentplayernum, currententity->keynum-1)) return false; } return true; @@ -632,6 +632,9 @@ static void PPL_BaseChain_Bump_2TMU(msurface_t *first, texture_t *tex) } PPL_FlushArrays(); + qglEnable(GL_BLEND); + qglBlendFunc(GL_DST_COLOR, GL_ZERO); + GL_MBind(GL_TEXTURE0_ARB, tex->gl_texturenum); GL_SelectTexture(GL_TEXTURE1_ARB); @@ -665,6 +668,9 @@ static void PPL_BaseChain_Bump_2TMU(msurface_t *first, texture_t *tex) } PPL_FlushArrays(); + qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + qglDisable(GL_BLEND); + qglDisableClientState(GL_TEXTURE_COORD_ARRAY); GL_SelectTexture(GL_TEXTURE0_ARB); } diff --git a/engine/gl/gl_rlight.c b/engine/gl/gl_rlight.c index 7d218022..3b8b63c2 100644 --- a/engine/gl/gl_rlight.c +++ b/engine/gl/gl_rlight.c @@ -406,7 +406,7 @@ LIGHT SAMPLING mplane_t *lightplane; vec3_t lightspot; -void GLQ3_LightGrid(vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir) +void GLQ3_LightGrid(model_t *mod, vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir) { q3lightgridinfo_t *lg = (q3lightgridinfo_t *)cl.worldmodel->lightgrid; int index[8]; @@ -675,7 +675,7 @@ int GLR_LightPoint (vec3_t p) if (cl.worldmodel->fromgame == fg_quake3) { - GLQ3_LightGrid(p, NULL, end, NULL); + GLQ3_LightGrid(cl.worldmodel, p, NULL, end, NULL); return (end[0] + end[1] + end[2])/3; } @@ -904,7 +904,7 @@ float *GLRecursiveLightPoint3C (mnode_t *node, vec3_t start, vec3_t end) #endif -void GLQ1BSP_LightPointValues(vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir) +void GLQ1BSP_LightPointValues(model_t *model, vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir) { vec3_t end; float *r; @@ -913,7 +913,7 @@ void GLQ1BSP_LightPointValues(vec3_t point, vec3_t res_diffuse, vec3_t res_ambie end[1] = point[1]; end[2] = point[2] - 2048; - r = GLRecursiveLightPoint3C(cl.worldmodel->nodes, point, end); + r = GLRecursiveLightPoint3C(model->nodes, point, end); if (r == NULL) { res_diffuse[0] = 0; diff --git a/engine/gl/gl_rsurf.c b/engine/gl/gl_rsurf.c index 1acd8da7..db5e0618 100644 --- a/engine/gl/gl_rsurf.c +++ b/engine/gl/gl_rsurf.c @@ -244,7 +244,7 @@ void GLR_AddStain(vec3_t org, float red, float green, float blue, float radius) int i; float parms[7]; - if (!cl.worldmodel || r_stains.value <= 0) + if (!cl.worldmodel || cl.worldmodel->needload || r_stains.value <= 0) return; parms[0] = radius; parms[1] = org[0]; diff --git a/engine/gl/gl_screen.c b/engine/gl/gl_screen.c index 09c8a597..48e9d288 100644 --- a/engine/gl/gl_screen.c +++ b/engine/gl/gl_screen.c @@ -229,7 +229,9 @@ void GLSCR_UpdateScreen (void) else { GL_BeginRendering (&glx, &gly, &glwidth, &glheight); + scr_drawloading = true; SCR_DrawLoading (); + scr_drawloading = false; GL_EndRendering (); GL_DoSwap(); RSpeedEnd(RSPEED_TOTALREFRESH); diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index bda31b1c..fc95cf4a 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -327,7 +327,7 @@ void GLR_AnimateLight (void); void R_RenderDlights (void); int GLR_LightPoint (vec3_t p); -void GLQ3_LightGrid(vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_lightdir); +void GLQ3_LightGrid(model_t *mod, vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir); //gl_heightmap.c diff --git a/engine/gl/gltod3d/gl_fakegl.cpp b/engine/gl/gltod3d/gl_fakegl.cpp index b3306a22..1db6a4e9 100644 --- a/engine/gl/gltod3d/gl_fakegl.cpp +++ b/engine/gl/gltod3d/gl_fakegl.cpp @@ -48,8 +48,6 @@ the fact that it uses wrapper functions to call methods in a class could be a re #define WINGDIAPI DECLSPEC_IMPORT #endif - - #pragma warning( disable : 4244 ) #pragma warning( disable : 4820 ) diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index 05d508d8..1c4b23af 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -1075,6 +1075,33 @@ void QCC_PR_LexString (void) c = 30; else if (c == '>') c = 31; + else if (c == 'x' || c == 'X') + { + int d; + c = 0; + + d = (unsigned char)*pr_file_p++; + if (d >= '0' && d <= '9') + c += d - '0'; + else if (d >= 'A' && d <= 'F') + c += d - 'A' + 10; + else if (d >= 'a' && d <= 'f') + c += d - 'a' + 10; + else + QCC_PR_ParseError(ERR_BADCHARACTURECODE, "Bad character code"); + + c *= 16; + + d = (unsigned char)*pr_file_p++; + if (d >= '0' && d <= '9') + c += d - '0'; + else if (d >= 'A' && d <= 'F') + c += d - 'A' + 10; + else if (d >= 'a' && d <= 'f') + c += d - 'a' + 10; + else + QCC_PR_ParseError(ERR_BADCHARACTURECODE, "Bad character code"); + } else if (c == '\\') c = '\\'; else if (c == '\'') @@ -1364,6 +1391,16 @@ void QCC_PR_LexVector (void) { pr_immediate.vector[i] = QCC_PR_LexFloat (); QCC_PR_LexWhitespace (); + + if (*pr_file_p == '\'' && i == 1) + { + if (i < 2) + QCC_PR_ParseWarning (WARN_FTE_SPECIFIC, "Bad vector"); + + for (i++ ; i<3 ; i++) + pr_immediate.vector[i] = 0; + break; + } } if (*pr_file_p != '\'') QCC_PR_ParseError (ERR_INVALIDVECTORIMMEDIATE, "Bad vector"); diff --git a/engine/qclib/qccmain.c b/engine/qclib/qccmain.c index 1896b518..a7c03695 100644 --- a/engine/qclib/qccmain.c +++ b/engine/qclib/qccmain.c @@ -2912,7 +2912,7 @@ newstyle: strcpy (destfile, qcc_token); #ifndef QCCONLY - p=1; + p=0; s2 = strcpy(destfile2, destfile); if (!strncmp(s2, "./", 2)) s2+=2; @@ -2933,10 +2933,7 @@ newstyle: p--; } } - if (s>=qccmfilename) - sprintf(destfile, "%s%s", qccmfilename, s2); - else - sprintf(destfile, "%s", s2); + sprintf(destfile, "%s", s2); while (p>0) { diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 28a244cd..f8596027 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -3395,14 +3395,14 @@ void PF_sv_getlight (progfuncs_t *prinst, struct globalvars_s *pr_globals) vec3_t diffuse, ambient, dir; if (sv.worldmodel && sv.worldmodel->funcs.LightPointValues) { - sv.worldmodel->funcs.LightPointValues(point, diffuse, ambient, dir); + sv.worldmodel->funcs.LightPointValues(sv.worldmodel, point, diffuse, ambient, dir); VectorMA(ambient, 0.5, diffuse, G_VECTOR(OFS_RETURN)); } else { - G_FLOAT(OFS_RETURN+0) = 0.5; - G_FLOAT(OFS_RETURN+1) = 0.5; - G_FLOAT(OFS_RETURN+2) = 0.5; + G_FLOAT(OFS_RETURN+0) = 128; + G_FLOAT(OFS_RETURN+1) = 128; + G_FLOAT(OFS_RETURN+2) = 128; return; } } @@ -3928,33 +3928,11 @@ void PF_droptofloor (progfuncs_t *prinst, struct globalvars_s *pr_globals) } } -/* -=============== -PF_lightstyle - -void(float style, string value [, float colour]) lightstyle -=============== -*/ -void PF_lightstyle (progfuncs_t *prinst, struct globalvars_s *pr_globals) +void PF_applylightstyle(int style, char *val, int col) { - int style; - char *val; client_t *client; int j; -#ifdef PEXT_LIGHTSTYLECOL - int col; - if (*svprogfuncs->callargc >= 3) - { - col = G_FLOAT(OFS_PARM2); - if (IS_NAN(col) || !col || col > 0x111) - col = 7; - } - else col = 7; -#endif - - style = G_FLOAT(OFS_PARM0); - val = PR_GetStringOfs(prinst, OFS_PARM1); if (style < 0 || style >= MAX_LIGHTSTYLES) { @@ -4009,6 +3987,35 @@ void PF_lightstyle (progfuncs_t *prinst, struct globalvars_s *pr_globals) } } +/* +=============== +PF_lightstyle + +void(float style, string value [, float colour]) lightstyle +=============== +*/ +void PF_lightstyle (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + int style; + char *val; + +#ifdef PEXT_LIGHTSTYLECOL + int col; + if (*svprogfuncs->callargc >= 3) + { + col = G_FLOAT(OFS_PARM2); + if (IS_NAN(col) || !col || col > 0x111) + col = 7; + } + else col = 7; +#endif + + style = G_FLOAT(OFS_PARM0); + val = PR_GetStringOfs(prinst, OFS_PARM1); + + PF_applylightstyle(style, val, col); +} + void PF_lightstylevalue (progfuncs_t *prinst, struct globalvars_s *pr_globals) { int style; @@ -4026,8 +4033,6 @@ void PF_lightstylestatic (progfuncs_t *prinst, struct globalvars_s *pr_globals) int style; float num; char *val; - client_t *client; - int j; static char *styleDefs[] = { @@ -4056,56 +4061,7 @@ void PF_lightstylestatic (progfuncs_t *prinst, struct globalvars_s *pr_globals) num = 'z'-'a'-1; val = styleDefs[(int)num]; - - if (style < 0 || style >= MAX_LIGHTSTYLES) - { - Con_Printf("WARNING: Bad lightstyle %i.\n", style); - return; - } - if (strlen(val) > MAX_STYLESTRING-1) - Con_Printf("WARNING: Style string is longer than standard (%i). Some clients could crash.\n", MAX_STYLESTRING-1); - - -// change the string in sv - if (sv.strings.lightstyles[style]) - Z_Free(sv.strings.lightstyles[style]); - sv.strings.lightstyles[style] = Z_Malloc(strlen(val)+1); - strcpy(sv.strings.lightstyles[style], val); -// sv.lightstyles[style] = val; -#ifdef PEXT_LIGHTSTYLECOL - sv.strings.lightstylecolours[style] = col; -#endif - -// send message to all clients on this server - if (sv.state != ss_active) - return; - - for (j=0, client = svs.clients ; jcontroller) - continue; - - if ( client->state == cs_spawned ) - { -#ifdef PEXT_LIGHTSTYLECOL - if ((client->fteprotocolextensions & PEXT_LIGHTSTYLECOL) && col!=7) - { - ClientReliableWrite_Begin (client, svc_lightstylecol, strlen(val)+4); - ClientReliableWrite_Char (client, style); - ClientReliableWrite_Char (client, col); - ClientReliableWrite_String (client, val); - } - else - { -#endif - ClientReliableWrite_Begin (client, svc_lightstyle, strlen(val)+3); - ClientReliableWrite_Char (client, style); - ClientReliableWrite_String (client, val); -#ifdef PEXT_LIGHTSTYLECOL - } -#endif - } - } + PF_applylightstyle(style, val, col); } void PF_rint (progfuncs_t *prinst, struct globalvars_s *pr_globals) @@ -9188,7 +9144,7 @@ void PF_getsurfacenearpoint(progfuncs_t *prinst, struct globalvars_s *pr_globals surf = model->surfaces; - for (i = model->numsurfaces; i; i--, surf = surf++) + for (i = model->numsurfaces; i; i--, surf++) { if (surf->flags & SURF_PLANEBACK) planedist = -DotProduct(point, surf->plane->normal); diff --git a/engine/server/server.h b/engine/server/server.h index 99ec4042..6f2ea618 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -513,6 +513,11 @@ typedef struct client_s int rate; int drate; + + netadr_t realip; + int realip_status; + int realip_num; + int realip_ping; } client_t; #define ISQWCLIENT(cl) ((cl)->protocol == SCP_QUAKEWORLD) @@ -616,6 +621,7 @@ typedef struct int forceFrame; struct mvddest_s *dest; + struct mvdpendingdest_s *pendingdest; } demo_t; diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index 71caa09d..f653c0b4 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -488,14 +488,17 @@ void SV_Map_f (void) startspot = spot; } - COM_FlushFSCache(); - // check to make sure the level exists if (*level == '*') { memmove(level, level+1, strlen(level)); newunit=true; } +#ifndef SERVERONLY + SCR_ImageName(level); +#endif + + COM_FlushFSCache(); if (strlen(level) > 4 && !strcmp(level + strlen(level)-4, ".cin")) { @@ -573,14 +576,15 @@ void SV_Map_f (void) svs.clients[i].state=cs_connected; } - SV_BroadcastCommand ("changing\n"); - SV_SendMessagesToAll (); - #ifndef SERVERONLY S_StopAllSounds (true); - SCR_BeginLoadingPlaque(); +// SCR_BeginLoadingPlaque(); + SCR_ImageName(level); #endif + SV_BroadcastCommand ("changing \"%s\"\n", level); + SV_SendMessagesToAll (); + if (newunit || !startspot || !SV_LoadLevelCache(level, startspot, false)) { if (waschangelevel && !startspot) diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 32f6e749..29d4c257 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -581,7 +581,8 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us total_loading_size = 100; current_loading_size = 0; loading_stage = 1; - SCR_BeginLoadingPlaque(); +// SCR_BeginLoadingPlaque(); + SCR_ImageName(server); #endif NET_InitServer(); @@ -711,7 +712,8 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us strcpy (sv.name, server); #ifndef SERVERONLY current_loading_size+=10; - SCR_BeginLoadingPlaque(); + //SCR_BeginLoadingPlaque(); + SCR_ImageName(server); #endif Cvar_ApplyLatches(CVAR_LATCH); @@ -772,12 +774,14 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us #ifndef SERVERONLY current_loading_size+=10; - SCR_BeginLoadingPlaque(); +// SCR_BeginLoadingPlaque(); + SCR_ImageName(server); #endif SV_CalcPHS (); #ifndef SERVERONLY current_loading_size+=10; - SCR_BeginLoadingPlaque(); + //SCR_BeginLoadingPlaque(); + SCR_ImageName(server); #endif if (sv.worldmodel->fromgame == fg_doom) @@ -921,7 +925,8 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us #ifndef SERVERONLY current_loading_size+=10; - SCR_BeginLoadingPlaque(); + //SCR_BeginLoadingPlaque(); + SCR_ImageName(server); #endif for (i=0 ; i= MAX_CLIENTS) + { + //a malitious user + return; + } + + if (cookie != svs.clients[slotnum].realip_num) + { + //could be someone trying to kick someone else + //so we can't kick, as much as we might like to. + return; + } + + if (svs.clients[slotnum].realip_status) + return; + + + svs.clients[slotnum].realip_status = 1; + svs.clients[slotnum].realip = net_from; +} + +void SVC_ACK (void) +{ + int slotnum; + for (slotnum = 0; slotnum < MAX_CLIENTS; slotnum++) + { + if (svs.clients[slotnum].state) + { + if (svs.clients[slotnum].realip_status == 1 && NET_CompareAdr(svs.clients[slotnum].realip, net_from)) + { + if (!*Cmd_Argv(1)) + svs.clients[slotnum].realip_status = 2; + else if (atoi(Cmd_Argv(1)) == svs.clients[slotnum].realip_ping && + atoi(Cmd_Argv(2)) == svs.clients[slotnum].realip_num) + { + svs.clients[slotnum].realip_status = 3; + } + else + { + Netchan_OutOfBandPrint(NS_SERVER, net_from, "realip not accepted. Please stop hacking.\n"); + } + return; + } + } + } + Con_Printf ("A2A_ACK from %s\n", NET_AdrToString (net_from)); +} + /* ================= SV_ConnectionlessPacket @@ -2231,7 +2286,7 @@ qboolean SV_ConnectionlessPacket (void) if (!strcmp(c, "ping") || ( c[0] == A2A_PING && (c[1] == 0 || c[1] == '\n')) ) SVC_Ping (); else if (c[0] == A2A_ACK && (c[1] == 0 || c[1] == '\n') ) - Con_Printf ("A2A_ACK from %s\n", NET_AdrToString (net_from)); + SVC_ACK (); else if (!strcmp(c,"status")) SVC_Status (); else if (!strcmp(c,"log")) @@ -2272,6 +2327,8 @@ qboolean SV_ConnectionlessPacket (void) #endif else if (!strcmp(c, "rcon")) SVC_RemoteCommand (); + else if (!strcmp(c, "realip")) + SVC_RealIP (); else if (!PR_GameCodePacket(net_message.data+4)) Con_Printf ("bad connectionless packet from %s:\n%s\n" , NET_AdrToString (net_from), s); diff --git a/engine/server/sv_mvd.c b/engine/server/sv_mvd.c index 04d249f3..13d27653 100644 --- a/engine/server/sv_mvd.c +++ b/engine/server/sv_mvd.c @@ -30,6 +30,24 @@ void SV_MVDStop_f (void); #define demo_size_padding 0x1000 +//qtv proxies are meant to send a small header now, bit like http +//this header gives supported version numbers and stuff +typedef struct mvdpendingdest_s { + qboolean error; //disables writers, quit ASAP. + int socket; + + char inbuffer[2048]; + char outbuffer[2048]; + + char challenge[64]; + int hasauthed; + + int insize; + int outsize; + + struct mvdpendingdest_s *nextdest; +} mvdpendingdest_t; + typedef struct mvddest_s { qboolean error; //disables writers, quit ASAP. @@ -51,6 +69,10 @@ typedef struct mvddest_s { } mvddest_t; mvddest_t *singledest; +mvddest_t *SV_InitStream(int socket); +static qboolean SV_MVD_Record (mvddest_t *dest); +extern cvar_t qtv_password; + void DestClose(mvddest_t *d, qboolean destroyfiles) { char path[MAX_OSPATH]; @@ -151,6 +173,364 @@ void DestFlush(qboolean compleate) } } +void SV_MVD_RunPendingConnections(void) +{ + unsigned short ushort_result; + char *e; + int len; + mvdpendingdest_t *p; + mvdpendingdest_t *np; + + if (!demo.pendingdest) + return; + + while (demo.pendingdest && demo.pendingdest->error) + { + np = demo.pendingdest->nextdest; + + if (demo.pendingdest->socket != -1) + closesocket(demo.pendingdest->socket); + Z_Free(demo.pendingdest); + demo.pendingdest = np; + } + + for (p = demo.pendingdest; p && p->nextdest; p = p->nextdest) + { + if (p->nextdest->error) + { + np = p->nextdest->nextdest; + if (p->nextdest->socket != -1) + closesocket(p->nextdest->socket); + Z_Free(p->nextdest); + p->nextdest = np; + } + } + + for (p = demo.pendingdest; p; p = p->nextdest) + { + if (p->outsize && !p->error) + { + len = send(p->socket, p->outbuffer, p->outsize, 0); + if (len == 0) //client died + p->error = true; + else if (len > 0) //we put some data through + { //move up the buffer + p->outsize -= len; + memmove(p->outbuffer, p->outbuffer+len, p->outsize ); + } + else + { //error of some kind. would block or something + int e; + e = qerrno; + if (e != EWOULDBLOCK) + p->error = true; + } + } + if (!p->error) + { + len = recv(p->socket, p->inbuffer + p->insize, sizeof(p->inbuffer) - p->insize - 1, 0); + if (len > 0) + {//fixme: cope with extra \rs + char *end; + p->insize += len; + p->inbuffer[p->insize] = 0; + + for (end = p->inbuffer; ; end++) + { + if (*end == '\0') + { + end = NULL; + break; //not enough data + } + + if (end[0] == '\n') + { + if (end[1] == '\n') + { + end[1] = '\0'; + break; + } + } + } + if (end) + { //we found the end of the header + char *start, *lineend; + int versiontouse = 0; + int raw = 0; + char password[256] = ""; + enum { + QTVAM_NONE, + QTVAM_PLAIN, + QTVAM_CCITT, + QTVAM_MD4, + QTVAM_MD5, + } authmethod = QTVAM_NONE; + + start = p->inbuffer; + + lineend = strchr(start, '\n'); + if (!lineend) + { +// char *e; +// e = "This is a QTV server."; +// send(p->socket, e, strlen(e), 0); + + p->error = true; + continue; + } + *lineend = '\0'; + COM_ParseToken(start, NULL); + start = lineend+1; + if (strcmp(com_token, "QTV")) + { //it's an error if it's not qtv. + p->error = true; + lineend = strchr(start, '\n'); + continue; + } + + for(;;) + { + lineend = strchr(start, '\n'); + if (!lineend) + break; + *lineend = '\0'; + start = COM_ParseToken(start, NULL); + if (*start == ':') + { +//VERSION: a list of the different qtv protocols supported. Multiple versions can be specified. The first is assumed to be the prefered version. +//RAW: if non-zero, send only a raw mvd with no additional markup anywhere (for telnet use). Doesn't work with challenge-based auth, so will only be accepted when proxy passwords are not required. +//AUTH: specifies an auth method, the exact specs varies based on the method +// PLAIN: the password is sent as a PASSWORD line +// MD4: the server responds with an "AUTH: MD4\n" line as well as a "CHALLENGE: somerandomchallengestring\n" line, the client sends a new 'initial' request with CHALLENGE: MD4\nRESPONSE: hexbasedmd4checksumhere\n" +// MD5: same as md4 +// CCITT: same as md4, but using the CRC stuff common to all quake engines. +// if the supported/allowed auth methods don't match, the connection is silently dropped. +//SOURCE: which stream to play from, DEFAULT is special. Without qualifiers, it's assumed to be a tcp address. +//COMPRESSION: Suggests a compression method (multiple are allowed). You'll get a COMPRESSION response, and compression will begin with the binary data. + + start = start+1; + Con_Printf("qtv, got (%s) (%s)\n", com_token, start); + if (!strcmp(com_token, "VERSION")) + { + start = COM_ParseToken(start, NULL); + if (atoi(com_token) == 1) + versiontouse = 1; + } + else if (!strcmp(com_token, "RAW")) + { + start = COM_ParseToken(start, NULL); + raw = atoi(com_token); + } + else if (!strcmp(com_token, "PASSWORD")) + { + start = COM_ParseToken(start, NULL); + Q_strncpyz(password, com_token, sizeof(password)); + } + else if (!strcmp(com_token, "AUTH")) + { + int thisauth; + start = COM_ParseToken(start, NULL); + if (!strcmp(com_token, "NONE")) + thisauth = QTVAM_PLAIN; + else if (!strcmp(com_token, "PLAIN")) + thisauth = QTVAM_PLAIN; + else if (!strcmp(com_token, "CCIT")) + thisauth = QTVAM_CCITT; + else if (!strcmp(com_token, "MD4")) + thisauth = QTVAM_MD4; +// else if (!strcmp(com_token, "MD5")) +// thisauth = QTVAM_MD5; + else + { + thisauth = QTVAM_NONE; + Con_DPrintf("qtv: received unrecognised auth method (%s)\n", com_token); + } + + if (authmethod < thisauth) + authmethod = thisauth; + } + else if (!strcmp(com_token, "SOURCE")) + { + //servers don't support source, and ignore it. + //source is only useful for qtv proxy servers. + } + else if (!strcmp(com_token, "COMPRESSION")) + { + //compression not supported yet + } + else + { + //not recognised. + } + } + start = lineend+1; + } + + len = (end - p->inbuffer)+2; + p->insize -= len; + memmove(p->inbuffer, p->inbuffer + len, p->insize); + p->inbuffer[p->insize] = 0; + + e = NULL; + if (p->hasauthed) + { + } + else if (!*qtv_password.string) + p->hasauthed = true; //no password, no need to auth. + else if (*password) + { + switch (authmethod) + { + case QTVAM_NONE: + e = ("QTVSV 1\n" + "PERROR: You need to provide a common auth method.\n\n"); + break; + case QTVAM_PLAIN: + p->hasauthed = !strcmp(qtv_password.string, password); + break; + case QTVAM_CCITT: + QCRC_Init(&ushort_result); + QCRC_AddBlock(&ushort_result, p->challenge, strlen(p->challenge)); + QCRC_AddBlock(&ushort_result, qtv_password.string, strlen(qtv_password.string)); + p->hasauthed = (ushort_result == atoi(password)); + break; + case QTVAM_MD4: + { + char hash[512]; + int md4sum[4]; + + snprintf(hash, sizeof(hash), "%s%s", p->challenge, qtv_password.string); + Com_BlockFullChecksum (hash, strlen(hash), (unsigned char*)md4sum); + sprintf(hash, "%X%X%X%X", md4sum[0], md4sum[1], md4sum[2], md4sum[3]); + p->hasauthed = !strcmp(password, hash); + } + break; + case QTVAM_MD5: + default: + e = ("QTVSV 1\n" + "PERROR: FTEQWSV bug detected.\n\n"); + break; + } + if (!p->hasauthed && !e) + { + if (raw) + e = ""; + else + e = ("QTVSV 1\n" + "PERROR: Bad password.\n\n"); + } + } + else + { + //no password, and not automagically authed + switch (authmethod) + { + case QTVAM_NONE: + if (raw) + e = ""; + else + e = ("QTVSV 1\n" + "PERROR: You need to provide a common auth method.\n\n"); + break; + case QTVAM_PLAIN: + p->hasauthed = !strcmp(qtv_password.string, password); + break; + + if (0) + { + case QTVAM_CCITT: + e = ("QTVSV 1\n" + "AUTH: CCITT\n" + "CHALLENGE: "); + } + else if (0) + { + case QTVAM_MD4: + e = ("QTVSV 1\n" + "AUTH: MD4\n" + "CHALLENGE: "); + } + else + { + case QTVAM_MD5: + e = ("QTVSV 1\n" + "AUTH: MD5\n" + "CHALLENGE: "); + } + + send(p->socket, e, strlen(e), 0); + send(p->socket, p->challenge, strlen(p->challenge), 0); + e = "\n\n"; + send(p->socket, e, strlen(e), 0); + continue; + + default: + e = ("QTVSV 1\n" + "PERROR: FTEQWSV bug detected.\n\n"); + break; + } + } + + if (e) + { + } + else if (!versiontouse) + { + e = ("QTVSV 1\n" + "PERROR: Incompatable version (valid version is v1)\n\n"); + } + else if (raw) + { + if (p->hasauthed == false) + { + e = ""; + } + else + { + SV_MVD_Record(SV_InitStream(p->socket)); + p->socket = -1; //so it's not cleared wrongly. + } + p->error = true; + } + else + { + if (p->hasauthed == true) + { + e = ("QTVSV 1\n" + "\n"); + send(p->socket, e, strlen(e), 0); + e = NULL; + SV_MVD_Record(SV_InitStream(p->socket)); + p->socket = -1; //so it's not cleared wrongly. + } + else + { + e = ("QTVSV 1\n" + "PERROR: You need to provide a password.\n\n"); + } + p->error = true; + } + + if (e) + { + send(p->socket, e, strlen(e), 0); + p->error = true; + } + } + } + else if (len == 0) + p->error = true; + else + { //error of some kind. would block or something + int e; + e = qerrno; + if (e != EWOULDBLOCK) + p->error = true; + } + } + } +} + void DestCloseAllFlush(qboolean destroyfiles) { mvddest_t *d; @@ -192,7 +572,7 @@ int DemoWriteDest(void *data, int len, mvddest_t *d) return len; } -int DemoWrite(void *data, int len) //broadcast to all proxies +int DemoWrite(void *data, int len) //broadcast to all proxies/mvds { mvddest_t *d; for (d = demo.dest; d; d = d->nextdest) @@ -204,6 +584,36 @@ int DemoWrite(void *data, int len) //broadcast to all proxies return len; } +void DemoWriteQTVTimePad(int msecs) //broadcast to all proxies +{ + mvddest_t *d; + unsigned char buffer[6]; + while (msecs > 0) + { + //duration + if (msecs > 255) + buffer[0] = 255; + else + buffer[0] = msecs; + msecs -= buffer[0]; + //message type + buffer[1] = dem_read; + //length + buffer[2] = 0; + buffer[3] = 0; + buffer[4] = 0; + buffer[5] = 0; + + for (d = demo.dest; d; d = d->nextdest) + { + if (d->desttype == DEST_STREAM) + { + DemoWriteDest(buffer, sizeof(buffer), d); + } + } + } +} + void SV_TimeOfDay(date_t *date) { @@ -395,8 +805,9 @@ cvar_t sv_demoNoVis = SCVAR("sv_demoNoVis", ""); cvar_t sv_demoMaxSize = SCVAR("sv_demoMaxSize", ""); cvar_t sv_demoExtraNames = SCVAR("sv_demoExtraNames", ""); -cvar_t mvd_streamport = SCVAR("mvd_streamport", "0"); -cvar_t mvd_maxstreams = SCVAR("mvd_maxstreams", "1"); +cvar_t qtv_password = SCVAR("qtv_password", ""); +cvar_t qtv_streamport = FCVAR("qtv_streamport", "mvd_streamport", "0", 0); +cvar_t qtv_maxstreams = FCVAR("qtv_maxstreams", "mvd_maxstreams", "1", 0); cvar_t sv_demoPrefix = SCVAR("sv_demoPrefix", ""); cvar_t sv_demoSuffix = SCVAR("sv_demoSuffix", ""); @@ -1071,6 +1482,21 @@ mvddest_t *SV_InitStream(int socket) return dst; } +void SV_MVD_InitPendingStream(int socket, char *ip) +{ + mvdpendingdest_t *dst; + int i; + dst = Z_Malloc(sizeof(mvdpendingdest_t)); + dst->socket = socket; + + Q_strncpyz(dst->challenge, ip, sizeof(dst->challenge)); + for (i = strlen(dst->challenge); i < sizeof(dst->challenge)-1; i++) + dst->challenge[i] = rand()%(127-33) + 33; //generate a random challenge + + dst->nextdest = demo.pendingdest; + demo.pendingdest = dst; +} + /* ==================== SV_Stop @@ -1739,37 +2165,6 @@ void SV_MVDEasyRecord_f (void) return; } - // -> scream -/* if (c == 2) - Q_strncpyz (name, Cmd_Argv(1), sizeof(name)); - - else { - // guess game type and write demo name - i = Dem_CountPlayers(); - if (teamplay.value && i > 2) - { - // Teamplay - snprintf (name, sizeof(name), "team_%s_vs_%s_%s", - Dem_Team(1), - Dem_Team(2), - sv.name); - } else { - if (i == 2) { - // Duel - snprintf (name, sizeof(name), "duel_%s_vs_%s_%s", - Dem_PlayerName(1), - Dem_PlayerName(2), - sv.name); - } else { - // FFA - snprintf (name, sizeof(name), "ffa_%s(%d)", - sv.name, - i); - } - } - }*/ - - if (c == 2) Q_strncpyz (name, Cmd_Argv(1), sizeof(name)); else @@ -1881,22 +2276,31 @@ void SV_MVDStream_Poll(void) int count; qboolean wanted; mvddest_t *dest; + char *ip; - if (!sv.state || !mvd_streamport.value) + if (!sv.state || !qtv_streamport.value) wanted = false; - else if (listenport && (int)mvd_streamport.value != listenport) //easy way to switch... disable for a frame. :) + else if (listenport && (int)qtv_streamport.value != listenport) //easy way to switch... disable for a frame. :) { - listenport = mvd_streamport.value; + listenport = qtv_streamport.value; wanted = false; } else { - listenport = mvd_streamport.value; + listenport = qtv_streamport.value; wanted = true; } if (wanted && listensocket==INVALID_SOCKET) + { listensocket = MVD_StreamStartListening(listenport); + if (listensocket==INVALID_SOCKET && qtv_streamport.modified) + { + Con_Printf("Cannot open TCP port %i for QTV\n", listenport); + qtv_streamport.modified = false; + } + + } else if (!wanted && listensocket!=INVALID_SOCKET) { closesocket(listensocket); @@ -1912,7 +2316,7 @@ void SV_MVDStream_Poll(void) if (client == INVALID_SOCKET) return; - if (mvd_maxstreams.value > 0) + if (qtv_maxstreams.value > 0) { count = 0; for (dest = demo.dest; dest; dest = dest->nextdest) @@ -1923,28 +2327,23 @@ void SV_MVDStream_Poll(void) } } - if (count > mvd_maxstreams.value) + if (count > qtv_maxstreams.value) { //sorry - char *goawaymessage = "This server enforces a limit on the number of proxies connected at any one time. Please try again later\n"; - char packetheader[6]; - packetheader[0] = 1; - packetheader[1] = dem_all; - packetheader[2] = strlen(goawaymessage)+1; - packetheader[3] = 0; - packetheader[4] = 0; - packetheader[5] = 0; + char *goawaymessage = "QTVSV 1\nERROR: This server enforces a limit on the number of proxies connected at any one time. Please try again later\n\n"; - send(client, packetheader, sizeof(packetheader), 0); - send(client, goawaymessage, strlen(goawaymessage)+1, 0); + send(client, goawaymessage, strlen(goawaymessage), 0); closesocket(client); return; } } SockadrToNetadr(&addr, &na); - Con_Printf("MVD streaming client connected from %s\n", NET_AdrToString(na)); + ip = NET_AdrToString(na); + Con_Printf("MVD streaming client attempting to connect from %s\n", ip); - SV_MVD_Record (SV_InitStream(client)); + SV_MVD_InitPendingStream(client, ip); + +// SV_MVD_Record (SV_InitStream(client)); } void SV_MVDList_f (void) @@ -2357,8 +2756,9 @@ void SV_MVDInit(void) Cmd_AddCommand ("rmdemo", SV_MVDRemove_f); Cmd_AddCommand ("rmdemonum", SV_MVDRemoveNum_f); - Cvar_Register(&mvd_streamport, "MVD Streaming"); - Cvar_Register(&mvd_maxstreams, "MVD Streaming"); + Cvar_Register(&qtv_streamport, "MVD Streaming"); + Cvar_Register(&qtv_maxstreams, "MVD Streaming"); + Cvar_Register(&qtv_password, "MVD Streaming"); } #endif diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index db1c8a0e..ef179d75 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -759,6 +759,9 @@ qboolean SV_Push (edict_t *pusher, vec3_t move, vec3_t amove) block = SV_TestEntityPosition (check); if (!block) { + //if leaving it where it was, allow it to drop to the floor again (useful for plats that move downward) + check->v->flags = (int)check->v->flags & ~FL_ONGROUND; + num_moved--; continue; } @@ -1914,6 +1917,7 @@ qboolean SV_Physics (void) old_time = sv.time; host_frametime = 0; } + if (svs.gametype != GT_QUAKE3) if (host_frametime < sv_maxtic.value && realtime) { // sv.time+=host_frametime; diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index 907c5ea8..5576a951 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -1914,7 +1914,7 @@ void SV_SendClientMessages (void) #endif - +void DemoWriteQTVTimePad(int msecs); #define Max(a, b) ((a>b)?a:b) void SV_SendMVDMessage(void) { @@ -1929,6 +1929,8 @@ void SV_SendMVDMessage(void) extern cvar_t sv_demoPings; // extern cvar_t sv_demoMaxSize; + SV_MVD_RunPendingConnections(); + if (!sv.mvdrecording) return; @@ -1959,8 +1961,12 @@ void SV_SendMVDMessage(void) cls |= 1 << i; } - if (!cls) { + if (!cls) + { SZ_Clear (&demo.datagram); + DemoWriteQTVTimePad((int)((sv.time - demo.time)*1000)); + DestFlush(false); + demo.time = sv.time; return; } diff --git a/engine/server/sv_sys_win.c b/engine/server/sv_sys_win.c index a6b0de14..bfa9d295 100644 --- a/engine/server/sv_sys_win.c +++ b/engine/server/sv_sys_win.c @@ -367,7 +367,7 @@ double Sys_DoubleTime (void) static int starttime; _ftime( &tstruct ); - + if (!starttime) starttime = tstruct.time; t = (tstruct.time-starttime) + tstruct.millitm*0.001; diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 39018993..be44ffb4 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -107,6 +107,60 @@ host_client and sv_player will be valid. ============================================================ */ +qboolean SV_CheakRealIP(client_t *client, qboolean force) +{ + //returns true if they have a real ip + cvar_t *sv_getrealip; + char *serverip; + char *msg; + + sv_getrealip = Cvar_Get("sv_getrealip", "0", 0, "Experimental cvars"); + + if (!sv_getrealip || !sv_getrealip->value) + return true; + + if (client->netchan.remote_address.type == NA_LOOPBACK) + return true; //the loopback client doesn't have to pass realip checks + + if (client->realip_status == 3) + return true; //we know that the ip is authentic + if (client->realip_status == 2) + { + ClientReliableWrite_Begin(client, svc_print, 256); + ClientReliableWrite_Byte(client, svc_print); + ClientReliableWrite_Byte(client, PRINT_HIGH); + ClientReliableWrite_String(client, "Couldn't verify your real ip\n"); + return true; //client doesn't support certainty. + } + if (client->realip_status == -1) + return true; //can't get a better answer + + if (realtime - host_client->connection_started > 10) + { + client->realip_status = -1; + ClientReliableWrite_Begin(client, svc_print, 256); + ClientReliableWrite_Byte(client, svc_print); + ClientReliableWrite_Byte(client, PRINT_HIGH); + ClientReliableWrite_String(client, "Couldn't determine your real ip\n"); + return true; + } + + + if (client->realip_status == 1) + { + msg = va("\xff\xff\xff\xff%c %i", A2A_PING, client->realip_ping); + NET_SendPacket(NS_SERVER, strlen(msg), msg, client->realip); + } + else + { + serverip = NET_AdrToString (net_local_sv_ipadr); + + ClientReliableWrite_Byte(client, svc_stufftext); + ClientReliableWrite_String(client, va("packet %s \"realip %i %i\"\n", serverip, client-svs.clients, client->realip_num)); + } + return false; +} + /* ================ SV_New_f @@ -125,6 +179,8 @@ void SV_New_f (void) if (host_client->state == cs_spawned) return; + SV_CheakRealIP(host_client, false); + /* splitt delay host_client->state = cs_connected; host_client->connection_started = realtime; @@ -1236,6 +1292,16 @@ void SV_Begin_f (void) int i; qboolean sendangles=false; + if (!SV_CheakRealIP(host_client, true)) + { + if (host_client->protocol == SCP_QUAKE2) + ClientReliableWrite_Begin (host_client, svcq2_stufftext, 13+strlen(Cmd_Args())); + else + ClientReliableWrite_Begin (host_client, svc_stufftext, 13+strlen(Cmd_Args())); + ClientReliableWrite_String (host_client, va("cmd begin %s\n", Cmd_Args())); + return; + } + if (host_client->state == cs_spawned) return; // don't begin again diff --git a/engine/server/svmodel.c b/engine/server/svmodel.c index 36655ce5..6adf4a94 100644 --- a/engine/server/svmodel.c +++ b/engine/server/svmodel.c @@ -43,8 +43,155 @@ int mod_numknown; texture_t r_notexture_mip_real; texture_t *r_notexture_mip = &r_notexture_mip_real; +cvar_t sv_nogetlight = SCVAR("sv_nogetlight", "0"); + unsigned *model_checksum; + +int SVQ1_RecursiveLightPoint3C (model_t *model, mnode_t *node, vec3_t start, vec3_t end) +{ + int r; + float front, back, frac; + int side; + mplane_t *plane; + vec3_t mid; + msurface_t *surf; + int s, t, ds, dt; + int i; + mtexinfo_t *tex; + qbyte *lightmap; + unsigned scale; + int maps; + + + if (model->fromgame == fg_quake2) + { + if (node->contents != -1) + return -1; // solid + } + else + { + if (node->contents < 0) + return -1; // didn't hit anything + } + +// calculate mid point + +// FIXME: optimize for axial + plane = node->plane; + front = DotProduct (start, plane->normal) - plane->dist; + back = DotProduct (end, plane->normal) - plane->dist; + side = front < 0; + + if ( (back < 0) == side) + return SVQ1_RecursiveLightPoint3C (model, node->children[side], start, end); + + frac = front / (front-back); + mid[0] = start[0] + (end[0] - start[0])*frac; + mid[1] = start[1] + (end[1] - start[1])*frac; + mid[2] = start[2] + (end[2] - start[2])*frac; + +// go down front side + r = SVQ1_RecursiveLightPoint3C (model, node->children[side], start, mid); + if (r >= 0) + return r; // hit something + + if ( (back < 0) == side ) + return -1; // didn't hit anuthing + +// check for impact on this node + + surf = model->surfaces + node->firstsurface; + for (i=0 ; inumsurfaces ; i++, surf++) + { + if (surf->flags & SURF_DRAWTILED) + continue; // no lightmaps + + tex = surf->texinfo; + + s = DotProduct (mid, tex->vecs[0]) + tex->vecs[0][3]; + t = DotProduct (mid, tex->vecs[1]) + tex->vecs[1][3];; + + if (s < surf->texturemins[0] || + t < surf->texturemins[1]) + continue; + + ds = s - surf->texturemins[0]; + dt = t - surf->texturemins[1]; + + if ( ds > surf->extents[0] || dt > surf->extents[1] ) + continue; + + if (!surf->samples) + return 0; + + ds >>= 4; + dt >>= 4; + + lightmap = surf->samples; + r = 0; + if (lightmap) + { + + lightmap += (dt * ((surf->extents[0]>>4)+1) + ds)*3; + + for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + maps++) + { + scale = sv.strings.lightstyles[surf->styles[maps]][0]; + r += (lightmap[0]+lightmap[1]+lightmap[2])/3 * scale; + lightmap += ((surf->extents[0]>>4)+1) * + ((surf->extents[1]>>4)+1)*3; + } + + r >>= 8; + } + + return r; + } + +// go down back side + return SVQ1_RecursiveLightPoint3C (model, node->children[!side], mid, end); +} + +void SVQ1_LightPointValues(model_t *model, vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir) +{ + vec3_t end; + float r; + + res_dir[0] = 0; //software doesn't load luxes + res_dir[1] = 1; + res_dir[2] = 1; + + end[0] = point[0]; + end[1] = point[1]; + end[2] = point[2] - 2048; + + r = SVQ1_RecursiveLightPoint3C (model, model->nodes, point, end); + if (r < 0) + { + res_diffuse[0] = 0; + res_diffuse[1] = 0; + res_diffuse[2] = 0; + + res_ambient[0] = 0; + res_ambient[1] = 0; + res_ambient[2] = 0; + } + else + { + res_diffuse[0] = r; + res_diffuse[1] = r; + res_diffuse[2] = r; + + res_ambient[0] = r; + res_ambient[1] = r; + res_ambient[2] = r; + } +} + + + /* =============== Mod_Init @@ -53,6 +200,7 @@ Mod_Init void Mod_Init (void) { memset (mod_novis, 0xff, sizeof(mod_novis)); + Cvar_Register(&sv_nogetlight, "Memory preservation"); } /* @@ -514,15 +662,38 @@ void Mod_LoadTextures (lump_t *l) Mod_LoadLighting ================= */ -void Mod_LoadLighting (lump_t *l) +qboolean Mod_LoadLighting (lump_t *l) { + int i; + char *in; + char *out; if (!l->filelen) { loadmodel->lightdata = NULL; - return; + return true; } - loadmodel->lightdata = Hunk_AllocName ( l->filelen, loadname); - memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen); + + if (loadmodel->fromgame == fg_halflife) + { + loadmodel->lightdata = Hunk_AllocName ( l->filelen, loadname); + memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen); + } + else + { + loadmodel->lightdata = Hunk_AllocName ( l->filelen*3, loadname); + + in = mod_base + l->fileofs; + out = loadmodel->lightdata; + + for (i = 0; i < l->filelen; i++) + { + *out++ = *in; + *out++ = *in; + *out++ = *in++; + } + } + + return true; } @@ -566,7 +737,7 @@ void Mod_LoadEntities (lump_t *l) Mod_LoadVertexes ================= */ -void Mod_LoadVertexes (lump_t *l) +qboolean Mod_LoadVertexes (lump_t *l) { dvertex_t *in; mvertex_t *out; @@ -574,7 +745,10 @@ void Mod_LoadVertexes (lump_t *l) in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) - SV_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + { + Con_Printf ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + return false; + } count = l->filelen / sizeof(*in); out = Hunk_AllocName ( count*sizeof(*out), loadname); @@ -587,6 +761,7 @@ void Mod_LoadVertexes (lump_t *l) out->position[1] = LittleFloat (in->point[1]); out->position[2] = LittleFloat (in->point[2]); } + return true; } /* @@ -690,7 +865,7 @@ qboolean Mod_LoadSubmodels (lump_t *l) Mod_LoadEdges ================= */ -void Mod_LoadEdges (lump_t *l) +qboolean Mod_LoadEdges (lump_t *l) { dedge_t *in; medge_t *out; @@ -698,7 +873,10 @@ void Mod_LoadEdges (lump_t *l) in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) - SV_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + { + Con_Printf ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + return false; + } count = l->filelen / sizeof(*in); out = Hunk_AllocName ( (count + 1) * sizeof(*out), loadname); @@ -710,6 +888,7 @@ void Mod_LoadEdges (lump_t *l) out->v[0] = (unsigned short)LittleShort(in->v[0]); out->v[1] = (unsigned short)LittleShort(in->v[1]); } + return true; } /* @@ -717,7 +896,7 @@ void Mod_LoadEdges (lump_t *l) Mod_LoadTexinfo ================= */ -void Mod_LoadTexinfo (lump_t *l) +qboolean Mod_LoadTexinfo (lump_t *l) { texinfo_t *in; mtexinfo_t *out; @@ -727,7 +906,10 @@ void Mod_LoadTexinfo (lump_t *l) in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) - SV_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + { + Con_Printf ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + return false; + } count = l->filelen / sizeof(*in); out = Hunk_AllocName ( count*sizeof(*out), loadname); @@ -774,6 +956,7 @@ void Mod_LoadTexinfo (lump_t *l) } } } + return true; } /* @@ -837,7 +1020,7 @@ void CalcSurfaceExtents (msurface_t *s); Mod_LoadFaces ================= */ -void Mod_LoadFaces (lump_t *l) +qboolean Mod_LoadFaces (lump_t *l) { dface_t *in; msurface_t *out; @@ -846,7 +1029,10 @@ void Mod_LoadFaces (lump_t *l) in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) - SV_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + { + Con_Printf ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + return false; + } count = l->filelen / sizeof(*in); out = Hunk_AllocName ( count*sizeof(*out), loadname); @@ -877,8 +1063,10 @@ void Mod_LoadFaces (lump_t *l) i = LittleLong(in->lightofs); if (i == -1) out->samples = NULL; - else + else if (loadmodel->fromgame == fg_halflife) out->samples = loadmodel->lightdata + i; + else + out->samples = loadmodel->lightdata + i*3; // set the drawing flags flag @@ -899,6 +1087,8 @@ void Mod_LoadFaces (lump_t *l) continue; } } + + return true; } @@ -1209,14 +1399,17 @@ void Mod_LoadMarksurfaces (lump_t *l) Mod_LoadSurfedges ================= */ -void Mod_LoadSurfedges (lump_t *l) +qboolean Mod_LoadSurfedges (lump_t *l) { int i, count; int *in, *out; in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) - SV_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + { + Con_Printf ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + return false; + } count = l->filelen / sizeof(*in); out = Hunk_AllocName ( count*sizeof(*out), loadname); @@ -1225,6 +1418,8 @@ void Mod_LoadSurfedges (lump_t *l) for ( i=0 ; ichecksum2 = 0; // checksum all of the map, except for entities - for (i = 0; i < HEADER_LUMPS; i++) { + for (i = 0; i < HEADER_LUMPS; i++) + { if (i == LUMP_ENTITIES) continue; chksum = Com_BlockChecksum(mod_base + header->lumps[i].fileofs, @@ -1328,15 +1524,21 @@ qboolean Mod_LoadBrushModel (model_t *mod, void *buffer) } noerrors = true; -// Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]); -// Mod_LoadEdges (&header->lumps[LUMP_EDGES]); -// Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]); + if (!sv_nogetlight.value) + { + noerrors = noerrors && Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]); + noerrors = noerrors && Mod_LoadEdges (&header->lumps[LUMP_EDGES]); + noerrors = noerrors && Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]); ///*/on server?*/ Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]); -// Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]); + noerrors = noerrors && Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]); + } noerrors = noerrors && Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]); noerrors = noerrors && Mod_LoadPlanes (&header->lumps[LUMP_PLANES]); -///*/on server?*/ Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]); -// Mod_LoadFaces (&header->lumps[LUMP_FACES]); + if (!sv_nogetlight.value) + { + noerrors = noerrors && Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]); + noerrors = noerrors && Mod_LoadFaces (&header->lumps[LUMP_FACES]); + } // Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]); if (noerrors) Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]); @@ -1357,6 +1559,9 @@ qboolean Mod_LoadBrushModel (model_t *mod, void *buffer) Q1BSP_SetModelFuncs(mod); + if (mod->surfaces && mod->lightdata) + mod->funcs.LightPointValues = SVQ1_LightPointValues; + mod->numframes = 2; // regular and alternate animation //