cvar_t cl_maxidlefps = {CF_CLIENT | CF_ARCHIVE, "cl_maxidlefps", "20", "maximum fps cap when the game is not the active window (makes cpu time available to other programs"};
cvar_t cl_areagrid_link_SOLID_NOT = {CF_CLIENT, "cl_areagrid_link_SOLID_NOT", "1", "set to 0 to prevent SOLID_NOT entities from being linked to the area grid, and unlink any that are already linked (in the code paths that would otherwise link them), for better performance"};
+cvar_t cl_gameplayfix_nudgeoutofsolid_separation = {CF_CLIENT, "cl_gameplayfix_nudgeoutofsolid_separation", "0.03125", "keep objects this distance apart to prevent collision issues on seams"};
+
client_static_t cls;
client_state_t cl;
Cvar_RegisterVariable (&cl_maxidlefps);
Cvar_RegisterVariable (&cl_areagrid_link_SOLID_NOT);
+ Cvar_RegisterVariable (&cl_gameplayfix_nudgeoutofsolid_separation);
CL_Parse_Init();
CL_Particles_Init();
NULL, // #564
NULL, // #565
VM_CL_findbox, // #566 entity(vector mins, vector maxs) findbox = #566; (DP_QC_FINDBOX)
-NULL, // #567
+VM_nudgeoutofsolid, // #567 float(entity ent) nudgeoutofsolid = #567; (DP_QC_NUDGEOUTOFSOLID)
NULL, // #568
NULL, // #569
NULL, // #570
#define CF_PRIVATE (1<<11) // cvar should not be $ expanded or sent to the server under any circumstances (rcon_password, etc)
#define CF_MAXFLAGSVAL ((1<<12) - 1) // used to determine if flags is valid
// for internal use only!
+#define CF_REGISTERED (1<<29) // created by Cvar_RegisterVariable()
#define CF_DEFAULTSET (1<<30)
-#define CF_ALLOCATED (1<<31)
+#define CF_ALLOCATED (1<<31) // created by Cvar_Get() (console or QC)
#define CF_SHARED 3
typedef struct trace_s
{
// if true, the entire trace was in solid (see hitsupercontentsmask)
- int allsolid;
+ qbool allsolid;
// if true, the initial point was in solid (see hitsupercontentsmask)
- int startsolid;
+ qbool startsolid;
// this is set to true in world.c if startsolid was set in a trace against world
- int worldstartsolid;
+ qbool worldstartsolid;
// this is set to true in world.c if startsolid was set in a trace against a SOLID_BSP entity, in other words this is true if the entity is stuck in a door or wall, but not if stuck in another normal entity
- int bmodelstartsolid;
+ qbool bmodelstartsolid;
// if true, the trace passed through empty somewhere
// (set only by Q1BSP tracing)
- int inopen;
+ qbool inopen;
// if true, the trace passed through water/slime/lava somewhere
// (set only by Q1BSP tracing)
- int inwater;
+ qbool inwater;
// fraction of the total distance that was traveled before impact
// in case of impact this is actually nudged a bit off the surface
// (1.0 = did not hit anything)
const struct texture_s *hittexture;
// initially false, set when the start leaf is found
// (set only by Q1BSP tracing and entity box tracing)
- int startfound;
+ qbool startfound;
// if startsolid, contains the minimum penetration depth found in the
// trace, and the normal needed to push it out of that solid
double startdepth;
return;
}
+ if (!(var->flags & CF_REGISTERED) && !(var->flags & CF_ALLOCATED))
+ {
+ Con_Printf(CON_WARN "Warning: Cvar_SetQuick() cannot set unregistered cvar \"%s\"\n", var->name);
+ return; // setting an unregistered engine cvar crashes
+ }
+
if (developer_extra.integer)
Con_DPrintf("Cvar_SetQuick({\"%s\", \"%s\", %i, \"%s\"}, \"%s\");\n", var->name, var->string, var->flags, var->defstring, value);
cvar_hash_t *hash;
int hashindex;
+ if (cls.state == ca_dedicated && !(variable->flags & CF_SERVER))
+ return;
+
if(!*name)
{
- Con_Printf("Cvar_RegisterVirtual: invalid virtual cvar name\n");
+ Con_Printf(CON_WARN "Cvar_RegisterVirtual: invalid virtual cvar name\n");
return;
}
// check for overlap with a command
if (Cmd_Exists(cmd_local, name))
{
- Con_Printf("Cvar_RegisterVirtual: %s is a command\n", name);
+ Con_Printf(CON_WARN "Cvar_RegisterVirtual: %s is a command\n", name);
return;
}
if(Cvar_FindVar(&cvars_all, name, 0))
{
- Con_Printf("Cvar_RegisterVirtual: %s is a cvar\n", name);
+ Con_Printf(CON_WARN "Cvar_RegisterVirtual: %s is a cvar\n", name);
return;
}
switch (variable->flags & (CF_CLIENT | CF_SERVER))
{
- case CF_CLIENT:
+ case CF_CLIENT: // client-only cvar
+ if (cls.state == ca_dedicated)
+ return;
case CF_SERVER:
case CF_CLIENT | CF_SERVER:
cvars = &cvars_all;
// (because the engine directly accesses fixed variables)
// NOTE: this isn't actually used currently
// (all cvars are registered before config parsing)
- variable->flags |= (cvar->flags & ~CF_ALLOCATED);
+ variable->flags &= ~CF_ALLOCATED;
// cvar->string is now owned by variable instead
variable->string = cvar->string;
variable->defstring = cvar->defstring;
for (i = 0;i < PRVM_PROG_MAX;i++)
variable->globaldefindex[i] = -1;
+ // Safe for Cvar_SetQuick()
+ variable->flags |= CF_REGISTERED;
+
Cvar_Link(variable, cvars);
}
//description:
//Adds a new console command which will take priority over a previous command of the same name (including engine commands) and in CSQC is removed when the VM shuts down. This will call CSQC_ConsoleCommand(string command) or ConsoleCmd(string command) in SVQC. Return value should be true if QC handled the command, otherwise return false to have the engine handle it.
-
//DP_QC_FINDBOX
//idea: Mario
//darkplaces implementation: bones_was_here
//description:
//Returns a chain of entities that are touching a box (a simpler findradius); supports DP_QC_FINDCHAIN_TOFIELD
+//DP_QC_NUDGEOUTOFSOLID
+//idea: LadyHavoc, bones_was_here
+//darkplaces implementation: LadyHavoc, bones_was_here
+//builtin definitions:
+float(entity ent) nudgeoutofsolid = #567;
+//cvar definitions:
+//sv_gameplayfix_nudgeoutofsolid_separation
+//description:
+//Attempts to move a stuck entity out of solid brushes, returning 1 if successful, 0 if it remains stuck, -1 if it wasn't stuck.
+//Note: makes only one tracebox call if the entity isn't stuck, so don't call tracebox just to see if you should call nudgeoutofsolid.
+
+
float(float dividend, float divisor) mod = #245;
// add back the selfpack as new first item
FS_AddSelfPack();
- // set the default screenshot name to either the mod name or the
- // gamemode screenshot name
- if (strcmp(com_modname, gamedirname1))
- Cvar_SetQuick (&scr_screenshot_name, com_modname);
- else
- Cvar_SetQuick (&scr_screenshot_name, gamescreenshotname);
-
+ if (cls.state != ca_dedicated)
+ {
+ // set the default screenshot name to either the mod name or the
+ // gamemode screenshot name
+ if (strcmp(com_modname, gamedirname1))
+ Cvar_SetQuick (&scr_screenshot_name, com_modname);
+ else
+ Cvar_SetQuick (&scr_screenshot_name, gamescreenshotname);
+ }
+
if((i = Sys_CheckParm("-modname")) && i < sys.argc - 1)
strlcpy(com_modname, sys.argv[i+1], sizeof(com_modname));
if (Sys_CheckParm("-nostdout"))
sys_nostdout = 1;
+ // -dedicated is checked in SV_ServerOptions() but that's too late for Cvar_RegisterVariable() to skip all the client-only cvars
+ if (Sys_CheckParm ("-dedicated") || !cl_available)
+ cls.state = ca_dedicated;
+
// initialize console command/cvar/alias/command execution systems
Cmd_Init();
Log_Start();
- // put up the loading image so the user doesn't stare at a black screen...
- SCR_BeginLoadingPlaque(true);
-#ifdef CONFIG_MENU
if (cls.state != ca_dedicated)
+ {
+ // put up the loading image so the user doesn't stare at a black screen...
+ SCR_BeginLoadingPlaque(true);
+#ifdef CONFIG_MENU
MR_Init();
#endif
+ }
+
// check for special benchmark mode
// COMMANDLINEOPTION: Client: -benchmark <demoname> runs a timedemo and quits, results of any timedemo can be found in gamedir/benchmark.log (for example id1/benchmark.log)
i = Sys_CheckParm("-benchmark");
model_sprite.o \
netconn.o \
palette.o \
+ phys.o \
polygon.o \
portals.o \
protocol.o \
//cvar_t r_subdivide_size = {CF_CLIENT | CF_ARCHIVE, "r_subdivide_size", "128", "how large water polygons should be (smaller values produce more polygons which give better warping effects)"};
-cvar_t mod_bsp_portalize = {CF_CLIENT | CF_SERVER, "mod_bsp_portalize", "1", "enables portal generation from BSP tree (may take several seconds per map), used by r_drawportals, r_useportalculling, r_shadow_realtime_world_compileportalculling, sv_cullentities_portal"};
+cvar_t mod_bsp_portalize = {CF_CLIENT, "mod_bsp_portalize", "1", "enables portal generation from BSP tree (may take several seconds per map), used by r_drawportals, r_useportalculling, r_shadow_realtime_dlight_portalculling, r_shadow_realtime_world_compileportalculling"};
cvar_t r_novis = {CF_CLIENT, "r_novis", "0", "draws whole level, see also sv_cullentities_pvs 0"};
cvar_t r_nosurftextures = {CF_CLIENT, "r_nosurftextures", "0", "pretends there was no texture lump found in the q1bsp/hlbsp loading (useful for debugging this rare case)"};
cvar_t r_subdivisions_tolerance = {CF_CLIENT, "r_subdivisions_tolerance", "4", "maximum error tolerance on curve subdivision for rendering purposes (in other words, the curves will be given as many polygons as necessary to represent curves at this quality)"};
// recurse both sides, front side first
ret = Mod_Q1BSP_RecursiveHullCheck(t, node->children[p1side], p1f, midf, p1, mid);
// if this side is not empty, return what it is (solid or done)
- if (ret != HULLCHECKSTATE_EMPTY)
+ if (ret != HULLCHECKSTATE_EMPTY && !t->trace->allsolid)
return ret;
ret = Mod_Q1BSP_RecursiveHullCheck(t, node->children[p2side], midf, p2f, mid, p2);
--- /dev/null
+// for physics functions shared by the client and server
+
+#include "phys.h"
+
+#include "quakedef.h"
+#include "cl_collision.h"
+
+
+int PHYS_NudgeOutOfSolid(prvm_prog_t *prog, prvm_edict_t *ent)
+{
+ int bump, pass;
+ trace_t stucktrace;
+ vec3_t stuckorigin;
+ vec3_t stuckmins, stuckmaxs;
+ vec_t separation;
+ model_t *worldmodel;
+
+ if (prog == SVVM_prog)
+ {
+ worldmodel = sv.worldmodel;
+ separation = sv_gameplayfix_nudgeoutofsolid_separation.value;
+ }
+ else if (prog == CLVM_prog)
+ {
+ worldmodel = cl.worldmodel;
+ separation = cl_gameplayfix_nudgeoutofsolid_separation.value;
+ }
+ else
+ Sys_Error("PHYS_NudgeOutOfSolid: cannot be called from %s VM\n", prog->name);
+
+ VectorCopy(PRVM_serveredictvector(ent, mins), stuckmins);
+ VectorCopy(PRVM_serveredictvector(ent, maxs), stuckmaxs);
+ if (worldmodel && worldmodel->brushq1.numclipnodes)
+ separation = 0.0f; // when using hulls, it can not be enlarged
+ else
+ {
+ stuckmins[0] -= separation;
+ stuckmins[1] -= separation;
+ stuckmins[2] -= separation;
+ stuckmaxs[0] += separation;
+ stuckmaxs[1] += separation;
+ stuckmaxs[2] += separation;
+ }
+
+ // first pass we try to get it out of brush entities
+ // second pass we try to get it out of world only (can't win them all)
+ for (pass = 0;pass < 2;pass++)
+ {
+ VectorCopy(PRVM_serveredictvector(ent, origin), stuckorigin);
+ for (bump = 0;bump < 10;bump++)
+ {
+ if (prog == SVVM_prog) // TODO: can we refactor to use a shared TraceBox or at least a func ptr for these cases?
+ stucktrace = SV_TraceBox(stuckorigin, stuckmins, stuckmaxs, stuckorigin, pass ? MOVE_WORLDONLY : MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
+ else
+ stucktrace = CL_TraceBox(stuckorigin, stuckmins, stuckmaxs, stuckorigin, pass ? MOVE_WORLDONLY : MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value, pass ? false : true, false, NULL, false);
+
+ // Separation compared here to ensure a good location will be recognised reliably.
+ if (-stucktrace.startdepth <= separation
+ || (!stucktrace.bmodelstartsolid && !stucktrace.worldstartsolid)
+ || (pass && !stucktrace.worldstartsolid))
+ {
+ // found a good location, use it
+ VectorCopy(stuckorigin, PRVM_serveredictvector(ent, origin));
+ return bump || pass ? 1 : -1; // -1 means it wasn't stuck
+ }
+
+ VectorMA(stuckorigin, -stucktrace.startdepth, stucktrace.startdepthnormal, stuckorigin);
+ }
+ }
+ return 0;
+}
--- /dev/null
+#ifndef PHYS_H
+#define PHYS_H
+
+#include "quakedef.h"
+
+
+/*! move an entity that is stuck out of the surface it is stuck in (can move large amounts)
+ * returns 1 if it found a better place, 0 if it remains stuck, -1 if it wasn't stuck.
+ */
+int PHYS_NudgeOutOfSolid(prvm_prog_t *prog, prvm_edict_t *ent);
+extern cvar_t cl_gameplayfix_nudgeoutofsolid_separation;
+
+
+#endif // PHYS_H guard
dpvsnprintf(msg,sizeof(msg),fmt,argptr);
va_end(argptr);
- Con_Printf(CON_WARN "%s", msg);
+ Con_Printf(CON_WARN "%s VM warning: %s", prog->name, msg);
// TODO: either add a cvar/cmd to control the state dumping or replace some of the calls with Con_Printf [9/13/2006 Black]
if(prvm_backtraceforwarnings.integer && recursive != host.realtime) // NOTE: this compares to the time, just in case if PRVM_PrintState causes a Host_Error and keeps recursive set
}
}
+// DP_QC_NUDGEOUTOFSOLID
+// float(entity ent) nudgeoutofsolid = #567;
+void VM_nudgeoutofsolid(prvm_prog_t *prog)
+{
+ prvm_edict_t *ent;
+
+ VM_SAFEPARMCOUNTRANGE(1, 1, VM_nudgeoutofsolid);
+
+ ent = PRVM_G_EDICT(OFS_PARM0);
+ if (ent == prog->edicts)
+ {
+ VM_Warning(prog, "nudgeoutofsolid: can not modify world entity\n");
+ PRVM_G_FLOAT(OFS_RETURN) = 0;
+ return;
+ }
+ if (ent->free)
+ {
+ VM_Warning(prog, "nudgeoutofsolid: can not modify free entity\n");
+ PRVM_G_FLOAT(OFS_RETURN) = 0;
+ return;
+ }
+
+ PRVM_G_FLOAT(OFS_RETURN) = PHYS_NudgeOutOfSolid(prog, ent);
+
+ if (PRVM_G_FLOAT(OFS_RETURN) > 0)
+ {
+ if (prog == SVVM_prog)
+ SV_LinkEdict(ent);
+ else if (prog == CLVM_prog)
+ CL_LinkEdict(ent);
+ else
+ Sys_Error("PHYS_NudgeOutOfSolid: cannot be called from %s VM\n", prog->name);
+ }
+}
+
/*
=========
Common functions between menu.dat and clsprogs
void VM_physics_enable(prvm_prog_t *prog);
void VM_physics_addforce(prvm_prog_t *prog);
void VM_physics_addtorque(prvm_prog_t *prog);
+void VM_nudgeoutofsolid(prvm_prog_t *prog);
void VM_coverage(prvm_prog_t *prog);
#include "progs.h"
#include "progsvm.h"
#include "server.h"
+#include "phys.h"
#include "input.h"
#include "keys.h"
* returns true if it found a better place
*/
qbool SV_UnstickEntity (prvm_edict_t *ent);
-/*! move an entity that is stuck out of the surface it is stuck in (can move large amounts)
- * returns true if it found a better place
- */
-qbool SV_NudgeOutOfSolid(prvm_edict_t *ent);
/// calculates hitsupercontentsmask for a generic qc entity
int SV_GenericHitSuperContentsMask(const prvm_edict_t *edict);
i = Sys_CheckParm ("-dedicated");
if (i || !cl_available)
{
- cls.state = ca_dedicated;
// check for -dedicated specifying how many players
if (i && i + 1 < sys.argc && atoi (sys.argv[i+1]) >= 1)
svs.maxclients = atoi (sys.argv[i+1]);
{
advancetime = sys_ticrate.value;
// listen servers can run multiple server frames per client frame
- framelimit = cl_maxphysicsframesperserverframe.integer;
+ if (cl_maxphysicsframesperserverframe.integer > 0)
+ framelimit = cl_maxphysicsframesperserverframe.integer;
aborttime = Sys_DirtyTime() + 0.1;
}
return true;
}
-qbool SV_NudgeOutOfSolid(prvm_edict_t *ent)
-{
- prvm_prog_t *prog = SVVM_prog;
- int bump, pass;
- trace_t stucktrace;
- vec3_t stuckorigin;
- vec3_t stuckmins, stuckmaxs;
- vec_t nudge;
- vec_t separation = sv_gameplayfix_nudgeoutofsolid_separation.value;
- if (sv.worldmodel && sv.worldmodel->brushq1.numclipnodes)
- separation = 0.0f; // when using hulls, it can not be enlarged
- VectorCopy(PRVM_serveredictvector(ent, mins), stuckmins);
- VectorCopy(PRVM_serveredictvector(ent, maxs), stuckmaxs);
- stuckmins[0] -= separation;
- stuckmins[1] -= separation;
- stuckmins[2] -= separation;
- stuckmaxs[0] += separation;
- stuckmaxs[1] += separation;
- stuckmaxs[2] += separation;
- // first pass we try to get it out of brush entities
- // second pass we try to get it out of world only (can't win them all)
- for (pass = 0;pass < 2;pass++)
- {
- VectorCopy(PRVM_serveredictvector(ent, origin), stuckorigin);
- for (bump = 0;bump < 10;bump++)
- {
- stucktrace = SV_TraceBox(stuckorigin, stuckmins, stuckmaxs, stuckorigin, pass ? MOVE_WORLDONLY : MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
- if (!stucktrace.bmodelstartsolid || stucktrace.startdepth >= 0)
- {
- // found a good location, use it
- VectorCopy(stuckorigin, PRVM_serveredictvector(ent, origin));
- return true;
- }
- nudge = -stucktrace.startdepth;
- VectorMA(stuckorigin, nudge, stucktrace.startdepthnormal, stuckorigin);
- }
- }
- return false;
-}
-
/*
============
SV_PushEntity
// move start position out of solids
if (sv_gameplayfix_nudgeoutofsolid.integer && sv_gameplayfix_nudgeoutofsolid_separation.value >= 0)
{
- SV_NudgeOutOfSolid(ent);
+ PHYS_NudgeOutOfSolid(prog, ent);
}
VectorCopy(PRVM_serveredictvector(ent, origin), start);
"DP_QC_ENTITYSTRING",
"DP_QC_ETOS",
"DP_QC_EXTRESPONSEPACKET",
+"DP_QC_FINDBOX",
"DP_QC_FINDCHAIN",
"DP_QC_FINDCHAINFLAGS",
"DP_QC_FINDCHAINFLOAT",
"DP_QC_FINDFLAGS",
"DP_QC_FINDFLOAT",
"DP_QC_FS_SEARCH",
+"DP_QC_FS_SEARCH_PACKFILE",
"DP_QC_GETLIGHT",
"DP_QC_GETSURFACE",
"DP_QC_GETSURFACETRIANGLE",
"DP_QC_LOG",
"DP_QC_MINMAXBOUND",
"DP_QC_MULTIPLETEMPSTRINGS",
+"DP_QC_NUDGEOUTOFSOLID",
"DP_QC_NUM_FOR_EDICT",
"DP_QC_RANDOMVEC",
"DP_QC_SINCOSSQRTPOW",
"TW_SV_STEPCONTROL",
"ZQ_PAUSE",
"DP_RM_CLIPGROUP",
-"DP_QC_FS_SEARCH_PACKFILE",
-"DP_QC_FINDBOX",
NULL
//"EXT_CSQC" // not ready yet
};
void() droptofloor
===============
*/
-
+inline static qbool droptofloor_bsp_failcond(trace_t *trace)
+{
+ if (sv.worldmodel->brush.isq3bsp || sv.worldmodel->brush.isq2bsp)
+ return trace->startsolid;
+ else
+ return trace->allsolid || trace->fraction == 1;
+}
static void VM_SV_droptofloor(prvm_prog_t *prog)
{
- prvm_edict_t *ent;
- vec3_t end, entorigin, entmins, entmaxs;
- trace_t trace;
+ prvm_edict_t *ent;
+ vec3_t end;
+ trace_t trace;
VM_SAFEPARMCOUNTRANGE(0, 2, VM_SV_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype
return;
}
+ if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
+ {
+ int n = PHYS_NudgeOutOfSolid(prog, ent);
+ if (!n)
+ VM_Warning(prog, "droptofloor at \"%f %f %f\": sv_gameplayfix_droptofloorstartsolid_nudgetocorrect COULD NOT FIX badly placed entity \"%s\" before drop\n", PRVM_gameedictvector(ent, origin)[0], PRVM_gameedictvector(ent, origin)[1], PRVM_gameedictvector(ent, origin)[2], PRVM_GetString(prog, PRVM_gameedictstring(ent, classname)));
+ else if (n > 0)
+ VM_Warning(prog, "droptofloor at \"%f %f %f\": sv_gameplayfix_droptofloorstartsolid_nudgetocorrect FIXED badly placed entity \"%s\" before drop\n", PRVM_gameedictvector(ent, origin)[0], PRVM_gameedictvector(ent, origin)[1], PRVM_gameedictvector(ent, origin)[2], PRVM_GetString(prog, PRVM_gameedictstring(ent, classname)));
+ }
+
VectorCopy (PRVM_serveredictvector(ent, origin), end);
if (sv.worldmodel->brush.isq3bsp)
end[2] -= 4096;
else
end[2] -= 256; // Quake, QuakeWorld
- if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
- SV_NudgeOutOfSolid(ent);
-
- VectorCopy(PRVM_serveredictvector(ent, origin), entorigin);
- VectorCopy(PRVM_serveredictvector(ent, mins), entmins);
- VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs);
- trace = SV_TraceBox(entorigin, entmins, entmaxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
- if (trace.startsolid && sv_gameplayfix_droptofloorstartsolid.integer)
- {
- vec3_t offset, org;
- VectorSet(offset, 0.5f * (PRVM_serveredictvector(ent, mins)[0] + PRVM_serveredictvector(ent, maxs)[0]), 0.5f * (PRVM_serveredictvector(ent, mins)[1] + PRVM_serveredictvector(ent, maxs)[1]), PRVM_serveredictvector(ent, mins)[2]);
- VectorAdd(PRVM_serveredictvector(ent, origin), offset, org);
- trace = SV_TraceLine(org, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
- VectorSubtract(trace.endpos, offset, trace.endpos);
- if (trace.startsolid)
+ /* bones_was_here: not using SV_GenericHitSuperContentsMask(ent) anymore because it was setting:
+ * items: SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY
+ * monsters: SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP
+ * explobox: SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_CORPSE
+ * which caused (startsolid == true) when, for example, a health was touching a monster.
+ * Changing MOVE_NORMAL also fixes that, but other engines are using MOVE_NORMAL here.
+ */
+ trace = SV_TraceBox(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID, 0, 0, collision_extendmovelength.value);
+ if (droptofloor_bsp_failcond(&trace))
+ {
+ if (sv_gameplayfix_droptofloorstartsolid.integer)
{
- 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_LinkEdict(ent);
- PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
- PRVM_serveredictedict(ent, groundentity) = 0;
- PRVM_G_FLOAT(OFS_RETURN) = 1;
- }
- else if (trace.fraction < 1)
- {
- 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));
+ vec3_t offset, org;
+
+ offset[0] = 0.5f * (PRVM_serveredictvector(ent, mins)[0] + PRVM_serveredictvector(ent, maxs)[0]);
+ offset[1] = 0.5f * (PRVM_serveredictvector(ent, mins)[1] + PRVM_serveredictvector(ent, maxs)[1]);
+ offset[2] = PRVM_serveredictvector(ent, mins)[2];
+ VectorAdd(PRVM_serveredictvector(ent, origin), offset, org);
+ VectorAdd(end, offset, end);
+
+ trace = SV_TraceLine(org, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID, 0, 0, collision_extendmovelength.value);
+ if (droptofloor_bsp_failcond(&trace))
+ {
+ VM_Warning(prog, "droptofloor at \"%f %f %f\": sv_gameplayfix_droptofloorstartsolid COULD NOT FIX badly placed entity \"%s\"\n", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2], PRVM_GetString(prog, PRVM_gameedictstring(ent, classname)));
+ return;
+ }
+ VM_Warning(prog, "droptofloor at \"%f %f %f\": sv_gameplayfix_droptofloorstartsolid FIXED badly placed entity \"%s\"\n", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2], PRVM_GetString(prog, PRVM_gameedictstring(ent, classname)));
+ VectorSubtract(trace.endpos, offset, PRVM_serveredictvector(ent, origin));
+
+ // only because we dropped it without considering its bbox
if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
- SV_NudgeOutOfSolid(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);
- PRVM_G_FLOAT(OFS_RETURN) = 1;
- // if support is destroyed, keep suspended (gross hack for floating items in various maps)
- ent->priv.server->suspendedinairflag = true;
+ PHYS_NudgeOutOfSolid(prog, ent);
}
- }
- else
- {
- if (!trace.allsolid && trace.fraction < 1)
+ else
{
- VectorCopy (trace.endpos, PRVM_serveredictvector(ent, origin));
- SV_LinkEdict(ent);
- PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
- PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
- PRVM_G_FLOAT(OFS_RETURN) = 1;
- // if support is destroyed, keep suspended (gross hack for floating items in various maps)
- ent->priv.server->suspendedinairflag = true;
+ VM_Warning(prog, "droptofloor at \"%f %f %f\": badly placed entity \"%s\", startsolid: %d allsolid: %d\n", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2], PRVM_GetString(prog, PRVM_gameedictstring(ent, classname)), trace.startsolid, trace.allsolid);
+ return;
}
}
+ else
+ VectorCopy(trace.endpos, PRVM_serveredictvector(ent, origin));
+
+ SV_LinkEdict(ent);
+ PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
+ PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
+ PRVM_G_FLOAT(OFS_RETURN) = 1;
+ // if support is destroyed, keep suspended (gross hack for floating items in various maps)
+ ent->priv.server->suspendedinairflag = true;
}
/*
NULL, // #564
NULL, // #565
VM_SV_findbox, // #566 entity(vector mins, vector maxs) findbox = #566; (DP_QC_FINDBOX)
-NULL, // #567
+VM_nudgeoutofsolid, // #567 float(entity ent) nudgeoutofsolid = #567; (DP_QC_NUDGEOUTOFSOLID)
NULL, // #568
NULL, // #569
NULL, // #570