diff --git a/engine/client/cl_cam.c b/engine/client/cl_cam.c index 5932de2b6..f5465ede2 100644 --- a/engine/client/cl_cam.c +++ b/engine/client/cl_cam.c @@ -996,7 +996,7 @@ void Cam_FinishMove(playerview_t *pv, usercmd_t *cmd) int i; player_info_t *s; int end; - extern cvar_t cl_demospeed, cl_splitscreen; + extern cvar_t cl_demospeed; if (cls.state != ca_active) return; diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index 9daf3eb36..5b01cbc7e 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -4755,7 +4755,6 @@ void CLQW_ParsePlayerinfo (void) //add a new splitscreen autotrack view if we can if (cl.splitclients < MAX_SPLITS && !cl.players[num].spectator) { - extern cvar_t cl_splitscreen; if (cl.splitclients < cl_splitscreen.value+1) { for (i = 0; i < cl.splitclients; i++) diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index b63261b9f..eb2105ad4 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -59,7 +59,6 @@ usercmd_t cl_pendingcmd[MAX_SPLITS]; /*kinda a hack...*/ unsigned int con_splitmodifier; cvar_t cl_forceseat = CVARAD("in_forceseat", "0", "in_forcesplitclient", "Overrides the device identifiers to control a specific client from any device. This can be used for debugging mods, where you only have one keyboard/mouse."); -extern cvar_t cl_splitscreen; int CL_TargettedSplit(qboolean nowrap) { int mod; @@ -1723,6 +1722,7 @@ void CL_UpdateSeats(void) } if (!*InfoBuf_ValueForKey(info, "skin")) //give players the same skin by default, because we can. q2 cares for teams. qw might as well (its not like anyone actually uses them thanks to enemy-skin forcing). InfoBuf_SetKey(info, "skin", InfoBuf_ValueForKey(&cls.userinfo[0], "skin")); + InfoBuf_SetKey(info, "chat", ""); #ifdef SVNREVISION if (strcmp(STRINGIFY(SVNREVISION), "-")) @@ -2093,7 +2093,7 @@ static void CL_SendUserinfoUpdate(void) void CL_SendCmd (double frametime, qboolean mainloop) { sizebuf_t buf; - qbyte data[MAX_DATAGRAM]; + qbyte data[MAX_DATAGRAM*16]; int i, plnum; usercmd_t *cmd; float wantfps; @@ -2581,7 +2581,7 @@ CL_InitInput */ void CL_InitInput (void) { - static char pcmd[MAX_SPLITS][3][5]; + static char pcmd[MAX_SPLITS][3][6]; unsigned int sp, i; #define inputnetworkcvargroup "client networking options" cl.splitclients = 1; diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 4d658faf9..fa94083a0 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -1737,6 +1737,9 @@ void CL_RequestNextDownload (void) cl.sendprespawn = false; + if (cl_splitscreen.ival && !(cls.fteprotocolextensions & PEXT_SPLITSCREEN)) + Con_TPrintf(CON_WARNING "Splitscreen requested but not available on this server.\n"); + if (cl.worldmodel && cl.worldmodel->loadstate == MLS_LOADING) COM_WorkerPartialSync(cl.worldmodel, &cl.worldmodel->loadstate, MLS_LOADING); @@ -6777,8 +6780,8 @@ static void CL_ParsePrecache(void) model_t *model; CL_CheckOrEnqueDownloadFile(s, s, 0); model = Mod_ForName(Mod_FixName(s, cl.model_name[1]), (i == 1)?MLV_ERROR:MLV_WARN); - if (!model) - Con_Printf("svc_precache: Mod_ForName(\"%s\") failed\n", s); +// if (!model) +// Con_Printf("svc_precache: Mod_ForName(\"%s\") failed\n", s); cl.model_precache[i] = model; Q_strncpyz (cl.model_name[i], s, sizeof(cl.model_name[i])); @@ -6796,8 +6799,8 @@ static void CL_ParsePrecache(void) if (S_HaveOutput()) CL_CheckOrEnqueDownloadFile(va("sound/%s", s), NULL, 0); sfx = S_PrecacheSound (s); - if (!sfx) - Con_Printf("svc_precache: S_PrecacheSound(\"%s\") failed\n", s); +// if (!sfx) +// Con_Printf("svc_precache: S_PrecacheSound(\"%s\") failed\n", s); cl.sound_precache[i] = sfx; Q_strncpyz (cl.sound_name[i], s, sizeof(cl.sound_name[i])); } @@ -7098,11 +7101,14 @@ void CLQW_ParseServerMessage (void) CLQW_ParseServerData (); break; case svcfte_splitscreenconfig: + j = cl.splitclients; cl.splitclients = MSG_ReadByte(); for (i = 0; i < cl.splitclients && i < MAX_SPLITS; i++) { cl.playerview[i].playernum = MSG_ReadByte(); cl.playerview[i].viewentity = cl.playerview[i].playernum+1; + if (i>=j) //its new. + cl.playerview[i].chatstate = 0; } if (i < cl.splitclients) { diff --git a/engine/client/input.h b/engine/client/input.h index 50bd555fd..9f19242e9 100644 --- a/engine/client/input.h +++ b/engine/client/input.h @@ -66,6 +66,7 @@ void INS_SetupControllerAudioDevices(qboolean enabled); //creates audio devices #define DEVID_UNSET ~0u +extern cvar_t cl_splitscreen; extern cvar_t cl_nodelta; extern cvar_t cl_c2spps; extern cvar_t cl_c2sImpulseBackup; diff --git a/engine/client/m_multi.c b/engine/client/m_multi.c index 8434bb38a..efc87a6ac 100644 --- a/engine/client/m_multi.c +++ b/engine/client/m_multi.c @@ -991,7 +991,6 @@ void M_Menu_Teamplay_Items_Status_Location_Misc_f (void) void M_Menu_Network_f (void) { #if MAX_SPLITS > 1 - extern cvar_t cl_splitscreen; static const char *splitopts[] = { "Disabled", "2 Screens", diff --git a/engine/client/m_single.c b/engine/client/m_single.c index 6a08fc2d8..cddda30a3 100644 --- a/engine/client/m_single.c +++ b/engine/client/m_single.c @@ -316,7 +316,6 @@ void M_Menu_Load_f (void) #endif -extern cvar_t cl_splitscreen; void M_Menu_SinglePlayer_f (void) { emenu_t *menu; diff --git a/engine/client/menu.c b/engine/client/menu.c index 0bace0c60..fc03548dc 100644 --- a/engine/client/menu.c +++ b/engine/client/menu.c @@ -891,9 +891,6 @@ void M_Menu_Keys_f (void) int y; emenu_t *menu; vfsfile_t *bindslist; -#if MAX_SPLITS > 1 - extern cvar_t cl_splitscreen; -#endif menu = M_CreateMenu(0); switch(M_GameType()) diff --git a/engine/common/pmove.c b/engine/common/pmove.c index 9b5a110d6..c2a0ed050 100644 --- a/engine/common/pmove.c +++ b/engine/common/pmove.c @@ -1313,7 +1313,7 @@ static void PM_NudgePosition (void) } } - if (pmove.safeorigin_known) + if (pmove.safeorigin_known && PM_TestPlayerPosition(pmove.safeorigin, false)) VectorCopy (pmove.safeorigin, pmove.origin); else VectorCopy (base, pmove.origin); diff --git a/engine/common/pmove.h b/engine/common/pmove.h index 95eb729af..a9bf87776 100644 --- a/engine/common/pmove.h +++ b/engine/common/pmove.h @@ -58,7 +58,7 @@ typedef struct // player state vec3_t origin; - vec3_t safeorigin; + vec3_t safeorigin; //valid when safeorigin_known. needed for extrasr4's ladders otherwise they bug out. vec3_t angles; vec3_t velocity; vec3_t basevelocity; diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 8d0d949ea..77f76b770 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -18,7 +18,7 @@ static char *cvargroup_progs = "Progs variables"; cvar_t utf8_enable = CVARD("utf8_enable", "0", "When 1, changes the qc builtins to act upon codepoints instead of bytes. Do not use unless com_parseutf8 is also set."); -cvar_t sv_gameplayfix_nolinknonsolid = CVARD("sv_gameplayfix_nolinknonsolid", "1", "When 0, setorigin et al will not link the entity into the collision nodes (which is faster, especially if you have a lot of non-solid entities. When 1, allows entities to freely switch between .solid values (except for SOLID_BSP) without relinking. A lot of DP mods assume a value of 1 and will bug out otherwise, while 0 will restore a bugs present in various mods."); +cvar_t sv_gameplayfix_linknonsolid = CVARD("sv_gameplayfix_nolinknonsolid", "1", "When 0, setorigin et al will not link the entity into the collision nodes (which is faster, especially if you have a lot of non-solid entities. When 1, allows entities to freely switch between .solid values (except for SOLID_BSP) without relinking. A lot of DP mods assume a value of 1 and will bug out otherwise, while 0 will restore a bugs present in various mods."); cvar_t sv_gameplayfix_blowupfallenzombies = CVARD("sv_gameplayfix_blowupfallenzombies", "0", "Allow findradius to find non-solid entities. This may break certain mods. It is better for mods to use FL_FINDABLE_NONSOLID instead."); cvar_t sv_gameplayfix_findradiusdistancetobox = CVARD("sv_gameplayfix_findradiusdistancetobox", "0", "When 1, findradius checks to the nearest part of the entity instead of only its origin, making it find slightly more entities."); cvar_t sv_gameplayfix_droptofloorstartsolid = CVARD("sv_gameplayfix_droptofloorstartsolid", "0", "When droptofloor fails, this causes a second attemp, but with traceline instead."); @@ -86,7 +86,7 @@ void PF_Common_RegisterCvars(void) Cvar_Register (&sv_gameplayfix_blowupfallenzombies, cvargroup_progs); Cvar_Register (&sv_gameplayfix_findradiusdistancetobox, cvargroup_progs); - Cvar_Register (&sv_gameplayfix_nolinknonsolid, cvargroup_progs); + Cvar_Register (&sv_gameplayfix_linknonsolid, cvargroup_progs); Cvar_Register (&sv_gameplayfix_droptofloorstartsolid, cvargroup_progs); Cvar_Register (&dpcompat_findradiusarealinks, cvargroup_progs); #ifdef HAVE_LEGACY diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 9fff66d8d..dd6efe7e8 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -1319,7 +1319,6 @@ MSV_OpenUserDatabase(); #ifndef SERVERONLY /*force coop 1 if splitscreen and not deathmatch*/ { - extern cvar_t cl_splitscreen; if (cl_splitscreen.value && !deathmatch.value && !coop.value) Cvar_Set(&coop, "1"); } diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 11a249b61..11a896a25 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -450,7 +450,7 @@ void SV_FinalMessage (char *message) MSG_WriteByte (&buf, svc_disconnect); for (i=0, cl = svs.clients ; i<svs.allocated_client_slots ; i++, cl++) - if (cl->state >= cs_spawned) + if (cl->state >= cs_spawned && !cl->controlled) if (ISNQCLIENT(cl) || ISQWCLIENT(cl)) Netchan_Transmit (&cl->netchan, buf.cursize , buf.data, 10000); @@ -621,7 +621,8 @@ void SV_DropClient (client_t *drop) #ifndef SERVERONLY if (drop->netchan.remote_address.type == NA_LOOPBACK) { - Netchan_Transmit(&drop->netchan, 0, "", SV_RateForClient(drop)); + if (drop->protocol != SCP_BAD) + Netchan_Transmit(&drop->netchan, 0, "", SV_RateForClient(drop)); #ifdef warningmsg #pragma warningmsg("This means that we may not see the reason we kicked ourselves.") #endif @@ -2378,6 +2379,7 @@ client_t *SV_AddSplit(client_t *controller, char *info, int id) cl->playerclass = 0; cl->pendingdeltabits = NULL; cl->pendingcsqcbits = NULL; + cl->seat = curclients; cl->edict = NULL; #ifdef Q2SERVER diff --git a/engine/server/sv_nchan.c b/engine/server/sv_nchan.c index 18789c401..cb15153bf 100644 --- a/engine/server/sv_nchan.c +++ b/engine/server/sv_nchan.c @@ -104,16 +104,9 @@ sizebuf_t *ClientReliable_StartWrite(client_t *cl, int maxsize) return MVDWrite_Begin(dem_all, 0, maxsize); #endif - if (cl->controller) + if (cl->seat) { - client_t *sp; - int pnum = 0; - for (sp = cl->controller; sp; sp = sp->controlled) - { - if (sp == cl) - break; - pnum++; - } + int pnum = cl->seat; cl = cl->controller; ClientReliableWrite_Begin (cl, svcfte_choosesplitclient, 2+maxsize); ClientReliableWrite_Byte (cl, pnum); diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index d5ad439a4..9e413f2e9 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -1651,8 +1651,7 @@ void SV_SendFixAngle(client_t *client, sizebuf_t *msg, int fixtype, qboolean rol msg = NULL; //try to keep them vaugely reliable, where feasable. if (!msg) msg = ClientReliable_StartWrite(client, 10); - - if (client->seat) + else if (client->seat) { MSG_WriteByte(msg, svcfte_choosesplitclient); MSG_WriteByte(msg, client->seat); diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 7c237ccbe..4f697e8e1 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -4403,7 +4403,7 @@ static void SV_UpdateSeats(client_t *controller) return; //wait for the clientinfo stuff instead. for (curclients = 0, cl = controller; cl; cl = cl->controlled) - curclients++; + cl->seat = curclients++; ClientReliableWrite_Begin(controller, svcfte_splitscreenconfig, 2+curclients); ClientReliableWrite_Byte(controller, curclients); @@ -4412,11 +4412,11 @@ static void SV_UpdateSeats(client_t *controller) ClientReliableWrite_Byte(controller, cl - svs.clients); } - for (curclients = 0, cl = controller; cl; cl = cl->controlled, curclients++) + /*for (curclients = 0, cl = controller; cl; cl = cl->controlled, curclients++) { SV_SendFixAngle(cl, NULL, FIXANGLE_FIXED, false); cl->edict->v->fixangle = FIXANGLE_NO; //no point doing it again - } + }*/ } /* @@ -5375,7 +5375,8 @@ static void Cmd_AddSeat_f(void) if (!num || host_client->joinobservelockeduntil > realtime) return; - host_client->joinobservelockeduntil = realtime + 2; + if (host_client->netchan.remote_address.type != NA_LOOPBACK) + host_client->joinobservelockeduntil = realtime + 2; for (count = 1, prev = host_client, cl = host_client->controlled; cl; cl = cl->controlled) { @@ -8251,6 +8252,9 @@ void SV_ExecuteClientMessage (client_t *cl) case clc_stringcmd: s = MSG_ReadString (); SV_ExecuteUserCommand (s, false); +#ifdef NETPREPARSE + NPP_Flush(); //flush it just in case there was an error and we stopped preparsing. This is only really needed while debugging. +#endif host_client = cl; sv_player = cl->edict; @@ -8819,7 +8823,9 @@ void SVNQ_ExecuteClientMessage (client_t *cl) case clc_stringcmd: s = MSG_ReadString (); SV_ExecuteUserCommand (s, false); - +#ifdef NETPREPARSE + NPP_Flush(); //flush it just in case there was an error and we stopped preparsing. This is only really needed while debugging. +#endif host_client = cl; sv_player = cl->edict; if (cl->state < cs_connected) diff --git a/engine/server/world.c b/engine/server/world.c index 6cdf95ffe..dbc840f28 100644 --- a/engine/server/world.c +++ b/engine/server/world.c @@ -36,7 +36,7 @@ line of sight checks trace->crosscontent, but bullets don't size_t areagridsequence; //used to avoid poking the same ent twice. extern cvar_t sv_compatiblehulls; -extern cvar_t sv_gameplayfix_nolinknonsolid; +extern cvar_t sv_gameplayfix_linknonsolid; typedef struct { @@ -655,7 +655,7 @@ void QDECL World_LinkEdict (world_t *w, wedict_t *ent, qboolean touch_triggers) w->worldmodel->funcs.FindTouchedLeafs(w->worldmodel, &ent->pvsinfo, ent->v->absmin, ent->v->absmax); } - if (ent->v->solid == SOLID_NOT && !sv_gameplayfix_nolinknonsolid.ival) + if (ent->v->solid == SOLID_NOT && !sv_gameplayfix_linknonsolid.ival) return; #ifdef USEAREAGRID