diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index b05c5230d..3fd336874 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -491,13 +491,11 @@ void CL_ParsePacketEntities (qboolean delta) if (cls.protocol == CP_QUAKEWORLD && cls.demoplayback == DPB_MVD) { - extern float nextdemotime, olddemotime, demtime; + extern float nextdemotime; cl.oldgametime = cl.gametime; cl.oldgametimemark = cl.gametimemark; cl.gametime = nextdemotime; cl.gametimemark = realtime; - - newp->servertime = cl.gametime; } else if (!(cls.fteprotocolextensions & PEXT_ACCURATETIMINGS) && cls.protocol == CP_QUAKEWORLD) { @@ -505,11 +503,9 @@ void CL_ParsePacketEntities (qboolean delta) cl.oldgametimemark = cl.gametimemark; cl.gametime = realtime; cl.gametimemark = realtime; - - newp->servertime = realtime; } - else - newp->servertime = cl.gametime; + + newp->servertime = cl.gametime; if (delta) { @@ -1742,11 +1738,7 @@ void CL_LinkPacketEntities (void) } else { - if ((cls.fteprotocolextensions & PEXT_ACCURATETIMINGS) || cls.protocol != CP_QUAKEWORLD) - servertime = cl.servertime; - else - servertime = realtime; - + servertime = cl.servertime; nolerp = !CL_MayLerp() && cls.demoplayback != DPB_MVD && cls.demoplayback != DPB_EZTV; } pack = CL_ProcessPacketEntities(&servertime, nolerp); @@ -2027,7 +2019,7 @@ void CL_LinkPacketEntities (void) { extern cvar_t gl_part_flame; - if (cls.allow_anyparticles && gl_part_flame.ival) + if (model->particleeffect != P_INVALID && cls.allow_anyparticles && gl_part_flame.ival) { P_EmitEffect (ent->origin, model->particleeffect, &(le->emitstate)); } diff --git a/engine/client/cl_ignore.c b/engine/client/cl_ignore.c index 137d73380..d8cbd9aef 100644 --- a/engine/client/cl_ignore.c +++ b/engine/client/cl_ignore.c @@ -33,20 +33,24 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define PLAYER_ID_NOMATCH -1 #define PLAYER_NAME_NOMATCH -2 #define PLAYER_NUM_NOMATCH -3 -int Player_IdtoSlot (int id) { +int Player_IdtoSlot (int id) +{ int j; - for (j = 0; j < MAX_CLIENTS; j++) { + for (j = 0; j < MAX_CLIENTS; j++) + { if (cl.players[j].name[0] && cl.players[j].userid == id) return j; } return -1; } -int Player_StringtoSlot(char *arg) { +int Player_StringtoSlot(char *arg) +{ int i, slot; - for (i = 0; i < MAX_CLIENTS; i++) { + for (i = 0; i < MAX_CLIENTS; i++) + { if (cl.players[i].name[0] && !strncmp(arg, cl.players[i].name, MAX_SCOREBOARDNAME - 1)) return i; } @@ -54,28 +58,33 @@ int Player_StringtoSlot(char *arg) { if (!arg[0]) return PLAYER_NAME_NOMATCH; - for (i = 0; arg[i]; i++) { + for (i = 0; arg[i]; i++) + { if (!isdigit(arg[i])) return PLAYER_NAME_NOMATCH; } return ((slot = Player_IdtoSlot(Q_atoi(arg))) >= 0) ? slot : PLAYER_ID_NOMATCH; } -int Player_NametoSlot(char *name) { +int Player_NametoSlot(char *name) +{ int i; - for (i = 0; i < MAX_CLIENTS; i++) { + for (i = 0; i < MAX_CLIENTS; i++) + { if (cl.players[i].name[0] && !strncmp(cl.players[i].name, name, MAX_SCOREBOARDNAME - 1)) return i; } return PLAYER_NAME_NOMATCH; } -int Player_SlottoId (int slot) { +int Player_SlottoId (int slot) +{ return (slot >= 0 && slot < MAX_CLIENTS && cl.players[slot].name[0]) ? cl.players[slot].userid : -1; } -char *Player_MyName (void) { +char *Player_MyName (void) +{ return cl.players[cl.playernum[0]].name; } @@ -95,7 +104,8 @@ cvar_t ignore_opponents = SCVAR("ignore_opponents", "0"); char ignoreteamlist[MAX_TEAMIGNORELIST][16 + 1]; -typedef struct flood_s { +typedef struct flood_s +{ char data[2048]; float time; } flood_t; @@ -105,28 +115,65 @@ static int floodindex; extern int PaddedPrint (char *s, int x); -static qboolean IsIgnored(int slot) { +static qboolean IsIgnored(int slot) +{ return cl.players[slot].ignored; } -static void Display_Ignorelist(void) { +static void Display_Ignorelist(void) +{ int i; - int x = 0; + int x; + qboolean foundone; - Con_Printf ("\x02" "User Ignore List:\n"); - for (i = 0; i < MAX_CLIENTS; i++) - if (cl.players[i].name[0] && cl.players[i].ignored) - x = PaddedPrint(cl.players[i].name, x); - if (x) - Con_Printf ("\n"); x = 0; - - Con_Printf ("\x02" "Team Ignore List:\n"); - for (i = 0; i < MAX_TEAMIGNORELIST && ignoreteamlist[i][0]; i++) - x = PaddedPrint(ignoreteamlist[i], x); - if (x) + foundone = false; + for (i = 0; i < MAX_CLIENTS; i++) + { + if (cl.players[i].name[0] && cl.players[i].ignored) + { + if (!foundone) + { + Con_Printf ("\x02" "User Ignore List:\n"); + foundone++; + } + x = PaddedPrint(cl.players[i].name, x); + } + } + if (!foundone) + Con_Printf("\x02" "User Ignore List: empty\n"); + else if (x) Con_Printf ("\n"); + x = 0; + foundone = false; + for (i = 0; i < MAX_CLIENTS; i++) + { + if (cl.players[i].name[0] && cl.players[i].ignored) + { + if (!foundone) + { + Con_Printf ("\x02" "User Mute List:\n"); + foundone++; + } + x = PaddedPrint(cl.players[i].name, x); + } + } + if (!foundone) + Con_Printf("\x02" "User Mute List: empty\n"); + else if (x) + Con_Printf ("\n"); + + if (ignoreteamlist[i][0]) + { + x = 0; + Con_Printf ("\x02" "Team Ignore List:\n"); + for (i = 0; i < MAX_TEAMIGNORELIST && ignoreteamlist[i][0]; i++) + x = PaddedPrint(ignoreteamlist[i], x); + if (x) + Con_Printf ("\n"); + } + if (ignore_opponents.ival) Con_Printf("\x02" "Opponents are Ignored\n"); @@ -139,38 +186,94 @@ static void Display_Ignorelist(void) { Con_Printf("\n"); } -static qboolean Ignorelist_Add(int slot) { +static qboolean Ignorelist_Add(int slot) +{ if (IsIgnored(slot)) return false; cl.players[slot].ignored = true; + cl.players[slot].vignored = true; + S_Voip_Ignore(slot, true); + return true; +} +static qboolean Ignorelist_VAdd(int slot) +{ + if (cl.players[slot].vignored) + return false; + + cl.players[slot].vignored = true; + S_Voip_Ignore(slot, true); return true; } -static qboolean Ignorelist_Del(int slot) { +static qboolean Ignorelist_Del(int slot) +{ if (cl.players[slot].ignored == false) return false; cl.players[slot].ignored = false; + cl.players[slot].vignored = true; + S_Voip_Ignore(slot, false); return true; } -static void Ignore_f(void) { +static void VIgnore_f(void) +{ int c, slot; - if ((c = Cmd_Argc()) == 1) { + if ((c = Cmd_Argc()) == 1) + { Display_Ignorelist(); return; - } else if (c != 2) { + } + else if (c != 2) + { Con_Printf("Usage: %s [userid | name]\n", Cmd_Argv(0)); return; } - if ((slot = Player_StringtoSlot(Cmd_Argv(1))) == PLAYER_ID_NOMATCH) { + if ((slot = Player_StringtoSlot(Cmd_Argv(1))) == PLAYER_ID_NOMATCH) + { Con_Printf("%s : no player with userid %d\n", Cmd_Argv(0), Q_atoi(Cmd_Argv(1))); - } else if (slot == PLAYER_NAME_NOMATCH) { + } + else if (slot == PLAYER_NAME_NOMATCH) + { Con_Printf("%s : no player with name %s\n", Cmd_Argv(0), Cmd_Argv(1)); - } else { + } + else + { + if (Ignorelist_VAdd(slot)) + Con_Printf("Added user %s to ignore list\n", cl.players[slot].name); + else + Con_Printf ("User %s is already ignored\n", cl.players[slot].name); + } +} + +static void Ignore_f(void) +{ + int c, slot; + + if ((c = Cmd_Argc()) == 1) + { + Display_Ignorelist(); + return; + } + else if (c != 2) + { + Con_Printf("Usage: %s [userid | name]\n", Cmd_Argv(0)); + return; + } + + if ((slot = Player_StringtoSlot(Cmd_Argv(1))) == PLAYER_ID_NOMATCH) + { + Con_Printf("%s : no player with userid %d\n", Cmd_Argv(0), Q_atoi(Cmd_Argv(1))); + } + else if (slot == PLAYER_NAME_NOMATCH) + { + Con_Printf("%s : no player with name %s\n", Cmd_Argv(0), Cmd_Argv(1)); + } + else + { if (Ignorelist_Add(slot)) Con_Printf("Added user %s to ignore list\n", cl.players[slot].name); else @@ -178,33 +281,41 @@ static void Ignore_f(void) { } } -static void IgnoreList_f(void) { +static void IgnoreList_f(void) +{ if (Cmd_Argc() != 1) Con_Printf("%s : no arguments expected\n", Cmd_Argv(0)); else Display_Ignorelist(); } -static void Ignore_ID_f(void) { +static void Ignore_ID_f(void) +{ int c, userid, i, slot; char *arg; - if ((c = Cmd_Argc()) == 1) { + if ((c = Cmd_Argc()) == 1) + { Display_Ignorelist(); return; - } else if (c != 2) { + } + else if (c != 2) + { Con_Printf("Usage: %s [userid]\n", Cmd_Argv(0)); return; } arg = Cmd_Argv(1); - for (i = 0; arg[i]; i++) { - if (!isdigit(arg[i])) { + for (i = 0; arg[i]; i++) + { + if (!isdigit(arg[i])) + { Con_Printf("Usage: %s [userid]\n", Cmd_Argv(0)); return; } } userid = Q_atoi(arg); - if ((slot = Player_IdtoSlot(userid)) == PLAYER_ID_NOMATCH) { + if ((slot = Player_IdtoSlot(userid)) == PLAYER_ID_NOMATCH) + { Con_Printf("%s : no player with userid %d\n", Cmd_Argv(0), userid); return; } @@ -214,22 +325,31 @@ static void Ignore_ID_f(void) { Con_Printf ("User %s is already ignored\n", cl.players[slot].name); } -static void Unignore_f(void) { +static void Unignore_f(void) +{ int c, slot; - if ((c = Cmd_Argc()) == 1) { + if ((c = Cmd_Argc()) == 1) + { Display_Ignorelist(); return; - } else if (c != 2) { + } + else if (c != 2) + { Con_Printf("Usage: %s [userid | name]\n", Cmd_Argv(0)); return; } - if ((slot = Player_StringtoSlot(Cmd_Argv(1))) == PLAYER_ID_NOMATCH) { + if ((slot = Player_StringtoSlot(Cmd_Argv(1))) == PLAYER_ID_NOMATCH) + { Con_Printf("%s : no player with userid %d\n", Cmd_Argv(0), Q_atoi(Cmd_Argv(1))); - } else if (slot == PLAYER_NAME_NOMATCH) { + } + else if (slot == PLAYER_NAME_NOMATCH) + { Con_Printf("%s : no player with name %s\n", Cmd_Argv(0), Cmd_Argv(1)); - } else { + } + else + { if (Ignorelist_Del(slot)) Con_Printf("Removed user %s from ignore list\n", cl.players[slot].name); else @@ -237,26 +357,33 @@ static void Unignore_f(void) { } } -static void Unignore_ID_f(void) { +static void Unignore_ID_f(void) +{ int c, i, userid, slot; char *arg; - if ((c = Cmd_Argc()) == 1) { + if ((c = Cmd_Argc()) == 1) + { Display_Ignorelist(); return; - } else if (c != 2) { + } + else if (c != 2) + { Con_Printf("Usage: %s [userid]\n", Cmd_Argv(0)); return; } arg = Cmd_Argv(1); - for (i = 0; arg[i]; i++) { - if (!isdigit(arg[i])) { + for (i = 0; arg[i]; i++) + { + if (!isdigit(arg[i])) + { Con_Printf("Usage: %s [userid]\n", Cmd_Argv(0)); return; } } userid = Q_atoi(arg); - if ((slot = Player_IdtoSlot(userid)) == PLAYER_ID_NOMATCH) { + if ((slot = Player_IdtoSlot(userid)) == PLAYER_ID_NOMATCH) + { Con_Printf("%s : no player with userid %d\n", Cmd_Argv(0), userid); return; } @@ -266,23 +393,31 @@ static void Unignore_ID_f(void) { Con_Printf("User %s is not being ignored\n", cl.players[slot].name); } -static void Ignoreteam_f(void) { +static void Ignoreteam_f(void) +{ int c, i, j; char *arg; c = Cmd_Argc(); - if (c == 1) { + if (c == 1) + { Display_Ignorelist(); return; - } else if (c != 2) { + } + else if (c != 2) + { Con_Printf("Usage: %s [team]\n", Cmd_Argv(0)); return; } arg = Cmd_Argv(1); - for (i = 0; i < MAX_CLIENTS; i++) { - if (cl.players[i].name[0] && !cl.players[i].spectator && !strcmp(arg, cl.players[i].team)) { - for (j = 0; j < MAX_TEAMIGNORELIST && ignoreteamlist[j][0]; j++) { - if (!strncmp(arg, ignoreteamlist[j], sizeof(ignoreteamlist[j]) - 1)) { + for (i = 0; i < MAX_CLIENTS; i++) + { + if (cl.players[i].name[0] && !cl.players[i].spectator && !strcmp(arg, cl.players[i].team)) + { + for (j = 0; j < MAX_TEAMIGNORELIST && ignoreteamlist[j][0]; j++) + { + if (!strncmp(arg, ignoreteamlist[j], sizeof(ignoreteamlist[j]) - 1)) + { Con_Printf ("Team %s is already ignored\n", arg); return; } @@ -299,21 +434,27 @@ static void Ignoreteam_f(void) { Con_Printf("%s : no team with name %s\n", Cmd_Argv(0), arg); } -static void Unignoreteam_f(void) { +static void Unignoreteam_f(void) +{ int i, c, j; char *arg; c = Cmd_Argc(); - if (c == 1) { + if (c == 1) + { Display_Ignorelist(); return; - } else if (c != 2) { + } + else if (c != 2) + { Con_Printf("Usage: %s [team]\n", Cmd_Argv(0)); return; } arg = Cmd_Argv(1); - for (i = 0; i < MAX_TEAMIGNORELIST && ignoreteamlist[i][0]; i++) { - if (!strncmp(arg, ignoreteamlist[i], sizeof(ignoreteamlist[i]) - 1)) { + for (i = 0; i < MAX_TEAMIGNORELIST && ignoreteamlist[i][0]; i++) + { + if (!strncmp(arg, ignoreteamlist[i], sizeof(ignoreteamlist[i]) - 1)) + { for (j = i; j < MAX_TEAMIGNORELIST && ignoreteamlist[j][0]; j++) ; if ( --j > i) @@ -326,20 +467,24 @@ static void Unignoreteam_f(void) { Con_Printf("Team %s is not being ignored\n", arg); } -static void UnignoreAll_f (void) { +static void UnignoreAll_f (void) +{ int i; - if (Cmd_Argc() != 1) { + if (Cmd_Argc() != 1) + { Con_Printf("%s : no arguments expected\n", Cmd_Argv(0)); return; } for (i = 0; i < MAX_CLIENTS; i++) - cl.players[i].ignored = false; + Ignorelist_Del(i); Con_Printf("User ignore list cleared\n"); } -static void UnignoreteamAll_f (void) { - if (Cmd_Argc() != 1) { +static void UnignoreteamAll_f (void) +{ + if (Cmd_Argc() != 1) + { Con_Printf("%s : no arguments expected\n", Cmd_Argv(0)); return; } @@ -347,35 +492,46 @@ static void UnignoreteamAll_f (void) { Con_Printf("Team ignore list cleared\n"); } -char Ignore_Check_Flood(char *s, int flags, int offset) { +char Ignore_Check_Flood(char *s, int flags, int offset) +{ int i, p, q, len; char name[MAX_INFO_STRING]; if ( !( - ( (ignore_flood.value == 1 && (flags & TPM_NORMAL || flags & TPM_SPECTATOR)) || - (ignore_flood.value == 2 && flags != 0) ) - ) ) + ( (ignore_flood.value == 1 && (flags & TPM_NORMAL || flags & TPM_SPECTATOR)) || + (ignore_flood.value == 2 && flags != 0) ) + ) ) + { return NO_IGNORE_NO_ADD; + } - if (flags == 1 || flags == TPM_SPECTATOR) { + if (flags == 1 || flags == TPM_SPECTATOR) + { p = 0; q = offset - 3; - } else if (flags == TPM_TEAM) { + } + else if (flags == TPM_TEAM) + { p = 1; q = offset - 4; - } else if (flags == 8) { + } + else if (flags == 8) + { p = 7; q = offset -3; - } else + } + else return NO_IGNORE_NO_ADD; len = bound (0, q - p + 1, MAX_INFO_STRING - 1); Q_strncpyz(name, s + p, len + 1); - if (!cls.demoplayback && !strcmp(name, Player_MyName())) { + if (!cls.demoplayback && !strcmp(name, Player_MyName())) + { return NO_IGNORE_NO_ADD; } - for (i = 0; i < FLOODLIST_SIZE; i++) { + for (i = 0; i < FLOODLIST_SIZE; i++) + { if (floodlist[i].data[0] && !strncmp(floodlist[i].data, s, sizeof(floodlist[i].data) - 1) && realtime - floodlist[i].time < ignore_flood_duration.value) { return IGNORE_NO_ADD; @@ -384,8 +540,8 @@ char Ignore_Check_Flood(char *s, int flags, int offset) { return NO_IGNORE_ADD; } -void Ignore_Flood_Add(char *s) { - +void Ignore_Flood_Add(char *s) +{ floodlist[floodindex].data[0] = 0; Q_strncpyz(floodlist[floodindex].data, s, sizeof(floodlist[floodindex].data)); floodlist[floodindex].time = realtime; @@ -395,7 +551,8 @@ void Ignore_Flood_Add(char *s) { } -qboolean Ignore_Message(char *s, int flags, int offset) { +qboolean Ignore_Message(char *s, int flags, int offset) +{ int slot, i, p, q, len; char name[MAX_SCOREBOARDNAME]; @@ -408,16 +565,23 @@ qboolean Ignore_Message(char *s, int flags, int offset) { else if (ignore_spec.ival == 1 && (flags == 4) && !cl.spectator) return true; - if (flags == 1 || flags == 4) { + if (flags == 1 || flags == 4) + { p = 0; q = offset - 3; - } else if (flags == 2) { + } + else if (flags == 2) + { p = 1; q = offset - 4; - } else if (flags == 8) { + } + else if (flags == 8) + { p = 7; q = offset - 3; - } else { + } + else + { return false; } @@ -427,18 +591,20 @@ qboolean Ignore_Message(char *s, int flags, int offset) { if ((slot = Player_NametoSlot(name)) == PLAYER_NAME_NOMATCH) return false; - if (cl.players[slot].ignored) + if (IsIgnored(slot)) return true; if (ignore_opponents.ival && ( - (int) ignore_opponents.ival == 1 || - (cls.state >= ca_connected && /*!cl.standby &&*/ !cls.demoplayback && !cl.spectator) // match? - ) && - flags == 1 && !cl.spectator && slot != cl.playernum[0] && - (!cl.teamplay || strcmp(cl.players[slot].team, cl.players[cl.playernum[0]].team)) - ) + (int) ignore_opponents.ival == 1 || + (cls.state >= ca_connected && /*!cl.standby &&*/ !cls.demoplayback && !cl.spectator) // match? + ) && + flags == 1 && !cl.spectator && slot != cl.playernum[0] && + (!cl.teamplay || strcmp(cl.players[slot].team, cl.players[cl.playernum[0]].team)) + ) + { return true; + } if (!cl.teamplay) @@ -447,7 +613,8 @@ qboolean Ignore_Message(char *s, int flags, int offset) { if (cl.players[slot].spectator || !strcmp(Player_MyName(), name)) return false; - for (i = 0; i < MAX_TEAMIGNORELIST && ignoreteamlist[i][0]; i++) { + for (i = 0; i < MAX_TEAMIGNORELIST && ignoreteamlist[i][0]; i++) + { if (!strncmp(cl.players[slot].team, ignoreteamlist[i], sizeof(ignoreteamlist[i]) - 1)) return true; } @@ -455,7 +622,8 @@ qboolean Ignore_Message(char *s, int flags, int offset) { return false; } -void Ignore_ResetFloodList(void) { +void Ignore_ResetFloodList(void) +{ int i; for (i = 0; i < FLOODLIST_SIZE; i++) @@ -463,7 +631,8 @@ void Ignore_ResetFloodList(void) { floodindex = 0; } -void Ignore_Init(void) { +void Ignore_Init(void) +{ int i; #define IGNOREGROUP "Player Ignoring" @@ -479,7 +648,8 @@ void Ignore_Init(void) { Cvar_Register (&ignore_mode, IGNOREGROUP); Cvar_Register (&ignore_opponents, IGNOREGROUP); - Cmd_AddCommand ("ignore", Ignore_f); + Cmd_AddCommand ("mute", VIgnore_f); + Cmd_AddCommand ("ignore", Ignore_f); Cmd_AddCommand ("ignorelist", IgnoreList_f); Cmd_AddCommand ("unignore", Unignore_f); Cmd_AddCommand ("ignore_team", Ignoreteam_f); diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index 9094340f6..e8bd06853 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -871,14 +871,15 @@ void Name_Callback(struct cvar_s *var, char *oldvalue) } #endif -float CL_FilterTime (double time, float wantfps) //now returns the extra time not taken in this slot. Note that negative 1 means uncapped. +float CL_FilterTime (double time, float wantfps, qboolean ignoreserver) //now returns the extra time not taken in this slot. Note that negative 1 means uncapped. { float fps, fpscap; if (cls.timedemo || cls.protocol == CP_QUAKE3) return -1; - if (cls.demoplayback != DPB_NONE || cls.protocol != CP_QUAKEWORLD) + /*ignore the server if we're playing demos, sending to the server only as replies, or if its meant to be disabled (netfps depending on where its called from)*/ + if (cls.demoplayback != DPB_NONE || cls.protocol != CP_QUAKEWORLD || ignoreserver) { if (!wantfps) return -1; @@ -1040,7 +1041,7 @@ unsigned long _stdcall CL_IndepPhysicsThread(void *param) while(1) { time = Sys_Milliseconds(); - spare = CL_FilterTime((time - lasttime), cl_netfps.value); + spare = CL_FilterTime((time - lasttime), cl_netfps.value, false); if (spare) { //don't let them bank too much and get sudden bursts @@ -1568,16 +1569,19 @@ void CL_SendCmd (double frametime, qboolean mainloop) if (!runningindepphys) { // while we're not playing send a slow keepalive fullsend to stop mvdsv from screwing up - if (cls.state < ca_active && CL_FilterTime(msecstouse, -#ifdef IRCCONNECT //don't spam irc. - cls.netchan.remote_address.type == NA_IRC?0.5: -#endif - 12.5) == false) - fullsend = false; - else if (cl_netfps.value > 0) + if (cls.state < ca_active) + { + #ifdef IRCCONNECT //don't spam irc. + if (cls.netchan.remote_address.type == NA_IRC) + wantfps = 0.5; + else + #endif + wantfps = 12.5; + } + if (cl_netfps.value > 0 || !fullsend) { int spare; - spare = CL_FilterTime(msecstouse, cl_netfps.value); + spare = CL_FilterTime(msecstouse, wantfps, false); if (!spare && (msecstouse < 200 #ifdef IRCCONNECT || cls.netchan.remote_address.type == NA_IRC diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 55dec5b45..2ea032a1c 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -397,6 +397,7 @@ void CL_SupportedFTEExtensions(int *pext1, int *pext2) #ifdef PEXT2_VOICECHAT fteprotextsupported2 |= PEXT2_VOICECHAT; #endif + fteprotextsupported2 |= PEXT2_SETANGLEDELTA; fteprotextsupported &= strtoul(cl_pext_mask.string, NULL, 16); // fteprotextsupported2 &= strtoul(cl_pext2_mask.string, NULL, 16); @@ -1074,8 +1075,6 @@ void CL_ClearState (void) cl.oldgametime = 0; cl.gametime = 0; cl.gametimemark = 0; - - CL_RegisterParticles(); } /* @@ -3311,7 +3310,6 @@ extern cvar_t cl_sparemsec; int nopacketcount; void SNDDMA_SetUnderWater(qboolean underwater); -float CL_FilterTime (double time, float wantfps); float Host_Frame (double time) { static double time1 = 0; @@ -3377,19 +3375,19 @@ float Host_Frame (double time) { //limit the fps freely, and expect the netfps to cope. if (cl_maxfps.ival > 0) { -// realtime += spare/1000; //don't use it all! - spare = CL_FilterTime((realtime - oldrealtime)*1000, cl_maxfps.value); + realtime += spare/1000; //don't use it all! + spare = CL_FilterTime((realtime - oldrealtime)*1000, cl_maxfps.value, true); if (!spare) return 1; -// realtime -= spare/1000; //don't use it all! + //realtime -= spare/1000; //don't use it all! } } else { float maxfps = (cl_maxfps.ival>0||cls.protocol!=CP_QUAKEWORLD)?cl_maxfps.value:cl_netfps.value; realtime += spare/1000; //don't use it all! - spare = CL_FilterTime((realtime - oldrealtime)*1000, maxfps); + spare = CL_FilterTime((realtime - oldrealtime)*1000, maxfps, false); if (!spare) return 1; if (spare < 0 || cls.state < ca_onserver) @@ -3784,6 +3782,8 @@ Con_TPrintf (TL_NL); "\n" "See the GNU General Public License for more details.\n"); + realtime+=1; + Cbuf_Execute (); //server may have been waiting for the renderer if (!cls.demoinfile && !*cls.servername) { diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index ee0634e15..fdb175d43 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -2121,10 +2121,10 @@ void CL_ParseServerData (void) Info_SetValueForStarKey (svs.info, "*gamedir", str, MAX_SERVERINFO_STRING); #endif COM_FlushFSCache(); + Cvar_ForceCallback(Cvar_FindVar("r_particlesdesc")); } CL_ClearState (); - Cvar_ForceCallback(Cvar_FindVar("r_particlesdesc")); Stats_NewMap(); cl.servercount = svcnt; @@ -2543,6 +2543,8 @@ void CLNQ_ParseServerData(void) //Doesn't change gamedir - use with caution. //pretend it came from the server, and update cheat/permissions/etc CL_CheckServerInfo(); + Sys_RecentServer("+nqconnect", cls.servername, cls.servername, "Join NQ Server"); + #ifdef PEXT_CSQC CSQC_Shutdown(); if (cls.demoplayback) @@ -4595,7 +4597,11 @@ void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds from n *msg = '\0'; Con_DPrintf("stufftext: %s\n", stufftext); if (!strncmp(stufftext, "fullserverinfo ", 15)) + { Cmd_ExecuteString(stufftext, RESTRICT_SERVER+destsplit); //do this NOW so that it's done before any models or anything are loaded + if (cls.netchan.remote_address.type != NA_LOOPBACK) + Sys_RecentServer("+connect", cls.servername, va("%s (%s)", Info_ValueForKey(cl.serverinfo, "hostname"), cls.servername), "Join QW Server"); + } else { if (!strncmp(stufftext, "//querycmd ", 11)) @@ -4905,6 +4911,10 @@ void CL_ParseServerMessage (void) cl.viewentity[destsplit] = 0; break; #endif + case svcfte_setangledelta: + for (i=0 ; i<3 ; i++) + cl.viewangles[destsplit][i] += MSG_ReadAngle16 (); + break; case svc_setangle: if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) { diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index fc932b69c..346c77872 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -651,7 +651,6 @@ short LerpAngles16(short to, short from, float frac) void CL_CalcClientTime(void) { - { float want; float oldst = realtime; @@ -664,8 +663,6 @@ void CL_CalcClientTime(void) f = bound(0, f, 1); cl.time = cl.servertime = cl.gametime*f + cl.oldgametime*(1-f); } - else if (!(cls.fteprotocolextensions & PEXT_ACCURATETIMINGS) && cls.protocol == CP_QUAKEWORLD) - cl.servertime = cl.time; else { want = cl.oldgametime + (realtime - cl.gametimemark); diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index 5275d26f5..ff8c0fcff 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -2245,7 +2245,10 @@ void SCR_DrawTwoDimensional(int uimenu, qboolean nohud) CL_DrawPrydonCursor(); } else + { SCR_DrawFPS (); + SCR_DrawUPS (); + } SCR_CheckDrawCenterString (); } diff --git a/engine/client/cl_tent.c b/engine/client/cl_tent.c index 0af778101..840558118 100644 --- a/engine/client/cl_tent.c +++ b/engine/client/cl_tent.c @@ -243,6 +243,74 @@ tentsfx_t tentsfx[] = }; vec3_t playerbeam_end[MAX_SPLITS]; + +struct associatedeffect +{ + struct associatedeffect *next; + char mname[MAX_QPATH]; + char pname[MAX_QPATH]; + enum + { + AE_TRAIL, + AE_EMIT, + AE_REPLACE + } type; +} *associatedeffect; +void CL_AssociateEffect_f(void) +{ + char *modelname = Cmd_Argv(1); + char *effectname = Cmd_Argv(2); + int type = atoi(Cmd_Argv(3)); + struct associatedeffect *ae; + if (!strcmp(Cmd_Argv(0), "r_trail")) + type = AE_TRAIL; + else + { + if (type) + type = AE_REPLACE; + else + type = AE_EMIT; + } + + if ( + strstr(modelname, "player") || + strstr(modelname, "eyes") || + strstr(modelname, "flag") || + strstr(modelname, "tf_stan") || + strstr(modelname, ".bsp") || + strstr(modelname, "turr")) + { + Con_Printf("Sorry: Not allowed to attach effects to model \"%s\"\n", modelname); + return; + } + + if (strlen (modelname) >= MAX_QPATH || strlen(effectname) >= MAX_QPATH) + return; + + /*replace the old one if it exists*/ + for(ae = associatedeffect; ae; ae = ae->next) + { + if (!strcmp(ae->mname, modelname)) + if ((ae->type==AE_TRAIL) == (type==AE_TRAIL)) + { + strcpy(ae->pname, effectname); + break; + } + } + if (!ae) + { + ae = Z_Malloc(sizeof(*ae)); + ae->type = type; + strcpy(ae->mname, modelname); + strcpy(ae->pname, effectname); + ae->next = associatedeffect; + associatedeffect = ae; + } + + //FIXME: overkill + CL_RegisterParticles(); +} + /* ================= CL_ParseTEnts @@ -259,71 +327,135 @@ void CL_InitTEnts (void) *tentsfx[i].sfx = NULL; } + Cmd_AddRemCommand("r_effect", CL_AssociateEffect_f); + Cmd_AddRemCommand("r_trail", CL_AssociateEffect_f); + Cvar_Register (&cl_expsprite, "Temporary entity control"); Cvar_Register (&cl_truelightning, "Temporary entity control"); Cvar_Register (&cl_beam_trace, "Temporary entity control"); Cvar_Register (&r_explosionlight, "Temporary entity control"); } +void CL_ShutdownTEnts (void) +{ + struct associatedeffect *ae; + while(associatedeffect) + { + ae = associatedeffect; + associatedeffect = ae->next; + BZ_Free(ae); + } +} +void P_LoadedModel(model_t *mod) +{ + struct associatedeffect *ae; + int j; + + mod->particleeffect = P_INVALID; + mod->particletrail = P_INVALID; + mod->engineflags &= ~(MDLF_NODEFAULTTRAIL | MDLF_ENGULPHS); + + if (mod->type == mod_brush) + { + if (*mod->name != '*') + for (j = 0; j < mod->numtextures; j++) + mod->textures[j]->parttype = P_FindParticleType(va("tex_%s", mod->textures[j]->name)); + } + for(ae = associatedeffect; ae; ae = ae->next) + { + if (!strcmp(ae->mname, mod->name)) + { + switch(ae->type) + { + case AE_TRAIL: + mod->particletrail = P_FindParticleType(ae->pname); + break; + case AE_EMIT: + mod->particleeffect = P_FindParticleType(ae->pname); + mod->engineflags &= ~MDLF_ENGULPHS; + break; + case AE_REPLACE: + mod->particleeffect = P_FindParticleType(ae->pname); + mod->engineflags |= MDLF_ENGULPHS; + break; + } + } + } + if (mod->particletrail == P_INVALID) + P_DefaultTrail(mod); +} + void CL_RegisterParticles(void) { - pt_gunshot = P_ParticleTypeForName("TE_GUNSHOT"); /*shotgun*/ - ptdp_gunshotquad = P_ParticleTypeForName("TE_GUNSHOTQUAD"); /*DP: quadded shotgun*/ - pt_spike = P_ParticleTypeForName("TE_SPIKE"); /*nailgun*/ - ptdp_spikequad = P_ParticleTypeForName("TE_SPIKEQUAD"); /*DP: quadded nailgun*/ - pt_superspike = P_ParticleTypeForName("TE_SUPERSPIKE"); /*nailgun*/ - ptdp_superspikequad = P_ParticleTypeForName("TE_SUPERSPIKEQUAD"); /*DP: quadded nailgun*/ - pt_wizspike = P_ParticleTypeForName("TE_WIZSPIKE"); //scrag missile impact - pt_knightspike = P_ParticleTypeForName("TE_KNIGHTSPIKE"); //hellknight missile impact - pt_explosion = P_ParticleTypeForName("TE_EXPLOSION");/*rocket/grenade launcher impacts/far too many things*/ - ptdp_explosionquad = P_ParticleTypeForName("TE_EXPLOSIONQUAD"); /*nailgun*/ - pt_tarexplosion = P_ParticleTypeForName("TE_TAREXPLOSION");//tarbaby/spawn dying. - pt_teleportsplash = P_ParticleTypeForName("TE_TELEPORT");/*teleporters*/ - pt_lavasplash = P_ParticleTypeForName("TE_LAVASPLASH"); //e1m7 boss dying. - ptdp_smallflash = P_ParticleTypeForName("TE_SMALLFLASH"); //DP: - ptdp_flamejet = P_ParticleTypeForName("TE_FLAMEJET"); //DP: - ptdp_flame = P_ParticleTypeForName("EF_FLAME"); //DP: - ptdp_blood = P_ParticleTypeForName("TE_BLOOD"); /*when you hit something with the shotgun/axe/nailgun - nq uses the general particle builtin*/ - ptdp_spark = P_ParticleTypeForName("TE_SPARK");//DPTE_SPARK - ptdp_plasmaburn = P_ParticleTypeForName("TE_PLASMABURN"); - ptdp_tei_g3 = P_ParticleTypeForName("TE_TEI_G3"); - ptdp_tei_smoke = P_ParticleTypeForName("TE_TEI_SMOKE"); - ptdp_tei_bigexplosion = P_ParticleTypeForName("TE_TEI_BIGEXPLOSION"); - ptdp_tei_plasmahit = P_ParticleTypeForName("TE_TEI_PLASMAHIT"); - ptdp_stardust = P_ParticleTypeForName("EF_STARDUST"); - rt_rocket = P_ParticleTypeForName("TR_ROCKET"); /*rocket trail*/ - rt_grenade = P_ParticleTypeForName("TR_GRENADE"); /*grenade trail*/ - rt_blood = P_ParticleTypeForName("TR_BLOOD"); /*blood trail*/ - rt_wizspike = P_ParticleTypeForName("TR_WIZSPIKE"); - rt_slightblood = P_ParticleTypeForName("TR_SLIGHTBLOOD"); - rt_knightspike = P_ParticleTypeForName("TR_KNIGHTSPIKE"); - rt_vorespike = P_ParticleTypeForName("TR_VORESPIKE"); - rtdp_neharasmoke = P_ParticleTypeForName("TR_NEHAHRASMOKE"); - rtdp_nexuizplasma = P_ParticleTypeForName("TR_NEXUIZPLASMA"); - rtdp_glowtrail = P_ParticleTypeForName("TR_GLOWTRAIL"); - /*internal to psystem*/ P_ParticleTypeForName("SVC_PARTICLE"); + model_t *mod; + extern model_t mod_known[]; + extern int mod_numknown; + int i; + for (i=0 , mod=mod_known ; ineedload) + { + P_LoadedModel(mod); + } + } - ptqw_blood = P_ParticleTypeForName("TE_BLOOD"); - ptqw_lightningblood = P_ParticleTypeForName("TE_LIGHTNINGBLOOD"); + pt_gunshot = P_FindParticleType("TE_GUNSHOT"); /*shotgun*/ + ptdp_gunshotquad = P_FindParticleType("TE_GUNSHOTQUAD"); /*DP: quadded shotgun*/ + pt_spike = P_FindParticleType("TE_SPIKE"); /*nailgun*/ + ptdp_spikequad = P_FindParticleType("TE_SPIKEQUAD"); /*DP: quadded nailgun*/ + pt_superspike = P_FindParticleType("TE_SUPERSPIKE"); /*nailgun*/ + ptdp_superspikequad = P_FindParticleType("TE_SUPERSPIKEQUAD"); /*DP: quadded nailgun*/ + pt_wizspike = P_FindParticleType("TE_WIZSPIKE"); //scrag missile impact + pt_knightspike = P_FindParticleType("TE_KNIGHTSPIKE"); //hellknight missile impact + pt_explosion = P_FindParticleType("TE_EXPLOSION");/*rocket/grenade launcher impacts/far too many things*/ + ptdp_explosionquad = P_FindParticleType("TE_EXPLOSIONQUAD"); /*nailgun*/ + pt_tarexplosion = P_FindParticleType("TE_TAREXPLOSION");//tarbaby/spawn dying. + pt_teleportsplash = P_FindParticleType("TE_TELEPORT");/*teleporters*/ + pt_lavasplash = P_FindParticleType("TE_LAVASPLASH"); //e1m7 boss dying. + ptdp_smallflash = P_FindParticleType("TE_SMALLFLASH"); //DP: + ptdp_flamejet = P_FindParticleType("TE_FLAMEJET"); //DP: + ptdp_flame = P_FindParticleType("EF_FLAME"); //DP: + ptdp_blood = P_FindParticleType("TE_BLOOD"); /*when you hit something with the shotgun/axe/nailgun - nq uses the general particle builtin*/ + ptdp_spark = P_FindParticleType("TE_SPARK");//DPTE_SPARK + ptdp_plasmaburn = P_FindParticleType("TE_PLASMABURN"); + ptdp_tei_g3 = P_FindParticleType("TE_TEI_G3"); + ptdp_tei_smoke = P_FindParticleType("TE_TEI_SMOKE"); + ptdp_tei_bigexplosion = P_FindParticleType("TE_TEI_BIGEXPLOSION"); + ptdp_tei_plasmahit = P_FindParticleType("TE_TEI_PLASMAHIT"); + ptdp_stardust = P_FindParticleType("EF_STARDUST"); + rt_rocket = P_FindParticleType("TR_ROCKET"); /*rocket trail*/ + rt_grenade = P_FindParticleType("TR_GRENADE"); /*grenade trail*/ + rt_blood = P_FindParticleType("TR_BLOOD"); /*blood trail*/ + rt_wizspike = P_FindParticleType("TR_WIZSPIKE"); + rt_slightblood = P_FindParticleType("TR_SLIGHTBLOOD"); + rt_knightspike = P_FindParticleType("TR_KNIGHTSPIKE"); + rt_vorespike = P_FindParticleType("TR_VORESPIKE"); + rtdp_neharasmoke = P_FindParticleType("TR_NEHAHRASMOKE"); + rtdp_nexuizplasma = P_FindParticleType("TR_NEXUIZPLASMA"); + rtdp_glowtrail = P_FindParticleType("TR_GLOWTRAIL"); + /*internal to psystem*/ P_FindParticleType("SVC_PARTICLE"); + + ptqw_blood = P_FindParticleType("TE_BLOOD"); + ptqw_lightningblood = P_FindParticleType("TE_LIGHTNINGBLOOD"); - ptq2_blood = P_ParticleTypeForName("TE_BLOOD"); - rtq2_railtrail = P_ParticleTypeForName("TR_RAILTRAIL"); - rtq2_blastertrail = P_ParticleTypeForName("TR_BLASTERTRAIL"); - ptq2_blasterparticles = P_ParticleTypeForName("TE_BLASTERPARTICLES"); - rtq2_bubbletrail = P_ParticleTypeForName("TE_BUBBLETRAIL"); - rtq2_gib = P_ParticleTypeForName("TR_GIB"); - rtq2_rocket = P_ParticleTypeForName("TR_ROCKET"); - rtq2_grenade = P_ParticleTypeForName("TR_GRENADE"); + ptq2_blood = P_FindParticleType("TE_BLOOD"); + rtq2_railtrail = P_FindParticleType("TR_RAILTRAIL"); + rtq2_blastertrail = P_FindParticleType("TR_BLASTERTRAIL"); + ptq2_blasterparticles = P_FindParticleType("TE_BLASTERPARTICLES"); + rtq2_bubbletrail = P_FindParticleType("TE_BUBBLETRAIL"); + rtq2_gib = P_FindParticleType("TR_GIB"); + rtq2_rocket = P_FindParticleType("TR_ROCKET"); + rtq2_grenade = P_FindParticleType("TR_GRENADE"); - rtqw_railtrail = P_ParticleTypeForName("TE_RAILTRAIL"); - rtfte_lightning1 = P_ParticleTypeForName("TE_LIGHTNING1"); - ptfte_lightning1_end = P_ParticleTypeForName("TE_LIGHTNING1_END"); - rtfte_lightning2 = P_ParticleTypeForName("TE_LIGHTNING2"); - ptfte_lightning2_end = P_ParticleTypeForName("TE_LIGHTNING2_END"); - rtfte_lightning3 = P_ParticleTypeForName("TE_LIGHTNING3"); - ptfte_lightning3_end = P_ParticleTypeForName("TE_LIGHTNING3_END"); - ptfte_bullet = P_ParticleTypeForName("TE_BULLET"); - ptfte_superbullet = P_ParticleTypeForName("TE_SUPERBULLET"); + rtqw_railtrail = P_FindParticleType("TE_RAILTRAIL"); + rtfte_lightning1 = P_FindParticleType("TE_LIGHTNING1"); + ptfte_lightning1_end = P_FindParticleType("TE_LIGHTNING1_END"); + rtfte_lightning2 = P_FindParticleType("TE_LIGHTNING2"); + ptfte_lightning2_end = P_FindParticleType("TE_LIGHTNING2_END"); + rtfte_lightning3 = P_FindParticleType("TE_LIGHTNING3"); + ptfte_lightning3_end = P_FindParticleType("TE_LIGHTNING3_END"); + ptfte_bullet = P_FindParticleType("TE_BULLET"); + ptfte_superbullet = P_FindParticleType("TE_SUPERBULLET"); } #ifdef Q2CLIENT @@ -1459,7 +1591,7 @@ void CL_ParseCustomTEnt(void) t->netstyle = MSG_ReadByte(); str = MSG_ReadString(); Q_strncpyz(t->name, str, sizeof(t->name)); - t->particleeffecttype = P_ParticleTypeForName(str); + t->particleeffecttype = P_FindParticleType(str); if (t->netstyle & CTE_STAINS) { @@ -1598,7 +1730,7 @@ void CLDP_ParseTrailParticles(void) else ts = NULL; - effectindex = P_ParticleTypeForName(COM_Effectinfo_ForNumber(effectindex)); + effectindex = P_FindParticleType(COM_Effectinfo_ForNumber(effectindex)); if (P_ParticleTrail(start, end, effectindex, ts)) P_ParticleTrail(start, end, rt_blood, ts); } @@ -1625,7 +1757,7 @@ void CLDP_ParsePointParticles(qboolean compact) count = (unsigned short)MSG_ReadShort(); } - effectindex = P_ParticleTypeForName(COM_Effectinfo_ForNumber(effectindex)); + effectindex = P_FindParticleType(COM_Effectinfo_ForNumber(effectindex)); if (P_RunParticleEffectType(org, dir, count, effectindex)) P_RunParticleEffect (org, dir, 15, 15); } diff --git a/engine/client/client.h b/engine/client/client.h index 83d86a472..1b683b77b 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -156,6 +156,7 @@ typedef struct player_info_s qbyte pl; qboolean ignored; + qboolean vignored; colourised_t *colourised; @@ -857,6 +858,7 @@ void CL_UseIndepPhysics(qboolean allow); void CL_FlushClientCommands(void); void VARGS CL_SendClientCommand(qboolean reliable, char *format, ...) LIKEPRINTF(2); +float CL_FilterTime (double time, float wantfps, qboolean ignoreserver); int CL_RemoveClientCommands(char *command); void CL_AllowIndependantSendCmd(qboolean allow); diff --git a/engine/client/m_master.c b/engine/client/m_master.c index dd96da4b6..36004f736 100644 --- a/engine/client/m_master.c +++ b/engine/client/m_master.c @@ -1413,6 +1413,12 @@ void M_Menu_ServerList2_f(void) menucustom_t *cust; serverlist_t *info; + if (!qrenderer) + { + Cbuf_AddText("wait; menu_servers\n", Cmd_ExecLevel); + return; + } + key_dest = key_menu; m_state = m_complex; diff --git a/engine/client/p_classic.c b/engine/client/p_classic.c index f537f0bff..d94aee56e 100644 --- a/engine/client/p_classic.c +++ b/engine/client/p_classic.c @@ -98,7 +98,7 @@ static shader_t *classicshader; //obtains an index for the name, even if it is unknown (one can be loaded after. will only fail if the effect limit is reached) //technically this function is not meant to fail often, but thats fine so long as the other functions are meant to safely reject invalid effect numbers. -static int PClassic_ParticleTypeForName(char *name) +static int PClassic_FindParticleType(char *name) { if (!stricmp("tr_rocket", name)) return ROCKET_TRAIL; @@ -132,9 +132,9 @@ static int PClassic_ParticleTypeForName(char *name) } //returns a valid effect if both its existance is known, and it is fully functional -static int PClassic_FindParticleType(char *name) +static int PClassic_ParticleTypeForName(char *name) { - return P_ParticleTypeForName(name); + return P_FindParticleType(name); } //a convienience function. @@ -183,9 +183,6 @@ static void PClassic_EmitSkyEffectTris(model_t *mod, msurface_t *fa) static qboolean PClassic_InitParticles (void) { int i; - model_t *mod; - extern model_t mod_known[]; - extern int mod_numknown; if ((i = COM_CheckParm ("-particles")) && i + 1 < com_argc) { @@ -199,17 +196,6 @@ static qboolean PClassic_InitParticles (void) particles = (cparticle_t *) BZ_Malloc (r_numparticles * sizeof(cparticle_t)); - CL_RegisterParticles(); - - for (i=0 , mod=mod_known ; iparticleeffect = P_INVALID; - mod->particletrail = P_INVALID; - mod->engineflags &= ~(MDLF_NODEFAULTTRAIL | MDLF_ENGULPHS); - - P_DefaultTrail(mod); - } - for (i = 0; i < BUFFERVERTS; i += 3) { classictexcoords[i+1][0] = 1; diff --git a/engine/client/p_null.c b/engine/client/p_null.c index ff671835b..6d9a3f1b6 100644 --- a/engine/client/p_null.c +++ b/engine/client/p_null.c @@ -33,7 +33,6 @@ static void PNULL_EmitSkyEffectTris(model_t *mod, msurface_t *fa){} static qboolean PNULL_InitParticles (void) { - CL_RegisterParticles(); return true; } diff --git a/engine/client/p_script.c b/engine/client/p_script.c index 860de1035..8fb665783 100644 --- a/engine/client/p_script.c +++ b/engine/client/p_script.c @@ -58,6 +58,10 @@ struct extern qbyte *host_basepal; +extern particleengine_t pe_classic; +extern particleengine_t *fallback = NULL; +#define FALLBACKBIAS 0x1000000 + static int pt_pointfile = P_INVALID; static int pe_default = P_INVALID; static int pe_size2 = P_INVALID; @@ -319,9 +323,9 @@ extern cvar_t r_bloodstains; extern cvar_t gl_part_flame; // callbacks -static void R_ParticlesDesc_Callback(struct cvar_s *var, char *oldvalue); +static void R_ParticleDesc_Callback(struct cvar_s *var, char *oldvalue); -extern cvar_t r_particlesdesc; +extern cvar_t r_particledesc; extern cvar_t r_part_rain_quantity; extern cvar_t r_particle_tracelimit; extern cvar_t r_part_sparks; @@ -452,10 +456,19 @@ static int PScript_FindParticleType(char *name) break; } } - if (!ptype) - return P_INVALID; - if (!ptype->loaded) + if (!ptype || !ptype->loaded) + { + if (fallback) + { + if (!strncmp(name, "classic_", 8)) + i = fallback->FindParticleType(name+8); + else + i = fallback->FindParticleType(name); + if (i != P_INVALID) + return i+FALLBACKBIAS; + } return P_INVALID; + } return i; } @@ -1069,7 +1082,7 @@ static void P_ParticleEffect_f(void) ptype->spawnchance = atof(value); else if (!strcmp(var, "cliptype")) { - assoc = P_ParticleTypeForName(value);//careful - this can realloc all the particle types + assoc = PScript_ParticleTypeForName(value);//careful - this can realloc all the particle types ptype = &part_type[pnum]; ptype->cliptype = assoc; } @@ -1078,7 +1091,7 @@ static void P_ParticleEffect_f(void) else if (!strcmp(var, "emit")) { - assoc = P_ParticleTypeForName(value);//careful - this can realloc all the particle types + assoc = PScript_ParticleTypeForName(value);//careful - this can realloc all the particle types ptype = &part_type[pnum]; ptype->emit = assoc; } @@ -1288,73 +1301,6 @@ static void P_ParticleEffect_f(void) r_plooksdirty = true; } -//assosiate a point effect with a model. -//the effect will be spawned every frame with count*frametime -//has the capability to hide models. -static void P_AssosiateEffect_f (void) -{ - char *modelname = Cmd_Argv(1); - char *effectname = Cmd_Argv(2); - int effectnum; - model_t *model; - - if (!cls.demoplayback && ( - strstr(modelname, "player") || - strstr(modelname, "eyes") || - strstr(modelname, "flag") || - strstr(modelname, "tf_stan") || - strstr(modelname, ".bsp") || - strstr(modelname, "turr"))) - { - Con_Printf("Sorry: Not allowed to attach effects to model \"%s\"\n", modelname); - return; - } - - model = Mod_FindName(modelname); - if (!model) - return; - if (!cls.demoplayback && (model->flags & EF_ROTATE)) - { - Con_Printf("Sorry: You may not assosiate effects with item model \"%s\"\n", modelname); - return; - } - effectnum = P_AllocateParticleType(effectname); - model->particleeffect = effectnum; - if (atoi(Cmd_Argv(3))) - model->engineflags |= MDLF_ENGULPHS; - - P_SetModified(); //make it appear in f_modified. -} - -//assosiate a particle trail with a model. -//the effect will be spawned between two points when an entity with the model moves. -static void P_AssosiateTrail_f (void) -{ - char *modelname = Cmd_Argv(1); - char *effectname = Cmd_Argv(2); - int effectnum; - model_t *model; - - if (!cls.demoplayback && ( - strstr(modelname, "player") || - strstr(modelname, "eyes") || - strstr(modelname, "flag") || - strstr(modelname, "tf_stan"))) - { - Con_Printf("Sorry, you can't assosiate trails with model \"%s\"\n", modelname); - return; - } - - model = Mod_FindName(modelname); - if (!model) - return; - effectnum = P_AllocateParticleType(effectname); - model->particletrail = effectnum; - model->engineflags |= MDLF_NODEFAULTTRAIL; //we could have assigned the trail to a model that wasn't loaded. - - P_SetModified(); //make it appear in f_modified. -} - #if _DEBUG // R_BeamInfo_f - debug junk static void P_BeamInfo_f (void) @@ -1784,8 +1730,6 @@ static qboolean PScript_InitParticles (void) Cmd_AddRemCommand("pointfile", P_ReadPointFile_f); //load the leak info produced from qbsp into the particle system to show a line. :) Cmd_AddRemCommand("r_part", P_ParticleEffect_f); - Cmd_AddRemCommand("r_effect", P_AssosiateEffect_f); - Cmd_AddRemCommand("r_trail", P_AssosiateTrail_f); Cmd_AddRemCommand("r_exportbuiltinparticles", P_ExportBuiltinSet_f); Cmd_AddRemCommand("r_importeffectinfo", P_ImportEffectInfo_f); @@ -1795,7 +1739,6 @@ static qboolean PScript_InitParticles (void) Cmd_AddRemCommand("r_beaminfo", P_BeamInfo_f); #endif - CL_RegisterParticles(); pt_pointfile = P_AllocateParticleType("PT_POINTFILE"); pe_default = P_AllocateParticleType("PE_DEFAULT"); @@ -1803,8 +1746,8 @@ static qboolean PScript_InitParticles (void) pe_size3 = P_AllocateParticleType("PE_SIZE3"); pe_defaulttrail = P_AllocateParticleType("PE_DEFAULTTRAIL"); - Cvar_Hook(&r_particlesdesc, R_ParticlesDesc_Callback); - Cvar_ForceCallback(&r_particlesdesc); + Cvar_Hook(&r_particledesc, R_ParticleDesc_Callback); + Cvar_ForceCallback(&r_particledesc); for (i = 0; i < (BUFFERVERTS>>2)*6; i += 6) @@ -1828,18 +1771,22 @@ static qboolean PScript_InitParticles (void) pscripttmesh.st_array = pscripttexcoords; pscripttmesh.colors4f_array = pscriptcolours; pscripttmesh.indexes = pscripttriindexes; + + if (fallback) + fallback->InitParticles(); return true; } static void PScript_Shutdown (void) { - Cvar_Unhook(&r_particlesdesc); + if (fallback) + fallback->ShutdownParticles(); + + Cvar_Unhook(&r_particledesc); Cmd_RemoveCommand("pointfile"); //load the leak info produced from qbsp into the particle system to show a line. :) Cmd_RemoveCommand("r_part"); - Cmd_RemoveCommand("r_effect"); - Cmd_RemoveCommand("r_trail"); Cmd_RemoveCommand("r_exportbuiltinparticles"); Cmd_RemoveCommand("r_importeffectinfo"); @@ -1867,6 +1814,9 @@ static void PScript_ClearParticles (void) { int i; + if (fallback) + fallback->ClearParticles(); + free_particles = &particles[0]; for (i=0 ;iShutdownParticles(); + fallback = &pe_classic; + if (fallback) + fallback->InitParticles(); + return; + } + for (i = 0; partset_list[i].name; i++) { if (!stricmp(name, partset_list[i].name)) @@ -1977,10 +1937,6 @@ static void P_LoadParticleSet(char *name, qboolean first) static void R_Particles_KillAllEffects(void) { int i; - - model_t *mod; - extern model_t mod_known[]; - extern int mod_numknown; for (i = 0; i < numparticletypes; i++) { @@ -1995,26 +1951,23 @@ static void R_Particles_KillAllEffects(void) // BZ_Free(part_type); // part_type = NULL; - for (i=0 , mod=mod_known ; iparticleeffect = P_INVALID; - mod->particletrail = P_INVALID; - mod->engineflags &= ~(MDLF_NODEFAULTTRAIL | MDLF_ENGULPHS); - - P_DefaultTrail(mod); - } - f_modified_particles = false; + + if (fallback) + { + fallback->ShutdownParticles(); + fallback = NULL; + } } -static void R_ParticlesDesc_Callback(struct cvar_s *var, char *oldvalue) +static void R_ParticleDesc_Callback(struct cvar_s *var, char *oldvalue) { qboolean first; char *c; - if (cls.state == ca_disconnected) - return; // don't bother parsing while disconnected + if (qrenderer == QR_NONE) + return; // don't bother parsing early R_Particles_KillAllEffects(); @@ -2024,6 +1977,9 @@ static void R_ParticlesDesc_Callback(struct cvar_s *var, char *oldvalue) P_LoadParticleSet(com_token, first); first = false; } + + Cbuf_AddText("r_effect\n", RESTRICT_LOCAL); + CL_RegisterParticles(); } static void P_ReadPointFile_f (void) @@ -2362,6 +2318,9 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count, vec3_t ofsvec, arsvec; // offsetspread vec, areaspread vec trailstate_t *ts; + if (typenum >= FALLBACKBIAS && fallback) + return fallback->RunParticleEffectState(org, dir, count, typenum-FALLBACKBIAS, tsk); + if (typenum < 0 || typenum >= numparticletypes) return 1; @@ -2962,25 +2921,26 @@ static void PScript_RunParticleEffect (vec3_t org, vec3_t dir, int color, int co ptype = P_FindParticleType(va("pe_%i", color)); if (P_RunParticleEffectType(org, dir, count, ptype)) { - color &= ~0x7; if (count > 130 && part_type[pe_size3].loaded) { - part_type[pe_size3].colorindex = color; + part_type[pe_size3].colorindex = color & ~0x7; part_type[pe_size3].colorrand = 8; P_RunParticleEffectType(org, dir, count, pe_size3); - return; } - if (count > 20 && part_type[pe_size2].loaded) + else if (count > 20 && part_type[pe_size2].loaded) { - part_type[pe_size2].colorindex = color; + part_type[pe_size2].colorindex = color & ~0x7; part_type[pe_size2].colorrand = 8; P_RunParticleEffectType(org, dir, count, pe_size2); - return; } - part_type[pe_default].colorindex = color; - part_type[pe_default].colorrand = 8; - P_RunParticleEffectType(org, dir, count, pe_default); - return; + else if (part_type[pe_default].loaded || !fallback) + { + part_type[pe_default].colorindex = color & ~0x7; + part_type[pe_default].colorrand = 8; + P_RunParticleEffectType(org, dir, count, pe_default); + } + else + fallback->RunParticleEffect(org, dir, color, count); } } @@ -3644,6 +3604,9 @@ static int PScript_ParticleTrail (vec3_t startpos, vec3_t end, int type, trailst { part_type_t *ptype = &part_type[type]; + if (type >= FALLBACKBIAS && fallback) + return fallback->ParticleTrail(startpos, end, type-FALLBACKBIAS, tsk); + if (type < 0 || type >= numparticletypes) return 1; //bad value @@ -4554,6 +4517,9 @@ static void PScript_DrawParticles (void) P_AddRainParticles(); PScript_DrawParticleTypes(GL_DrawTexturedParticle, GL_DrawLineSparkParticle, GL_DrawTrifanParticle, GL_DrawTexturedSparkParticle, GL_DrawParticleBeam, GL_DrawClippedDecal); + + if (fallback) + fallback->DrawParticles(); } diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 99069a4b5..dc8ab673d 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -30,9 +30,6 @@ #define QCEditor NULL #endif - -#define ANGLE2SHORT(x) ((x/360.0)*65535) - static progfuncs_t *csqcprogs; typedef struct csqctreadstate_s { @@ -2314,6 +2311,7 @@ static void PF_cs_sound(progfuncs_t *prinst, struct globalvars_s *pr_globals) csqcedict_t *entity; float volume; float attenuation; + float pitchpct; sfx_t *sfx; @@ -2322,10 +2320,14 @@ static void PF_cs_sound(progfuncs_t *prinst, struct globalvars_s *pr_globals) sample = PR_GetStringOfs(prinst, OFS_PARM2); volume = G_FLOAT(OFS_PARM3); attenuation = G_FLOAT(OFS_PARM4); + if (*prinst->callargc >= 6) + pitchpct = G_FLOAT(OFS_PARM5); + else + pitchpct = 0; sfx = S_PrecacheSound(sample); if (sfx) - S_StartSound(-entity->entnum, channel, sfx, entity->v->origin, volume, attenuation, 0); + S_StartSound(-entity->entnum, channel, sfx, entity->v->origin, volume, attenuation, pitchpct); }; void PF_cs_pointsound(progfuncs_t *prinst, struct globalvars_s *pr_globals) @@ -2334,6 +2336,7 @@ void PF_cs_pointsound(progfuncs_t *prinst, struct globalvars_s *pr_globals) float *origin; float volume; float attenuation; + float pitchpct; sfx_t *sfx; @@ -2341,10 +2344,14 @@ void PF_cs_pointsound(progfuncs_t *prinst, struct globalvars_s *pr_globals) sample = PR_GetStringOfs(prinst, OFS_PARM1); volume = G_FLOAT(OFS_PARM2); attenuation = G_FLOAT(OFS_PARM3); + if (*prinst->callargc >= 5) + pitchpct = G_FLOAT(OFS_PARM4); + else + pitchpct = 0; sfx = S_PrecacheSound(sample); if (sfx) - S_StartSound(0, 0, sfx, origin, volume, attenuation, 0); + S_StartSound(0, 0, sfx, origin, volume, attenuation, pitchpct); } static void PF_cs_particle(progfuncs_t *prinst, struct globalvars_s *pr_globals) diff --git a/engine/client/r_part.c b/engine/client/r_part.c index 301e48923..f0c1da77e 100644 --- a/engine/client/r_part.c +++ b/engine/client/r_part.c @@ -37,8 +37,9 @@ void R_Rockettrail_Callback(struct cvar_s *var, char *oldvalue) for (i=0 , mod=mod_known ; iflags & EF_ROCKET) - P_DefaultTrail(mod); + if (!mod->needload) + if (mod->flags & EF_ROCKET) + P_DefaultTrail(mod); } } @@ -54,8 +55,9 @@ void R_Grenadetrail_Callback(struct cvar_s *var, char *oldvalue) for (i=0 , mod=mod_known ; iflags & EF_GRENADE) - P_DefaultTrail(mod); + if (!mod->needload) + if (mod->flags & EF_GRENADE) + P_DefaultTrail(mod); } } @@ -119,7 +121,7 @@ void R_ParticleSystem_Callback(struct cvar_s *var, char *oldvalue) cvar_t r_rockettrail = CVARFC("r_rockettrail", "1", CVAR_SEMICHEAT, R_Rockettrail_Callback); cvar_t r_grenadetrail = CVARFC("r_grenadetrail", "1", CVAR_SEMICHEAT, R_Grenadetrail_Callback); cvar_t r_particlesystem = CVARFC("r_particlesystem", IFMINIMAL("classic", "script"), CVAR_SEMICHEAT, R_ParticleSystem_Callback); -cvar_t r_particlesdesc = CVARF("r_particlesdesc", "spikeset tsshaft", CVAR_SEMICHEAT); +cvar_t r_particledesc = CVARAF("r_particledesc", "classic", "r_particlesdesc", CVAR_SEMICHEAT); extern cvar_t r_bouncysparks; extern cvar_t r_part_rain; extern cvar_t r_bloodstains; @@ -146,7 +148,7 @@ void P_InitParticleSystem(void) //particles - Cvar_Register(&r_particlesdesc, particlecvargroupname); + Cvar_Register(&r_particledesc, particlecvargroupname); Cvar_Register(&r_bouncysparks, particlecvargroupname); Cvar_Register(&r_part_rain, particlecvargroupname); @@ -308,31 +310,31 @@ void P_SelectableTrail(model_t *model, cvar_t *selection, int mdleffect, int mdl model->traildefaultindex= oppcidx; break; case 3: // alt rocket effect - model->particletrail = P_ParticleTypeForName("TR_ALTROCKET"); + model->particletrail = P_FindParticleType("TR_ALTROCKET"); model->traildefaultindex = 107; break; case 4: // gib - model->particletrail = P_ParticleTypeForName("TR_BLOOD"); + model->particletrail = P_FindParticleType("TR_BLOOD"); model->traildefaultindex = 70; break; case 5: // zombie gib - model->particletrail = P_ParticleTypeForName("TR_SLIGHTBLOOD"); + model->particletrail = P_FindParticleType("TR_SLIGHTBLOOD"); model->traildefaultindex = 70; break; case 6: // Scrag tracer - model->particletrail = P_ParticleTypeForName("TR_WIZSPIKE"); + model->particletrail = P_FindParticleType("TR_WIZSPIKE"); model->traildefaultindex = 60; break; case 7: // Knight tracer - model->particletrail = P_ParticleTypeForName("TR_KNIGHTSPIKE"); + model->particletrail = P_FindParticleType("TR_KNIGHTSPIKE"); model->traildefaultindex = 238; break; case 8: // Vore tracer - model->particletrail = P_ParticleTypeForName("TR_VORESPIKE"); + model->particletrail = P_FindParticleType("TR_VORESPIKE"); model->traildefaultindex = 154; break; case 9: // rail trail - model->particletrail = P_ParticleTypeForName("TR_RAILTRAIL"); + model->particletrail = P_FindParticleType("TR_RAILTRAIL"); model->traildefaultindex = 15; break; } @@ -349,87 +351,87 @@ void P_DefaultTrail (model_t *model) return; if (model->flags & EF_ROCKET) - P_SelectableTrail(model, &r_rockettrail, P_ParticleTypeForName("TR_ROCKET"), 109, P_ParticleTypeForName("TR_GRENADE"), 6); + P_SelectableTrail(model, &r_rockettrail, P_FindParticleType("TR_ROCKET"), 109, P_FindParticleType("TR_GRENADE"), 6); else if (model->flags & EF_GRENADE) - P_SelectableTrail(model, &r_grenadetrail, P_ParticleTypeForName("TR_GRENADE"), 6, P_ParticleTypeForName("TR_ROCKET"), 109); + P_SelectableTrail(model, &r_grenadetrail, P_FindParticleType("TR_GRENADE"), 6, P_FindParticleType("TR_ROCKET"), 109); else if (model->flags & EF_GIB) { - model->particletrail = P_ParticleTypeForName("TR_BLOOD"); + model->particletrail = P_FindParticleType("TR_BLOOD"); model->traildefaultindex = 70; } else if (model->flags & EF_TRACER) { - model->particletrail = P_ParticleTypeForName("TR_WIZSPIKE"); + model->particletrail = P_FindParticleType("TR_WIZSPIKE"); model->traildefaultindex = 60; } else if (model->flags & EF_ZOMGIB) { - model->particletrail = P_ParticleTypeForName("TR_SLIGHTBLOOD"); + model->particletrail = P_FindParticleType("TR_SLIGHTBLOOD"); model->traildefaultindex = 70; } else if (model->flags & EF_TRACER2) { - model->particletrail = P_ParticleTypeForName("TR_KNIGHTSPIKE"); + model->particletrail = P_FindParticleType("TR_KNIGHTSPIKE"); model->traildefaultindex = 238; } else if (model->flags & EF_TRACER3) { - model->particletrail = P_ParticleTypeForName("TR_VORESPIKE"); + model->particletrail = P_FindParticleType("TR_VORESPIKE"); model->traildefaultindex = 154; } else if (model->flags & EFH2_BLOODSHOT) //these are the hexen2 ones. { - model->particletrail = P_ParticleTypeForName("t_bloodshot"); + model->particletrail = P_FindParticleType("t_bloodshot"); model->traildefaultindex = 136; } else if (model->flags & EFH2_FIREBALL) { - model->particletrail = P_ParticleTypeForName("t_fireball"); + model->particletrail = P_FindParticleType("t_fireball"); model->traildefaultindex = 424; } else if (model->flags & EFH2_ACIDBALL) { - model->particletrail = P_ParticleTypeForName("t_acidball"); + model->particletrail = P_FindParticleType("t_acidball"); model->traildefaultindex = 440; } else if (model->flags & EFH2_ICE) { - model->particletrail = P_ParticleTypeForName("t_ice"); + model->particletrail = P_FindParticleType("t_ice"); model->traildefaultindex = 408; } else if (model->flags & EFH2_SPIT) { - model->particletrail = P_ParticleTypeForName("t_spit"); + model->particletrail = P_FindParticleType("t_spit"); model->traildefaultindex = 260; } else if (model->flags & EFH2_SPELL) { - model->particletrail = P_ParticleTypeForName("t_spell"); + model->particletrail = P_FindParticleType("t_spell"); model->traildefaultindex = 260; } else if (model->flags & EFH2_VORP_MISSILE) { - model->particletrail = P_ParticleTypeForName("t_vorpmissile"); + model->particletrail = P_FindParticleType("t_vorpmissile"); model->traildefaultindex = 302; } else if (model->flags & EFH2_SET_STAFF) { - model->particletrail = P_ParticleTypeForName("t_setstaff"); + model->particletrail = P_FindParticleType("t_setstaff"); model->traildefaultindex = 424; } else if (model->flags & EFH2_MAGICMISSILE) { - model->particletrail = P_ParticleTypeForName("t_magicmissile"); + model->particletrail = P_FindParticleType("t_magicmissile"); model->traildefaultindex = 149; } else if (model->flags & EFH2_BONESHARD) { - model->particletrail = P_ParticleTypeForName("t_boneshard"); + model->particletrail = P_FindParticleType("t_boneshard"); model->traildefaultindex = 384; } else if (model->flags & EFH2_SCARAB) { - model->particletrail = P_ParticleTypeForName("t_scarab"); + model->particletrail = P_FindParticleType("t_scarab"); model->traildefaultindex = 254; } else diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 681c0b64c..b94adbe22 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -1753,10 +1753,13 @@ TRACE(("dbg: R_ApplyRenderer: efrags\n")); Skin_FlushPlayers(); } -#ifdef VM_UI else + { + Cvar_ForceCallback(&r_particlesystem); +#ifdef VM_UI UI_Reset(); #endif + } switch (qrenderer) { @@ -2741,7 +2744,5 @@ void R_InitParticleTexture (void) } } ptritexture = R_LoadTexture32("", PARTICLETEXTURESIZE, PARTICLETEXTURESIZE, data, IF_NOMIPMAP|IF_NOPICMIP); - - Cvar_ForceCallback(&r_particlesystem); } diff --git a/engine/client/sbar.c b/engine/client/sbar.c index 272b61958..56059f0cb 100644 --- a/engine/client/sbar.c +++ b/engine/client/sbar.c @@ -2269,7 +2269,6 @@ qboolean Sbar_UpdateTeamStatus(player_info_t *player, char *status) static void Sbar_Voice(int y) { #ifdef VOICECHAT - char st[64]; int loudness; if (!cl_voip_showmeter.ival) return; diff --git a/engine/client/snd_al.c b/engine/client/snd_al.c index 95d0fe224..fd90c2fc1 100644 --- a/engine/client/snd_al.c +++ b/engine/client/snd_al.c @@ -155,6 +155,7 @@ static void S_Info(void); static void S_Shutdown_f(void); */ +static cvar_t s_al_enable = CVAR("s_al_enable", "0"); static cvar_t s_al_debug = CVAR("s_al_debug", "0"); static cvar_t s_al_max_distance = CVARFC("s_al_max_distance", "1000",0,OnChangeALMaxDistance); static cvar_t s_al_speedofsound = CVARFC("s_al_speedofsound", "343.3",0,OnChangeALSpeedOfSound); @@ -164,13 +165,9 @@ static cvar_t s_al_rolloff_factor = CVAR("s_al_rolloff_factor", "1"); static cvar_t s_al_reference_distance = CVAR("s_al_reference_distance", "120");static cvar_t s_al_velocityscale = CVAR("s_al_velocityscale", "1"); static cvar_t s_al_static_listener = CVAR("s_al_static_listener", "0"); //cheat -#define NUM_SOURCES 96 +#define NUM_SOURCES MAX_CHANNELS static ALuint source[NUM_SOURCES]; - -static ALuint static_source[NUM_SOURCES]; -static int num_static_source; - static ALCdevice *OpenAL_Device; static ALCcontext *OpenAL_Context; @@ -273,6 +270,7 @@ void OpenAL_LoadCache(sfx_t *s, sfxcache_t *sc) void OpenAL_CvarInit(void) { + Cvar_Register(&s_al_enable, SOUNDVARS); Cvar_Register(&s_al_debug, SOUNDVARS); Cvar_Register(&s_al_max_distance, SOUNDVARS); Cvar_Register(&s_al_dopplerfactor, SOUNDVARS); @@ -284,26 +282,11 @@ void OpenAL_CvarInit(void) Cvar_Register(&s_al_speedofsound, SOUNDVARS); } -void OpenAL_Update_Listener(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up) +extern float voicevolumemod; +void OpenAL_Update_Listener(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up, vec3_t velocity) { - static vec3_t oldpos; - vec3_t velocity; - vec3_t temp; - - VectorSubtract(origin,oldpos,velocity); - - - VectorCopy(origin, oldpos); - - - temp[0] = velocity[0]; - temp[1] = velocity[1]; - temp[2] = velocity[2]; - ListenPos[0] = origin[0]; - ListenPos[1] = origin[1]; - ListenPos[2] = origin[2]; - - + VectorScale(velocity, s_al_velocityscale.value, ListenVel); + VectorCopy(origin, ListenPos); ListenOri[0] = forward[0]; ListenOri[1] = forward[1]; @@ -311,17 +294,13 @@ void OpenAL_Update_Listener(vec3_t origin, vec3_t forward, vec3_t right, vec3_t ListenOri[3] = up[0]; ListenOri[4] = up[1]; ListenOri[5] = up[2]; - + if (!s_al_static_listener.value) { - palListenerf(AL_GAIN, volume.value); - + palListenerf(AL_GAIN, volume.value*voicevolumemod); palListenerfv(AL_POSITION, ListenPos); - - VectorScale(velocity,s_al_velocityscale.value, velocity); - palListenerfv(AL_VELOCITY, velocity); - + palListenerfv(AL_VELOCITY, ListenVel); palListenerfv(AL_ORIENTATION, ListenOri); } } @@ -339,7 +318,7 @@ static void OpenAL_StopAllSounds(qboolean clear) } } */ - +/* void OpenAL_StartSound(int entnum, int entchannel, sfx_t * sfx, vec3_t origin, float fvol, float attenuation, float pitch) { vec3_t tmp; @@ -392,6 +371,81 @@ void OpenAL_StartSound(int entnum, int entchannel, sfx_t * sfx, vec3_t origin, f if (num_sfx >= NUM_SOURCES) num_sfx =0; + PrintALError("post start sound"); +}*/ + +static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, unsigned int schanged) +{ + ALuint src; + sfx_t *sfx = chan->sfx; + float pitch; + + src = source[chan - sc->channel]; + if (!src) + { + if (!sfx || chan->master_vol == 0) + return; + palGenSources(1, &src); + source[chan - sc->channel] = src; + schanged = true; + } + + PrintALError("pre start sound"); + + if (schanged && src) + palSourceStop(src); + + /*just wanted to stop it?*/ + if (!sfx || chan->master_vol == 0) + { + if (src) + { + palDeleteBuffers(1, &src); + source[chan - sc->channel] = 0; + } + return; + } + + if (schanged) + { + if (!sfx->openal_buffer) + { + sfxcache_t *sc = S_LoadSound(sfx); + if (!sc) /*ack! can't start it if its not loaded!*/ + return; + OpenAL_LoadCache(sfx, sc); + } + + palSourcei(src, AL_BUFFER, sfx->openal_buffer); + } + palSourcef(src, AL_GAIN, chan->master_vol/255.0f); +// palSourcef(src, AL_MAX_DISTANCE, s_al_max_distance.value); +// palSourcef(src, AL_ROLLOFF_FACTOR, s_al_rolloff_factor.value); + palSourcefv(src, AL_POSITION, chan->origin); + palSourcefv(src, AL_VELOCITY, vec3_origin); + + if (schanged) + { + pitch = (float)chan->rate/(1<looping?AL_TRUE:AL_FALSE); + if (chan->entnum == -1 || chan->entnum == cl.playernum[0]+1) + { + palSourcei(src, AL_SOURCE_RELATIVE, AL_TRUE); + palSourcef(src, AL_ROLLOFF_FACTOR, 0.0f); + } + else + { + palSourcei(src, AL_SOURCE_RELATIVE, AL_FALSE); + palSourcef(src, AL_ROLLOFF_FACTOR, s_al_rolloff_factor.value*chan->dist_mult); + } + + /*and start it up again*/ + palSourcePlay(src); + } + PrintALError("post start sound"); } @@ -455,8 +509,6 @@ static qboolean OpenAL_Init(void) return false; } - num_static_source = 0; - OpenAL_Device = palcOpenDevice(NULL); if (OpenAL_Device == NULL) { @@ -473,8 +525,6 @@ static qboolean OpenAL_Init(void) palGenSources(NUM_SOURCES, source); PrintALError("alGensources for normal sources"); - palGenSources(NUM_SOURCES, static_source); - PrintALError("alGensources for static sources"); palListenerfv(AL_POSITION, ListenPos); @@ -566,7 +616,6 @@ static void OpenAL_Shutdown (soundcardinfo_t *sc) int i; palDeleteSources(NUM_SOURCES, source); - palDeleteSources(NUM_SOURCES, static_source); /*make sure the buffers are cleared from the sound effects*/ for (i=0;iSubmit = OpenAL_Submit; sc->Shutdown = OpenAL_Shutdown; sc->GetDMAPos = OpenAL_GetDMAPos; + sc->ChannelUpdate = OpenAL_ChannelUpdate; snprintf(sc->name, sizeof(sc->name), "OpenAL device"); sc->openal = 1; sc->inactive_sound = true; + sc->selfpainting = true; Cvar_ForceCallback(&s_al_distancemodel); Cvar_ForceCallback(&s_al_speedofsound); diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c index 71c967a02..b2c4b0b7a 100644 --- a/engine/client/snd_dma.c +++ b/engine/client/snd_dma.c @@ -45,6 +45,7 @@ vec3_t listener_origin; vec3_t listener_forward = {1, 0, 0}; vec3_t listener_right = {0, 1, 0}; vec3_t listener_up = {0, 0, 1}; +vec3_t listener_velocity; vec_t sound_nominal_clip_dist=1000.0; int soundtime; // sample PAIRS @@ -541,7 +542,10 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf) memmove(s_speex.capturebuf, s_speex.capturebuf + encpos, s_speex.capturepos-encpos); s_speex.capturepos -= encpos; } - +void S_Voip_Ignore(int slot, qboolean ignore) +{ + CL_SendClientCommand(true, "vignore %i %i", slot, ignore); +} static void S_Voip_Enable_f(void) { Cvar_SetValue(&cl_voip_send, cl_voip_send.ival | 2); @@ -605,6 +609,7 @@ typedef struct { } sdriver_t; sdriver_t drivers[] = { //in order of preference + {"OpenAL", &pOPENAL_InitCard}, //yay, get someone else to sort out sound support, woot {"DSound", &pDSOUND_InitCard}, //prefered on windows {"MacOS", &pMacOS_InitCard}, //prefered on mac @@ -614,7 +619,6 @@ sdriver_t drivers[] = { {"ALSA", &pALSA_InitCard}, //pure shite {"OSS", &pOSS_InitCard}, //good, but not likely to work any more - {"OpenAL", &pOPENAL_InitCard}, //yay, get someone else to sort out sound support, woot {"WaveOut", &pWAV_InitCard}, //doesn't work properly in vista, etc. {NULL, NULL} }; @@ -1296,7 +1300,7 @@ void SND_Spatialize(soundcardinfo_t *sc, channel_t *ch) // Start a sound effect // ======================================================================= -void S_StartSoundCard(soundcardinfo_t *sc, int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, int startpos, int pitchadj) +void S_StartSoundCard(soundcardinfo_t *sc, int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, int startpos, float pitchadj) { channel_t *target_chan, *check; sfxcache_t *scache; @@ -1313,17 +1317,9 @@ void S_StartSoundCard(soundcardinfo_t *sc, int entnum, int entchannel, sfx_t *sf if (nosound.ival) return; - if (!pitchadj) + if (pitchadj <= 0) pitchadj = 100; -#ifdef AVAIL_OPENAL - if (sc->openal) - { - OpenAL_StartSound(entnum, entchannel, sfx, origin, fvol, attenuation, pitchadj / 100.0f); - return; - } -#endif - vol = fvol*255; // pick a channel to play on @@ -1386,6 +1382,9 @@ void S_StartSoundCard(soundcardinfo_t *sc, int entnum, int entchannel, sfx_t *sf break; } } + + if (sc->ChannelUpdate) + sc->ChannelUpdate(sc, target_chan, true); } void S_StartSoundDelayed(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, float timeofs) @@ -1399,7 +1398,7 @@ void S_StartSoundDelayed(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, S_StartSoundCard(sc, entnum, entchannel, sfx, origin, fvol, attenuation, -(int)(timeofs * sc->sn.speed), 0); } -void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, int pitchadj) +void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, float pitchadj) { soundcardinfo_t *sc; @@ -1434,6 +1433,8 @@ void S_StopSoundCard(soundcardinfo_t *sc, int entnum, int entchannel) { sc->channel[i].end = 0; sc->channel[i].sfx = NULL; + if (sc->ChannelUpdate) + sc->ChannelUpdate(sc, &sc->channel[i], true); if (entchannel) return; } @@ -1470,6 +1471,8 @@ void S_StopAllSounds(qboolean clear) { s->decoder->abort(s); } + if (sc->ChannelUpdate) + sc->ChannelUpdate(sc, &sc->channel[i], true); } sc->total_chans = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS + NUM_MUSICS; // no statics @@ -1543,6 +1546,7 @@ void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation) scache->loopstart = 0; } + ss->entnum = -2; ss->sfx = sfx; ss->rate = 1<origin); @@ -1552,6 +1556,9 @@ void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation) ss->looping = true; SND_Spatialize (scard, ss); + + if (scard->ChannelUpdate) + scard->ChannelUpdate(scard, ss, true); } } @@ -1620,7 +1627,7 @@ mleaf_t *Q1BSP_LeafForPoint (model_t *model, vec3_t p); void S_UpdateAmbientSounds (soundcardinfo_t *sc) { mleaf_t *l; - float vol; + float vol, oldvol; int ambient_channel; channel_t *chan; int i; @@ -1666,14 +1673,22 @@ void S_UpdateAmbientSounds (soundcardinfo_t *sc) if (!l || !ambient_level.value) { for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++) - sc->channel[AMBIENT_FIRST+ambient_channel].sfx = NULL; + { + chan = &sc->channel[AMBIENT_FIRST+ambient_channel]; + chan->sfx = NULL; + if (sc->ChannelUpdate) + sc->ChannelUpdate(sc, chan, true); + } return; } for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++) { + static float level[NUM_AMBIENTS]; chan = &sc->channel[AMBIENT_FIRST+ambient_channel]; chan->sfx = ambient_sfx[AMBIENT_FIRST+ambient_channel]; + chan->entnum = -1; + chan->looping = true; chan->rate = 1<origin); @@ -1682,21 +1697,27 @@ void S_UpdateAmbientSounds (soundcardinfo_t *sc) if (vol < 8) vol = 0; + oldvol = level[ambient_channel]; + // don't adjust volume too fast - if (chan->master_vol < vol) + if (level[ambient_channel] < vol) { - chan->master_vol += host_frametime * ambient_fade.value; - if (chan->master_vol > vol) - chan->master_vol = vol; + level[ambient_channel] += host_frametime * ambient_fade.value; + if (level[ambient_channel] > vol) + level[ambient_channel] = vol; } else if (chan->master_vol > vol) { - chan->master_vol -= host_frametime * ambient_fade.value; - if (chan->master_vol < vol) - chan->master_vol = vol; + level[ambient_channel] -= host_frametime * ambient_fade.value; + if (level[ambient_channel] < vol) + level[ambient_channel] = vol; } + chan->master_vol = level[ambient_channel]; chan->vol[0] = chan->vol[1] = chan->vol[2] = chan->vol[3] = chan->vol[4] = chan->vol[5] = chan->master_vol; + + if (sc->ChannelUpdate) + sc->ChannelUpdate(sc, chan, (oldvol == 0) ^ (level[ambient_channel] == 0)); } } @@ -1741,8 +1762,7 @@ void S_UpdateCard(soundcardinfo_t *sc) #ifdef AVAIL_OPENAL if (sc->openal == 1) { - OpenAL_Update_Listener(listener_origin, listener_forward, listener_right, listener_up); - return; + OpenAL_Update_Listener(listener_origin, listener_forward, listener_right, listener_up, listener_velocity); } #endif diff --git a/engine/client/sound.h b/engine/client/sound.h index 67f0138cb..3c88ebdd3 100644 --- a/engine/client/sound.h +++ b/engine/client/sound.h @@ -115,7 +115,7 @@ typedef struct soundcardinfo_s soundcardinfo_t; void S_Init (void); void S_Startup (void); void S_Shutdown (void); -void S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, int pitchadj); +void S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, float pitchadj); void S_StartSoundDelayed(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, float timeofs); void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation); void S_StopSound (int entnum, int entchannel); @@ -154,9 +154,11 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf); void S_Voip_MapChange(void); int S_Voip_Loudness(qboolean ignorevad); //-1 for not capturing, otherwise between 0 and 100 qboolean S_Voip_Speaking(unsigned int plno); +void S_Voip_Ignore(unsigned int plno, qboolean ignore); #else #define S_Voip_Loudness() -1 #define S_Voip_Speaking(p) false +#define S_Voip_Ignore(p) #endif qboolean S_IsPlayingSomewhere(sfx_t *s); @@ -187,7 +189,7 @@ void SNDVC_MicInput(qbyte *buffer, int samples, int freq, int width); #ifdef AVAIL_OPENAL void OpenAL_LoadCache(sfx_t *s, sfxcache_t *sc); void OpenAL_StartSound(int entnum, int entchannel, sfx_t * sfx, vec3_t origin, float fvol, float attenuation, float pitchscale); -void OpenAL_Update_Listener(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up); +void OpenAL_Update_Listener(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up, vec3_t velocity); void OpenAL_CvarInit(void); #endif @@ -287,6 +289,7 @@ struct soundcardinfo_s { //windows has one defined AFTER directsound unsigned int (*GetDMAPos) (soundcardinfo_t *sc); void (*SetWaterDistortion) (soundcardinfo_t *sc, qboolean underwater); void (*Restore) (soundcardinfo_t *sc); + void (*ChannelUpdate) (soundcardinfo_t *sc, channel_t *channel, unsigned int schanged); //driver -specific void *handle; diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index ce81ccffd..8ff542c44 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -1250,6 +1250,7 @@ void NPQTV_Sys_Shutdown(void) } #else + /* ================== WinMain @@ -1261,6 +1262,134 @@ char *argv[MAX_NUM_ARGVS]; static char exename[256]; HWND hwnd_dialog; + + +#define COBJMACROS +#include +#include +#include +//#include + +#ifndef SHARD_APPIDINFOLINK +typedef struct SHARDAPPIDINFOLINK { + IShellLinkW *psl; + PCWSTR pszAppID; +} SHARDAPPIDINFOLINK; + +#define SHARD_APPIDINFOLINK 0x00000007 + +typedef struct { + GUID fmtid; + DWORD pid; +} PROPERTYKEY; +typedef struct IPropertyStore IPropertyStore; +; +typedef struct IPropertyStore +{ + CONST_VTBL struct + { + /*IUnknown*/ + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IPropertyStore * This, + REFIID riid, + void **ppvObject); + ULONG ( STDMETHODCALLTYPE *AddRef )( + IPropertyStore * This); + ULONG ( STDMETHODCALLTYPE *Release )( + IPropertyStore * This); + + /*property store stuff*/ + HRESULT ( STDMETHODCALLTYPE *GetCount)( + IPropertyStore * This, + ULONG *count); + + HRESULT ( STDMETHODCALLTYPE *GetAt)( + IPropertyStore * This, + DWORD prop, + PROPERTYKEY * key); + + HRESULT ( STDMETHODCALLTYPE *GetValue)( + IPropertyStore * This, + PROPERTYKEY * key, + PROPVARIANT * val); + + HRESULT ( STDMETHODCALLTYPE *SetValue)( + IPropertyStore * This, + PROPERTYKEY * key, + PROPVARIANT * val); + + HRESULT ( STDMETHODCALLTYPE *Commit)( + IPropertyStore * This); + } *lpVtbl; +} IPropertyStore; +static const IID IID_IPropertyStore = {0x886d8eeb, 0x8cf2, 0x4446, {0x8d, 0x02, 0xcd, 0xba, 0x1d, 0xbd, 0xcf, 0x99}}; +#endif + +#define WIN7_APPNAME L"FTEQuake" +void Sys_RecentServer(char *command, char *target, char *title, char *desc) +{ + HRESULT hr; + IShellLinkW *link; + IPropertyStore *prop_store; + SHARDAPPIDINFOLINK appinfo; + + WCHAR buf[1024]; + char tmp[1024], *s; + + // Get a pointer to the IShellLink interface. + hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, &link); + if (FAILED(hr)) + return; + swprintf(buf, sizeof(buf), L"%S", exename); + IShellLinkW_SetPath(link, buf); /*program to run*/ + Q_strncpyz(tmp, com_quakedir, sizeof(tmp)); + /*normalize the gamedir, so we don't end up with the same thing multiple times*/ + for(s = tmp; *s; s++) + { + if (*s == '\\') + *s = '/'; + else + *s = tolower(*s); + } + swprintf(buf, sizeof(buf), L"%S \"%S\" -basedir \"%S\"", command, target, tmp); + IShellLinkW_SetArguments(link, buf); /*args*/ + swprintf(buf, sizeof(buf), L"%S", desc); + IShellLinkW_SetDescription(link, buf); /*tooltip*/ + + hr = IShellLinkW_QueryInterface(link, &IID_IPropertyStore, &prop_store); + if(SUCCEEDED(hr)) + { + PROPVARIANT pv; + PROPERTYKEY PKEY_Title; + pv.vt=VT_LPSTR; + pv.pszVal=title; /*item text*/ + CLSIDFromString(L"{F29F85E0-4FF9-1068-AB91-08002B27B3D9}", &(PKEY_Title.fmtid)); + PKEY_Title.pid=2; + hr = prop_store->lpVtbl->SetValue(prop_store, &PKEY_Title, &pv); + hr = prop_store->lpVtbl->Commit(prop_store); + prop_store->lpVtbl->Release(prop_store); + } + + appinfo.pszAppID=WIN7_APPNAME; + appinfo.psl=link; + SHAddToRecentDocs(SHARD_APPIDINFOLINK, &appinfo); + IShellLinkW_Release(link); +} +void Win7_Init(void) +{ + HANDLE h; + HRESULT (WINAPI *pSetCurrentProcessExplicitAppUserModelID)(PCWSTR AppID); + + + h = LoadLibrary("shell32.dll"); + if (h) + { + pSetCurrentProcessExplicitAppUserModelID = (void*)GetProcAddress(h, "SetCurrentProcessExplicitAppUserModelID"); + if (pSetCurrentProcessExplicitAppUserModelID) + pSetCurrentProcessExplicitAppUserModelID(WIN7_APPNAME); + } +} + /* #ifdef _MSC_VER #include @@ -1285,6 +1414,8 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin if (hPrevInstance) return 0; + Win7_Init(); + #ifdef _MSC_VER #if _M_IX86_FP >= 1 { @@ -1499,6 +1630,22 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin //client console should now be initialized. + switch(M_GameType()) + { + case MGT_QUAKE1: + Sys_RecentServer("+menu_servers", "", "Server List", "Pick a server to play on"); + Sys_RecentServer("+map start", "", "Start New Game (Quake)", "Begin a new game"); + break; + case MGT_QUAKE2: + Sys_RecentServer("+menu_servers", "", "Server List", "Pick a server to play on"); + Sys_RecentServer("+map unit1", "", "Start New Game (Quake2)", "Begin a new game"); + break; + case MGT_HEXEN2: + Sys_RecentServer("+menu_servers", "", "Server List", "Pick a server to play on"); + Sys_RecentServer("+map demo1", "", "Start New Game (Hexen2)", "Begin a new game"); + break; + } + /* main window message loop */ while (1) { @@ -1529,8 +1676,8 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin SetHookState(sys_disableWinKeys.ival); /*sleep if its not yet time for a frame*/ - if (sleeptime > 0) - Sleep(sleeptime); + //if (sleeptime > 0) + // Sleep(sleeptime); #else Sys_Error("wut?"); #endif diff --git a/engine/common/com_phys_ode.c b/engine/common/com_phys_ode.c index 3bb068d89..3451f3ae0 100644 --- a/engine/common/com_phys_ode.c +++ b/engine/common/com_phys_ode.c @@ -1170,7 +1170,7 @@ void World_Physics_Init(void) # if defined(WIN64) "libode1_64.dll" # elif defined(WIN32) - "libode1.dll" + "ode_double" # elif defined(MACOSX) "libode.1.dylib" # else diff --git a/engine/common/fs.c b/engine/common/fs.c index 6a5e0f8e4..f4a0196a7 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -2222,6 +2222,7 @@ void COM_InitFilesystem (void) char *ev; qboolean usehome; + qboolean autobasedir = true; int gamenum=-1; @@ -2235,7 +2236,10 @@ void COM_InitFilesystem (void) // i = COM_CheckParm ("-basedir"); if (i && i < com_argc-1) + { strcpy (com_quakedir, com_argv[i+1]); + autobasedir = false; + } else strcpy (com_quakedir, host_parms.basedir); @@ -2323,7 +2327,24 @@ void COM_InitFilesystem (void) for (i = 0; gamemode_info[i].argname; i++) { if (!strcmp(gamemode_info[i].argname, "-quake")) + { gamenum = i; + + if (autobasedir) + { + if (Sys_FindGameData(gamemode_info[i].poshname, gamemode_info[i].exename, com_quakedir, sizeof(com_quakedir))) + { + if (com_quakedir[strlen(com_quakedir)-1] == '\\') + com_quakedir[strlen(com_quakedir)-1] = '/'; + else if (com_quakedir[strlen(com_quakedir)-1] != '/') + { + com_quakedir[strlen(com_quakedir)+1] = '\0'; + com_quakedir[strlen(com_quakedir)] = '/'; + } + } + } + break; + } } } diff --git a/engine/common/particles.h b/engine/common/particles.h index 4f2b48625..6e01df125 100644 --- a/engine/common/particles.h +++ b/engine/common/particles.h @@ -95,10 +95,10 @@ struct model_s; struct msurface_s; void P_InitParticleSystem(void); +void P_LoadedModel(struct model_s *mod); /*checks a model's various effects*/ void P_DefaultTrail (struct model_s *model); void P_EmitEffect (vec3_t pos, int type, trailstate_t **tsk);//this is just a wrapper -#define P_ParticleTypeForName pe->ParticleTypeForName #define P_FindParticleType pe->FindParticleType #define P_RunParticleEffectTypeString pe->RunParticleEffectTypeString diff --git a/engine/common/protocol.h b/engine/common/protocol.h index 62b1b6590..908b3eea9 100644 --- a/engine/common/protocol.h +++ b/engine/common/protocol.h @@ -74,6 +74,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifdef VOICECHAT #define PEXT2_VOICECHAT 0x00000002 #endif +#define PEXT2_SETANGLEDELTA 0x00000004 //#define PEXT2_64PLAYERS 0x02000000 //Client is able to cope with 64 players. Wow. //#define PEXT2_PK3DOWNLOADS 0x10000000 //retrieve a list of pk3s/pk3s/paks for downloading (with optional URL and crcs) @@ -272,6 +273,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define svcfte_cgamepacket 83 #define svcfte_voicechat 84 +#define svcfte_setangledelta 85 // [angle3] add this to the current viewangles //fitz svcs @@ -828,6 +830,7 @@ typedef struct q1usercmd_s qbyte impulse; } q1usercmd_t; #define SHORT2ANGLE(x) (x) * (360.0/65536) +#define ANGLE2SHORT(x) (x) * (65536/360.0) diff --git a/engine/common/sys.h b/engine/common/sys.h index f6923b8df..bf3259291 100644 --- a/engine/common/sys.h +++ b/engine/common/sys.h @@ -45,6 +45,7 @@ void VARGS Sys_Printf (char *fmt, ...) LIKEPRINTF(1); // send text to the console void Sys_Quit (void); +void Sys_RecentServer(char *command, char *target, char *title, char *desc); typedef struct { void **funcptr; diff --git a/engine/dotnet2005/ftequake.vcproj b/engine/dotnet2005/ftequake.vcproj index d2071572b..695d53d94 100644 --- a/engine/dotnet2005/ftequake.vcproj +++ b/engine/dotnet2005/ftequake.vcproj @@ -14137,13 +14137,6 @@ Name="VCCLCompilerTool" /> - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -28851,177 +29008,6 @@ /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c index 276687add..869cf14ba 100644 --- a/engine/gl/gl_draw.c +++ b/engine/gl/gl_draw.c @@ -392,8 +392,6 @@ TRACE(("dbg: GLDraw_ReInit: Allocating upload buffers\n")); "}\n" ); - missing_texture = GL_LoadTexture("no_texture", 16, 16, (unsigned char*)r_notexture_mip + r_notexture_mip->offsets[0], IF_NOALPHA|IF_NOGAMMA, 0); - GL_SetupSceneProcessingTextures(); // save a texture slot for translated picture @@ -2228,10 +2226,10 @@ void GL_Upload8 (char *name, qbyte *data, int width, int height, unsigned int fl { for (i=(s&~3)-4 ; i>=0 ; i-=4) { - trans[i] = d_8to24rgbtable[data[i]]; - trans[i+1] = d_8to24rgbtable[data[i+1]]; - trans[i+2] = d_8to24rgbtable[data[i+2]]; - trans[i+3] = d_8to24rgbtable[data[i+3]]; + trans[i] = d_8to24rgbtable[data[i]]|0xff000000; + trans[i+1] = d_8to24rgbtable[data[i+1]]|0xff000000; + trans[i+2] = d_8to24rgbtable[data[i+2]]|0xff000000; + trans[i+3] = d_8to24rgbtable[data[i+3]]|0xff000000; } for (i=s&~3 ; ineedload = false; - P_DefaultTrail(mod); return mod; } #endif @@ -589,7 +588,6 @@ model_t *RMod_LoadModel (model_t *mod, qboolean crash) { mod->needload = false; RMod_LoadDoomSprite(mod); - P_DefaultTrail(mod); return mod; } #endif @@ -738,7 +736,7 @@ model_t *RMod_LoadModel (model_t *mod, qboolean crash) continue; } - P_DefaultTrail(mod); + P_LoadedModel(mod); Validation_IncludeFile(mod->name, (char *)buf, com_filesize); return mod; @@ -760,7 +758,7 @@ couldntload: mod->maxs[2] = 16; mod->needload = true; mod->engineflags = 0; - P_DefaultTrail(mod); + P_LoadedModel(mod); return mod; } @@ -1076,7 +1074,7 @@ TRACE(("dbg: RMod_LoadTextures: inittexturedescs\n")); tx->width = mt->width; tx->height = mt->height; - tx->parttype = P_ParticleTypeForName(va("tex_%s", tx->name)); + tx->parttype = P_INVALID; if (!mt->offsets[0]) //this is a hl external style texture, load it a little later (from a wad) { @@ -3060,8 +3058,6 @@ qboolean RMod_LoadBrushModel (model_t *mod, void *buffer) *loadmodel = *mod; strcpy (loadmodel->name, name); mod = loadmodel; - - P_DefaultTrail(mod); } } #ifdef RUNTIMELIGHTING diff --git a/engine/gl/gl_rmisc.c b/engine/gl/gl_rmisc.c index 4397d9518..9f0e3d256 100644 --- a/engine/gl/gl_rmisc.c +++ b/engine/gl/gl_rmisc.c @@ -971,6 +971,8 @@ TRACE(("dbg: GLR_NewMap: wiping them stains (getting the cloth out)\n")); TRACE(("dbg: GLR_NewMap: building lightmaps\n")); Surf_BuildLightmaps (); + CL_RegisterParticles(); + TRACE(("dbg: GLR_NewMap: ui\n")); #ifdef VM_UI UI_Reset(); diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index a5763c0e4..c983f57bb 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -594,20 +594,12 @@ static void Shader_DeformVertexes ( shader_t *shader, shaderpass_t *pass, char * static void Shader_SkyParms(shader_t *shader, shaderpass_t *pass, char **ptr) { - int i; skydome_t *skydome; float skyheight; char *boxname; if (shader->skydome) { - for (i = 0; i < 5; i++) - { - Z_Free(shader->skydome->meshes[i].xyz_array); - Z_Free(shader->skydome->meshes[i].normals_array); - Z_Free(shader->skydome->meshes[i].st_array); - } - Z_Free(shader->skydome); } @@ -1788,16 +1780,6 @@ void Shader_Free (shader_t *shader) if (shader->skydome) { - for (i = 0; i < 5; i++) - { - if (shader->skydome->meshes[i].xyz_array) - { - Z_Free ( shader->skydome->meshes[i].xyz_array ); - Z_Free ( shader->skydome->meshes[i].normals_array ); - Z_Free ( shader->skydome->meshes[i].st_array ); - } - } - Z_Free (shader->skydome); } @@ -2167,23 +2149,33 @@ void Shader_Finish (shader_t *s) int i; shaderpass_t *pass; - if (s->flags & SHADER_SKY && r_fastsky.ival) + if (s->flags & SHADER_SKY) { - s->flags = 0; - s->numdeforms = 0; - s->numpasses = 0; - s->numprogparams = 0; + /*skies go all black if fastsky is set*/ + if (r_fastsky.ival) + s->flags = 0; + /*or if its purely a skybox and has missing textures*/ + if (!s->numpasses) + for (i = 0; i < 6; i++) + if (missing_texture.num == s->skydome->farbox_textures[i].num) + s->flags = 0; + if (!(s->flags & SHADER_SKY)) + { + Shader_Free(s); + memset(s, 0, sizeof(*s)); - Shader_DefaultScript(s->name, s, - "{\n" + Shader_DefaultScript(s->name, s, "{\n" - "map $whiteimage\n" - "rgbgen const $r_fastskycolour\n" + "sort sky\n" + "{\n" + "map $whiteimage\n" + "rgbgen const $r_fastskycolour\n" + "}\n" + "surfaceparm nodlight\n" "}\n" - "surfaceparm nodlight\n" - "}\n" - ); - return; + ); + return; + } } if (!s->numpasses && !(s->flags & (SHADER_NODRAW|SHADER_SKY)) && !s->fog_dist) @@ -2856,6 +2848,7 @@ void Shader_DefaultBSPQ1(char *shortname, shader_t *s, const void *args) { //q1 sky if (r_fastsky.ival) + { builtin = ( "{\n" "sort sky\n" @@ -2866,7 +2859,9 @@ void Shader_DefaultBSPQ1(char *shortname, shader_t *s, const void *args) "surfaceparm nodlight\n" "}\n" ); + } else if (*r_skyboxname.string) + { builtin = ( "{\n" "sort sky\n" @@ -2874,8 +2869,16 @@ void Shader_DefaultBSPQ1(char *shortname, shader_t *s, const void *args) "surfaceparm nodlight\n" "}\n" ); + Shader_DefaultScript(shortname, s, builtin); + if (s->flags & SHADER_SKY) + return; + builtin = NULL; + /*if the r_skybox failed to load or whatever, reset and fall through and just use the regular sky*/ + Shader_Free(s); + memset (s, 0, sizeof(*s)); + } #ifdef GLQUAKE - else if (qrenderer == QR_OPENGL && gl_config.arb_shader_objects) + if (!builtin && qrenderer == QR_OPENGL && gl_config.arb_shader_objects) builtin = ( "{\n" "sort sky\n" @@ -2934,7 +2937,7 @@ void Shader_DefaultBSPQ1(char *shortname, shader_t *s, const void *args) "}\n" ); #endif - else + if (!builtin) builtin = ( "{\n" "sort sky\n" @@ -3310,11 +3313,11 @@ static int R_LoadShader ( char *name, shader_gen_t *defaultgen, const char *gena if (defaultgen) { memset ( s, 0, sizeof( shader_t ) ); - s->generator = defaultgen; - s->genargs = genargs; + defaultgen(shortname, s, genargs); Com_sprintf ( s->name, MAX_QPATH, shortname ); Hash_Add(&shader_active_hash, s->name, s, &s->bucket); - defaultgen(shortname, s, genargs); + s->generator = defaultgen; + s->genargs = genargs; return f; } @@ -3384,11 +3387,13 @@ void Shader_DoReload(void) { Shader_Free(s); memset ( s, 0, sizeof( shader_t ) ); + + defaultgen(shortname, s, genargs); + s->generator = defaultgen; s->genargs = genargs; Com_sprintf ( s->name, MAX_QPATH, shortname ); Hash_Add(&shader_active_hash, s->name, s, &s->bucket); - s->generator(shortname, s, s->genargs); R_BuildDefaultTexnums(&oldtn, s); } } diff --git a/engine/gl/gl_vidnt.c b/engine/gl/gl_vidnt.c index 9eea8a6ed..6986f0bf0 100644 --- a/engine/gl/gl_vidnt.c +++ b/engine/gl/gl_vidnt.c @@ -816,7 +816,10 @@ void VID_UnSetMode (void) } if (hInstGL) { +#ifndef NPQTV + //FIXME: not cleaning up after myself because nvidia drivers crash the second time around FreeLibrary(hInstGL); +#endif hInstGL = NULL; } } @@ -894,6 +897,7 @@ qboolean VID_AttachGL (rendererstate_t *info) TRACE(("dbg: VID_AttachGL: bSetupPixelFormat\n")); if (bSetupPixelFormat(maindc)) break; + ReleaseDC(mainwindow, maindc); } if (!*info->glrenderer || !stricmp(info->glrenderer, "opengl32.dll") || !stricmp(info->glrenderer, "opengl32")) //go for windows system dir if we failed with the default. Should help to avoid the 3dfx problem. @@ -912,6 +916,7 @@ qboolean VID_AttachGL (rendererstate_t *info) TRACE(("dbg: VID_AttachGL: bSetupPixelFormat\n")); if (bSetupPixelFormat(maindc)) break; + ReleaseDC(mainwindow, maindc); } } @@ -921,14 +926,14 @@ qboolean VID_AttachGL (rendererstate_t *info) TRACE(("dbg: VID_AttachGL: qwglCreateContext\n")); - baseRC = qwglCreateContext( maindc ); + baseRC = qwglCreateContext(maindc); if (!baseRC) { Con_SafePrintf(CON_ERROR "Could not initialize GL (wglCreateContext failed).\n\nMake sure you in are 65535 color mode, and try running -window.\n"); //green to make it show. return false; } TRACE(("dbg: VID_AttachGL: qwglMakeCurrent\n")); - if (!qwglMakeCurrent( maindc, baseRC )) + if (!qwglMakeCurrent(maindc, baseRC)) { Con_SafePrintf(CON_ERROR "wglMakeCurrent failed\n"); //green to make it show. return false; diff --git a/engine/gl/shader.h b/engine/gl/shader.h index 4bbf529d8..f33f26cb8 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -225,8 +225,6 @@ typedef struct shaderpass_s { typedef struct { - mesh_t meshes[5]; - texid_t farbox_textures[6]; texid_t nearbox_textures[6]; } skydome_t; diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 52143fe96..64e3b8f15 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -9058,7 +9058,6 @@ void PF_runclientphys(progfuncs_t *prinst, struct globalvars_s *pr_globals) //set up the movement command msecs = pr_global_struct->input_timelength*1000 + 0.5f; //precision inaccuracies. :( -#define ANGLE2SHORT(x) (x) * (65536/360.0) pmove.cmd.angles[0] = ANGLE2SHORT((pr_global_struct->input_angles)[0]); pmove.cmd.angles[1] = ANGLE2SHORT((pr_global_struct->input_angles)[1]); pmove.cmd.angles[2] = ANGLE2SHORT((pr_global_struct->input_angles)[2]); diff --git a/engine/server/server.h b/engine/server/server.h index 4fe567133..dde94cd45 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -467,9 +467,22 @@ typedef struct client_s int lastsequence_acknoledged; - unsigned int voice_read; +#ifdef VOICECHAT + unsigned int voice_read; /*place in ring*/ unsigned char voice_mute[MAX_CLIENTS/8]; qboolean voice_active; + enum + { + /*note - when recording an mvd, only 'all' will be received by non-spectating viewers. all other chat will only be heard when spectating the receiver(or sender) of said chat*/ + + /*should we add one to respond to the last speaker? or should that be an automagic +voip_reply instead?*/ + VT_TEAM, + VT_ALL, + VT_NONMUTED, /*cheap, but allows custom private channels with no external pesters*/ + VT_PLAYERSLOT0 + /*player0+...*/ + } voice_target; +#endif #ifdef SVCHAT svchat_t chat; diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 791d537d3..fce5f9bd0 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -832,6 +832,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us //this applies to a few other things too, but cheats is the only special one (because of the *) Q_strncpyz(cl.serverinfo, svs.info, sizeof(cl.serverinfo)); CL_CheckServerInfo(); + Cvar_ForceCallback(Cvar_FindVar("r_particlesdesc")); #endif diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 960c92cf4..600762cda 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -3941,6 +3941,7 @@ void SV_InitLocal (void) #ifdef PEXT2_VOICECHAT svs.fteprotocolextensions2 |= PEXT2_VOICECHAT; #endif + svs.fteprotocolextensions2 |= PEXT2_SETANGLEDELTA; // if (svs.protocolextensions) // Info_SetValueForStarKey (svs.info, "*"DISTRIBUTION"_ext", va("%x", svs.protocolextensions), MAX_SERVERINFO_STRING); diff --git a/engine/server/sv_mvd.c b/engine/server/sv_mvd.c index f2e8dc758..f053fdae8 100644 --- a/engine/server/sv_mvd.c +++ b/engine/server/sv_mvd.c @@ -1157,7 +1157,8 @@ qboolean SV_MVDWritePackets (int num) // now write it to buf flags = cl->flags; - if (cl->fixangle) { + if (cl->fixangle) + { demo.fixangletime[i] = cl->cmdtime; } diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index 9020aa9be..1e9d1234d 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -1000,6 +1000,7 @@ void SV_WriteEntityDataToMessage (client_t *client, sizebuf_t *msg, int pnum) edict_t *other; edict_t *ent; int i; + float newa; ent = client->edict; @@ -1026,16 +1027,29 @@ void SV_WriteEntityDataToMessage (client_t *client, sizebuf_t *msg, int pnum) } // a fixangle might get lost in a dropped packet. Oh well. - if ( ent->v->fixangle ) + if (ent->v->fixangle) { if (pnum) { MSG_WriteByte(msg, svcfte_choosesplitclient); MSG_WriteByte(msg, pnum); } - MSG_WriteByte (msg, svc_setangle); - for (i=0 ; i < 3 ; i++) - MSG_WriteAngle (msg, ent->v->angles[i] ); + if (client->fteprotocolextensions2 & PEXT2_SETANGLEDELTA && client->delta_sequence != -1) + { + MSG_WriteByte (msg, svcfte_setangledelta); + for (i=0 ; i < 3 ; i++) + { + newa = ent->v->angles[i] - SHORT2ANGLE(client->lastcmd.angles[i]); + MSG_WriteAngle16 (msg, newa); + client->lastcmd.angles[i] = ANGLE2SHORT(ent->v->angles[i]); + } + } + else + { + MSG_WriteByte (msg, svc_setangle); + for (i=0 ; i < 3 ; i++) + MSG_WriteAngle (msg, ent->v->angles[i]); + } ent->v->fixangle = 0; } } diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 5102ca6af..1eb7c9ed2 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -2094,7 +2094,7 @@ void SV_NextUpload (void) } #ifdef VOICECHAT -#define VOICE_RING_SIZE 512 +#define VOICE_RING_SIZE 512 /*POT*/ struct { struct voice_ring_s @@ -2110,6 +2110,7 @@ struct } voice; void SV_VoiceReadPacket(void) { + unsigned int vt = host_client->voice_target; unsigned int j, cln; struct voice_ring_s *ring; unsigned short bytes; @@ -2135,6 +2136,10 @@ void SV_VoiceReadPacket(void) ring->gen = gen; ring->seq = seq; + /*broadcast it its to their team, and its not teamplay*/ + if (vt == VT_TEAM && !teamplay.ival) + vt = VT_ALL; + /*figure out which team members are meant to receive it*/ for (j = 0; j < MAX_CLIENTS/8; j++) ring->receiver[j] = 0; @@ -2145,11 +2150,12 @@ void SV_VoiceReadPacket(void) if (cl->state != cs_spawned && cl->state != cs_connected) continue; + /*spectators may only talk to spectators*/ if (host_client->spectator && !sv_spectalk.ival) if (!cl->spectator) continue; - if (teamplay.ival) + if (vt == VT_TEAM) { // the spectator team if (host_client->spectator) @@ -2163,6 +2169,16 @@ void SV_VoiceReadPacket(void) continue; // on different teams } } + else if (vt == VT_NONMUTED) + { + if (host_client->voice_mute[j>>3] & (1<<(j&3))) + continue; + } + else if (vt >= VT_PLAYERSLOT0) + { + if (j != vt - VT_PLAYERSLOT0) + continue; + } //make sure we don't send the say to the same client 20 times due to splitscreen if (cl->controller) @@ -2173,10 +2189,10 @@ void SV_VoiceReadPacket(void) ring->receiver[cln>>3] |= 1<<(cln&3); } - if (sv.mvdrecording && sv_voip_record.ival) + if (sv.mvdrecording && sv_voip_record.ival) { // non-team messages should be seen always, even if not tracking any player - if (!teamplay.ival) + if (vt == VT_ALL && (!host_client->spectator || sv_spectalk.ival)) { MVDWrite_Begin (dem_all, 0, ring->datalen+6); } @@ -2200,7 +2216,8 @@ void SV_VoiceReadPacket(void) } void SV_VoiceInitClient(client_t *client) { - client->voice_active = true; + client->voice_target = VT_TEAM; + client->voice_active = false; client->voice_read = voice.write; memset(client->voice_mute, 0, sizeof(client->voice_mute)); } @@ -2235,7 +2252,7 @@ void SV_VoiceSendPacket(client_t *client, sizebuf_t *buf) if (client->voice_mute[ring->sender>>3] & (1<<(ring->sender&3))) send = false; - /*additional ways to block it*/ + /*additional ways to block voice*/ if (client->download) send = false; @@ -2254,11 +2271,68 @@ void SV_VoiceSendPacket(client_t *client, sizebuf_t *buf) } } -void SV_Voice_MuteAll(void) +void SV_Voice_Ignore_f(void) +{ + unsigned int other; + int type = 0; + + if (Cmd_Argc() < 2) + { + /*only a name = toggle*/ + type = 0; + } + else + { + /*mute if 1, unmute if 0*/ + if (atoi(Cmd_Argv(2))) + type = 1; + else + type = -1; + } + other = atoi(Cmd_Argv(1)); + if (other >= MAX_CLIENTS) + return; + + switch(type) + { + case -1: + host_client->voice_mute[other>>3] &= ~(1<<(other&3)); + break; + case 0: + host_client->voice_mute[other>>3] ^= (1<<(other&3)); + break; + case 1: + host_client->voice_mute[other>>3] |= (1<<(other&3)); + } +} +void SV_Voice_Target_f(void) +{ + unsigned int other; + char *t = Cmd_Argv(1); + if (!strcmp(t, "team")) + host_client->voice_target = VT_TEAM; + else if (!strcmp(t, "all")) + host_client->voice_target = VT_ALL; + else if (!strcmp(t, "nonmuted")) + host_client->voice_target = VT_NONMUTED; + else if (*t >= '0' && *t <= '9') + { + other = atoi(t); + if (other >= MAX_CLIENTS) + return; + host_client->voice_target = VT_PLAYERSLOT0 + other; + } + else + { + /*don't know who you mean, futureproofing*/ + host_client->voice_target = VT_TEAM; + } +} +void SV_Voice_MuteAll_f(void) { host_client->voice_active = false; } -void SV_Voice_UnmuteAll(void) +void SV_Voice_UnmuteAll_f(void) { host_client->voice_active = true; } @@ -4142,8 +4216,10 @@ ucmd_t ucmds[] = {"demoinfo", SV_MVDInfo_f}, #ifdef VOICECHAT - {"muteall", SV_Voice_MuteAll}, - {"unmuteall", SV_Voice_UnmuteAll}, + {"voicetarg", SV_Voice_Target_f}, + {"vignore", SV_Voice_Ignore_f}, /*ignore/mute specific player*/ + {"muteall", SV_Voice_MuteAll_f}, /*disables*/ + {"unmuteall", SV_Voice_UnmuteAll_f}, /*reenables*/ #endif {NULL, NULL}