From: vortex Date: Sun, 21 Aug 2011 14:55:40 +0000 (+0000) Subject: 2 new cvars: sv_gameplayfix_unstickentities and sv_gameplayfix_unstickplayers to... X-Git-Tag: xonotic-v0.6.0~163^2~263 X-Git-Url: http://git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=commitdiff_plain;h=d35a3da5c044ae514578d133eced5a9e8ee17bb0 2 new cvars: sv_gameplayfix_unstickentities and sv_gameplayfix_unstickplayers to enable/disable unsticking checks, added a couple of VF_ parms for csqc setview to control fog (so CSQC viewports can have different fog settings). Rearranged fog update (moved all update code from R_UpdateVariables to R_UpdateFog which is called for each viewport render), so can have different fog settings for several viewports. Added back cvar r_transparent_sortmindist. git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@11289 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/cl_screen.c b/cl_screen.c index d5ca01e6..0d891b69 100644 --- a/cl_screen.c +++ b/cl_screen.c @@ -1608,17 +1608,16 @@ static void SCR_DrawTouchscreenOverlay(void) } } -extern void R_UpdateFogColor(void); +extern void R_UpdateFog(void); void R_ClearScreen(qboolean fogcolor) { float clearcolor[4]; // clear to black Vector4Clear(clearcolor); - if (fogcolor) + if (fogcolor && r_fog_clear.integer) { - R_UpdateFogColor(); - if (r_fog_clear.integer) - VectorCopy(r_refdef.fogcolor, clearcolor); + R_UpdateFog(); + VectorCopy(r_refdef.fogcolor, clearcolor); } // clear depth is 1.0 // LordHavoc: we use a stencil centered around 128 instead of 0, diff --git a/clvm_cmds.c b/clvm_cmds.c index d9b8c77d..fd4207c6 100644 --- a/clvm_cmds.c +++ b/clvm_cmds.c @@ -889,6 +889,38 @@ void VM_CL_R_SetView (void) case VF_CLEARSCREEN: PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.isoverlay; break; + case VF_FOG_DENSITY: + PRVM_G_FLOAT(OFS_RETURN) = r_refdef.fog_density; + break; + case VF_FOG_COLOR: + PRVM_G_VECTOR(OFS_RETURN)[0] = r_refdef.fog_red; + PRVM_G_VECTOR(OFS_RETURN)[1] = r_refdef.fog_green; + PRVM_G_VECTOR(OFS_RETURN)[2] = r_refdef.fog_blue; + break; + case VF_FOG_COLOR_R: + PRVM_G_VECTOR(OFS_RETURN)[0] = r_refdef.fog_red; + break; + case VF_FOG_COLOR_G: + PRVM_G_VECTOR(OFS_RETURN)[1] = r_refdef.fog_green; + break; + case VF_FOG_COLOR_B: + PRVM_G_VECTOR(OFS_RETURN)[2] = r_refdef.fog_blue; + break; + case VF_FOG_ALPHA: + PRVM_G_FLOAT(OFS_RETURN) = r_refdef.fog_alpha; + break; + case VF_FOG_START: + PRVM_G_FLOAT(OFS_RETURN) = r_refdef.fog_start; + break; + case VF_FOG_END: + PRVM_G_FLOAT(OFS_RETURN) = r_refdef.fog_end; + break; + case VF_FOG_HEIGHT: + PRVM_G_FLOAT(OFS_RETURN) = r_refdef.fog_height; + break; + case VF_FOG_FADEDEPTH: + PRVM_G_FLOAT(OFS_RETURN) = r_refdef.fog_fadedepth; + break; default: PRVM_G_FLOAT(OFS_RETURN) = 0; VM_Warning("VM_CL_R_GetView : unknown parm %i\n", c); @@ -1004,6 +1036,38 @@ void VM_CL_R_SetView (void) case VF_CLEARSCREEN: r_refdef.view.isoverlay = !k; break; + case VF_FOG_DENSITY: + r_refdef.fog_density = k; + break; + case VF_FOG_COLOR: + r_refdef.fog_red = f[0]; + r_refdef.fog_green = f[1]; + r_refdef.fog_blue = f[2]; + break; + case VF_FOG_COLOR_R: + r_refdef.fog_red = k; + break; + case VF_FOG_COLOR_G: + r_refdef.fog_green = k; + break; + case VF_FOG_COLOR_B: + r_refdef.fog_blue = k; + break; + case VF_FOG_ALPHA: + r_refdef.fog_alpha = k; + break; + case VF_FOG_START: + r_refdef.fog_start = k; + break; + case VF_FOG_END: + r_refdef.fog_end = k; + break; + case VF_FOG_HEIGHT: + r_refdef.fog_height = k; + break; + case VF_FOG_FADEDEPTH: + r_refdef.fog_fadedepth = k; + break; default: PRVM_G_FLOAT(OFS_RETURN) = 0; VM_Warning("VM_CL_R_SetView : unknown parm %i\n", c); @@ -3034,6 +3098,7 @@ void VM_CL_R_RenderScene (void) // we need to update any RENDER_VIEWMODEL entities at this point because // csqc supplies its own view matrix CL_UpdateViewEntities(); + // now draw stuff! R_RenderView(); diff --git a/csprogs.h b/csprogs.h index bb0a3fb8..c82974b2 100644 --- a/csprogs.h +++ b/csprogs.h @@ -41,6 +41,17 @@ #define VF_PERSPECTIVE 200 //(float) #define VF_CLEARSCREEN 201 //(float) +#define VF_FOG_DENSITY 202 //(float) +#define VF_FOG_COLOR 203 //(vector) +#define VF_FOG_COLOR_R 204 //(float) +#define VF_FOG_COLOR_G 205 //(float) +#define VF_FOG_COLOR_B 206 //(float) +#define VF_FOG_ALPHA 207 //(float) +#define VF_FOG_START 208 //(float) +#define VF_FOG_END 209 //(float) +#define VF_FOG_HEIGHT 210 //(float) +#define VF_FOG_FADEDEPTH 211 //(float) + #define RF_VIEWMODEL 1 // The entity is never drawn in mirrors. In engines with realtime lighting, it casts no shadows. #define RF_EXTERNALMODEL 2 // The entity is appears in mirrors but not in the normal view. It does still cast shadows in engines with realtime lighting. #define RF_DEPTHHACK 4 // The entity appears closer to the view than normal, either by scaling it wierdly or by just using a depthrange. This will usually be found in conjunction with RF_VIEWMODEL diff --git a/gl_rmain.c b/gl_rmain.c index 435cefe5..68b0d8f8 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -126,6 +126,7 @@ cvar_t r_fog_exp2 = {0, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rat cvar_t r_fog_clear = {0, "r_fog_clear", "1", "clears renderbuffer with fog color before render starts"}; cvar_t r_drawfog = {CVAR_SAVE, "r_drawfog", "1", "allows one to disable fog rendering"}; cvar_t r_transparentdepthmasking = {CVAR_SAVE, "r_transparentdepthmasking", "0", "enables depth writes on transparent meshes whose materially is normally opaque, this prevents seeing the inside of a transparent mesh"}; +cvar_t r_transparent_sortmindist = {CVAR_SAVE, "r_transparent_sortmindist", "0", "lower distance limit for transparent sorting"}; cvar_t r_transparent_sortmaxdist = {CVAR_SAVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"}; cvar_t r_transparent_sortarraysize = {CVAR_SAVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"}; @@ -4239,6 +4240,7 @@ void GL_Main_Init(void) Cvar_RegisterVariable(&r_fog_clear); Cvar_RegisterVariable(&r_drawfog); Cvar_RegisterVariable(&r_transparentdepthmasking); + Cvar_RegisterVariable(&r_transparent_sortmindist); Cvar_RegisterVariable(&r_transparent_sortmaxdist); Cvar_RegisterVariable(&r_transparent_sortarraysize); Cvar_RegisterVariable(&r_texture_dds_load); @@ -6530,67 +6532,9 @@ static void R_BlendView(void) matrix4x4_t r_waterscrollmatrix; -void R_UpdateFogColor(void) // needs to be called before HDR subrender too, as that changes colorscale! +void R_UpdateFog(void) // needs to be called before HDR subrender too, as that changes colorscale! { - if (r_refdef.fog_density) - { - r_refdef.fogcolor[0] = r_refdef.fog_red; - r_refdef.fogcolor[1] = r_refdef.fog_green; - r_refdef.fogcolor[2] = r_refdef.fog_blue; - - Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height); - r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3]; - r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0; - r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth); - - { - vec3_t fogvec; - VectorCopy(r_refdef.fogcolor, fogvec); - // color.rgb *= ContrastBoost * SceneBrightness; - VectorScale(fogvec, r_refdef.view.colorscale, fogvec); - r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f); - r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f); - r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f); - } - } -} - -void R_UpdateVariables(void) -{ - R_Textures_Frame(); - - r_refdef.scene.ambient = r_ambient.value * (1.0f / 64.0f); - - r_refdef.farclip = r_farclip_base.value; - if (r_refdef.scene.worldmodel) - r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2; - r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f); - - if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1) - Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1); - r_refdef.polygonfactor = 0; - r_refdef.polygonoffset = 0; - r_refdef.shadowpolygonfactor = r_refdef.polygonfactor + r_shadow_polygonfactor.value * (r_shadow_frontsidecasting.integer ? 1 : -1); - r_refdef.shadowpolygonoffset = r_refdef.polygonoffset + r_shadow_polygonoffset.value * (r_shadow_frontsidecasting.integer ? 1 : -1); - - r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0; - r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil; - r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer; - r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil; - r_refdef.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1; - if (FAKELIGHT_ENABLED) - { - r_refdef.lightmapintensity *= r_fakelight_intensity.value; - } - if (r_showsurfaces.integer) - { - r_refdef.scene.rtworld = false; - r_refdef.scene.rtworldshadows = false; - r_refdef.scene.rtdlight = false; - r_refdef.scene.rtdlightshadows = false; - r_refdef.lightmapintensity = 0; - } - + // Nehahra fog if (gamemode == GAME_NEHAHRA) { if (gl_fogenable.integer) @@ -6621,12 +6565,11 @@ void R_UpdateVariables(void) } } + // fog parms r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1); r_refdef.fog_start = max(0, r_refdef.fog_start); r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end); - // R_UpdateFogColor(); // why? R_RenderScene does it anyway - if (r_refdef.fog_density && r_drawfog.integer) { r_refdef.fogenabled = true; @@ -6652,6 +6595,66 @@ void R_UpdateVariables(void) else r_refdef.fogenabled = false; + // fog color + if (r_refdef.fog_density) + { + r_refdef.fogcolor[0] = r_refdef.fog_red; + r_refdef.fogcolor[1] = r_refdef.fog_green; + r_refdef.fogcolor[2] = r_refdef.fog_blue; + + Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height); + r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3]; + r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0; + r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth); + + { + vec3_t fogvec; + VectorCopy(r_refdef.fogcolor, fogvec); + // color.rgb *= ContrastBoost * SceneBrightness; + VectorScale(fogvec, r_refdef.view.colorscale, fogvec); + r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f); + r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f); + r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f); + } + } +} + +void R_UpdateVariables(void) +{ + R_Textures_Frame(); + + r_refdef.scene.ambient = r_ambient.value * (1.0f / 64.0f); + + r_refdef.farclip = r_farclip_base.value; + if (r_refdef.scene.worldmodel) + r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2; + r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f); + + if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1) + Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1); + r_refdef.polygonfactor = 0; + r_refdef.polygonoffset = 0; + r_refdef.shadowpolygonfactor = r_refdef.polygonfactor + r_shadow_polygonfactor.value * (r_shadow_frontsidecasting.integer ? 1 : -1); + r_refdef.shadowpolygonoffset = r_refdef.polygonoffset + r_shadow_polygonoffset.value * (r_shadow_frontsidecasting.integer ? 1 : -1); + + r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0; + r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil; + r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer; + r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil; + r_refdef.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1; + if (FAKELIGHT_ENABLED) + { + r_refdef.lightmapintensity *= r_fakelight_intensity.value; + } + if (r_showsurfaces.integer) + { + r_refdef.scene.rtworld = false; + r_refdef.scene.rtworldshadows = false; + r_refdef.scene.rtdlight = false; + r_refdef.scene.rtdlightshadows = false; + r_refdef.lightmapintensity = 0; + } + switch(vid.renderpath) { case RENDERPATH_GL20: @@ -6899,7 +6902,7 @@ void R_RenderScene(void) r_refdef.stats.renders++; - R_UpdateFogColor(); + R_UpdateFog(); // don't let sound skip if going slow if (r_refdef.scene.extraupdate) diff --git a/meshqueue.c b/meshqueue.c index d21ba627..34334e6d 100644 --- a/meshqueue.c +++ b/meshqueue.c @@ -17,6 +17,7 @@ int trans_sortarraysize; meshqueue_t **trans_hash = NULL; meshqueue_t ***trans_hashpointer = NULL; extern cvar_t r_transparent_sortarraysize; +extern cvar_t r_transparent_sortmindist; extern cvar_t r_transparent_sortmaxdist; float mqt_viewplanedist; @@ -73,8 +74,10 @@ void R_MeshQueue_RenderTransparent(void) // check for bad cvars if (r_transparent_sortarraysize.integer < 1 || r_transparent_sortarraysize.integer > 32768) Cvar_SetValueQuick(&r_transparent_sortarraysize, bound(1, r_transparent_sortarraysize.integer, 32768)); - if (r_transparent_sortmaxdist.integer < 1 || r_transparent_sortmaxdist.integer > 32768) - Cvar_SetValueQuick(&r_transparent_sortmaxdist, bound(1, r_transparent_sortmaxdist.integer, 32768)); + if (r_transparent_sortmindist.integer < 1 || r_transparent_sortmindist.integer >= r_transparent_sortmaxdist.integer) + Cvar_SetValueQuick(&r_transparent_sortmindist, 0); + if (r_transparent_sortmaxdist.integer < r_transparent_sortmindist.integer || r_transparent_sortmaxdist.integer > 32768) + Cvar_SetValueQuick(&r_transparent_sortmaxdist, bound(r_transparent_sortmindist.integer, r_transparent_sortmaxdist.integer, 32768)); // update hash array if (trans_sortarraysize != r_transparent_sortarraysize.integer) @@ -96,7 +99,7 @@ void R_MeshQueue_RenderTransparent(void) maxhashindex = trans_sortarraysize - 1; for (i = 0, mqt = mqt_array; i < mqt_count; i++, mqt++) { - hashindex = bound(0, (int)(min(mqt->dist, r_transparent_sortmaxdist.integer) * distscale), maxhashindex); + hashindex = bound(0, (int)(bound(0, mqt->dist - r_transparent_sortmindist.integer, r_transparent_sortmaxdist.integer) * distscale), maxhashindex); // link to tail of hash chain (to preserve render order) mqt->next = NULL; *trans_hashpointer[hashindex] = mqt; diff --git a/server.h b/server.h index ed552a14..538a6220 100644 --- a/server.h +++ b/server.h @@ -451,6 +451,8 @@ extern cvar_t sv_gameplayfix_swiminbmodels; extern cvar_t sv_gameplayfix_upwardvelocityclearsongroundflag; extern cvar_t sv_gameplayfix_downtracesupportsongroundflag; extern cvar_t sv_gameplayfix_q1bsptracelinereportstexture; +extern cvar_t sv_gameplayfix_unstickplayers; +extern cvar_t sv_gameplayfix_unstickentities; extern cvar_t sv_gravity; extern cvar_t sv_idealpitchscale; extern cvar_t sv_jumpstep; diff --git a/sv_main.c b/sv_main.c index 87187b51..aa7ce320 100644 --- a/sv_main.c +++ b/sv_main.c @@ -121,6 +121,8 @@ cvar_t sv_gameplayfix_swiminbmodels = {0, "sv_gameplayfix_swiminbmodels", "1", " cvar_t sv_gameplayfix_upwardvelocityclearsongroundflag = {0, "sv_gameplayfix_upwardvelocityclearsongroundflag", "1", "prevents monsters, items, and most other objects from being stuck to the floor when pushed around by damage, and other situations in mods"}; cvar_t sv_gameplayfix_downtracesupportsongroundflag = {0, "sv_gameplayfix_downtracesupportsongroundflag", "1", "prevents very short moves from clearing onground (which may make the player stick to the floor at high netfps)"}; cvar_t sv_gameplayfix_q1bsptracelinereportstexture = {0, "sv_gameplayfix_q1bsptracelinereportstexture", "1", "enables mods to get accurate trace_texture results on q1bsp by using a surface-hitting traceline implementation rather than the standard solidbsp method, q3bsp always reports texture accurately"}; +cvar_t sv_gameplayfix_unstickplayers = {0, "sv_gameplayfix_unstickplayers", "1", "big hack to try and fix the rare case of MOVETYPE_WALK entities getting stuck in the world clipping hull."}; +cvar_t sv_gameplayfix_unstickentities = {0, "sv_gameplayfix_unstickentities", "1", "hack to check if entities are crossing world collision hull and try to move them to the right position"}; cvar_t sv_gravity = {CVAR_NOTIFY, "sv_gravity","800", "how fast you fall (512 = roughly earth gravity)"}; cvar_t sv_idealpitchscale = {0, "sv_idealpitchscale","0.8", "how much to look up/down slopes and stairs when not using freelook"}; cvar_t sv_jumpstep = {CVAR_NOTIFY, "sv_jumpstep", "0", "whether you can step up while jumping (sv_gameplayfix_stepwhilejumping must also be 1)"}; @@ -525,6 +527,8 @@ void SV_Init (void) Cvar_RegisterVariable (&sv_gameplayfix_upwardvelocityclearsongroundflag); Cvar_RegisterVariable (&sv_gameplayfix_downtracesupportsongroundflag); Cvar_RegisterVariable (&sv_gameplayfix_q1bsptracelinereportstexture); + Cvar_RegisterVariable (&sv_gameplayfix_unstickplayers); + Cvar_RegisterVariable (&sv_gameplayfix_unstickentities); Cvar_RegisterVariable (&sv_gravity); Cvar_RegisterVariable (&sv_idealpitchscale); Cvar_RegisterVariable (&sv_jumpstep); diff --git a/sv_phys.c b/sv_phys.c index 7b9d705a..629727c6 100644 --- a/sv_phys.c +++ b/sv_phys.c @@ -2264,7 +2264,8 @@ void SV_WalkMove (prvm_edict_t *ent) if (sv.frametime <= 0) return; - SV_CheckStuck (ent); + if (sv_gameplayfix_unstickplayers.integer) + SV_CheckStuck (ent); applygravity = !SV_CheckWater (ent) && PRVM_serveredictfloat(ent, movetype) == MOVETYPE_WALK && ! ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP); @@ -2544,6 +2545,7 @@ SV_Physics_Toss Toss, bounce, and fly movement. When onground, do nothing. ============= */ + void SV_Physics_Toss (prvm_edict_t *ent) { trace_t trace; @@ -2604,7 +2606,8 @@ void SV_Physics_Toss (prvm_edict_t *ent) if (trace.bmodelstartsolid) { // try to unstick the entity - SV_UnstickEntity(ent); + if (sv_gameplayfix_unstickentities.integer) + SV_UnstickEntity(ent); if(!SV_PushEntity (&trace, ent, move, false, true)) return; // teleported if (ent->priv.server->free) diff --git a/svvm_cmds.c b/svvm_cmds.c index 617d1e33..f5d3293b 100644 --- a/svvm_cmds.c +++ b/svvm_cmds.c @@ -1101,6 +1101,7 @@ VM_SV_droptofloor void() droptofloor =============== */ + static void VM_SV_droptofloor (void) { prvm_edict_t *ent; @@ -1128,7 +1129,8 @@ static void VM_SV_droptofloor (void) end[2] -= 256; if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer) - SV_UnstickEntity(ent); + if (sv_gameplayfix_unstickentities.integer) + SV_UnstickEntity(ent); trace = SV_TraceBox(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent)); if (trace.startsolid && sv_gameplayfix_droptofloorstartsolid.integer) @@ -1141,7 +1143,8 @@ static void VM_SV_droptofloor (void) if (trace.startsolid) { Con_DPrintf("droptofloor at %f %f %f - COULD NOT FIX BADLY PLACED ENTITY\n", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]); - SV_UnstickEntity(ent); + if (sv_gameplayfix_unstickentities.integer) + SV_UnstickEntity(ent); SV_LinkEdict(ent); PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND; PRVM_serveredictedict(ent, groundentity) = 0; @@ -1151,7 +1154,8 @@ static void VM_SV_droptofloor (void) { Con_DPrintf("droptofloor at %f %f %f - FIXED BADLY PLACED ENTITY\n", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]); VectorCopy (trace.endpos, PRVM_serveredictvector(ent, origin)); - SV_UnstickEntity(ent); + if (sv_gameplayfix_unstickentities.integer) + SV_UnstickEntity(ent); SV_LinkEdict(ent); PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND; PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);