]> git.xonotic.org Git - xonotic/darkplaces.git/blob - phys.c
physics: fix and refactor unsticking
[xonotic/darkplaces.git] / phys.c
1 // for physics functions shared by the client and server
2
3 #include "phys.h"
4
5 #include "quakedef.h"
6 #include "cl_collision.h"
7
8
9 int PHYS_NudgeOutOfSolid(prvm_prog_t *prog, prvm_edict_t *ent)
10 {
11         int bump, pass;
12         trace_t stucktrace;
13         vec3_t testorigin, targetorigin;
14         vec3_t stuckmins, stuckmaxs;
15         vec_t separation;
16         model_t *worldmodel;
17
18         if (prog == SVVM_prog)
19         {
20                 worldmodel = sv.worldmodel;
21                 separation = sv_gameplayfix_nudgeoutofsolid_separation.value;
22         }
23         else if (prog == CLVM_prog)
24         {
25                 worldmodel = cl.worldmodel;
26                 separation = cl_gameplayfix_nudgeoutofsolid_separation.value;
27         }
28         else
29                 Sys_Error("PHYS_NudgeOutOfSolid: cannot be called from %s VM\n", prog->name);
30
31         VectorCopy(PRVM_serveredictvector(ent, mins), stuckmins);
32         VectorCopy(PRVM_serveredictvector(ent, maxs), stuckmaxs);
33         if (worldmodel && worldmodel->brushq1.numclipnodes)
34                 separation = 0.0f; // when using hulls, it can not be enlarged
35         else
36         {
37                 stuckmins[0] -= separation;
38                 stuckmins[1] -= separation;
39                 stuckmins[2] -= separation;
40                 stuckmaxs[0] += separation;
41                 stuckmaxs[1] += separation;
42                 stuckmaxs[2] += separation;
43         }
44
45         // first pass we try to get it out of brush entities
46         // second pass we try to get it out of world only (can't win them all)
47         for (pass = 0;pass < 2;pass++)
48         {
49                 VectorCopy(PRVM_serveredictvector(ent, origin), testorigin);
50                 for (bump = 0;bump < 10;bump++)
51                 {
52                         if (prog == SVVM_prog) // TODO: can we refactor to use a shared TraceBox or at least a func ptr for these cases?
53                                 stucktrace = SV_TraceBox(testorigin, stuckmins, stuckmaxs, testorigin, pass ? MOVE_WORLDONLY : MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
54                         else
55                                 stucktrace = CL_TraceBox(testorigin, stuckmins, stuckmaxs, testorigin, pass ? MOVE_WORLDONLY : MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value, pass ? false : true, false, NULL, false);
56
57                         // Separation compared here to ensure a good location will be recognised reliably.
58                         if (-stucktrace.startdepth <= separation
59                         || (!stucktrace.bmodelstartsolid && !stucktrace.worldstartsolid)
60                         || (pass && !stucktrace.worldstartsolid))
61                         {
62                                 // found a good location, use it
63                                 VectorCopy(testorigin, PRVM_serveredictvector(ent, origin));
64                                 return bump || pass ? 1 : -1; // -1 means it wasn't stuck
65                         }
66
67                         VectorMA(testorigin, -stucktrace.startdepth, stucktrace.startdepthnormal, targetorigin);
68                         // Trace to targetorigin so we don't set it out of the world in complex cases.
69                         if (prog == SVVM_prog)
70                                 stucktrace = SV_TraceBox(testorigin, stuckmins, stuckmaxs, targetorigin, pass ? MOVE_WORLDONLY : MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
71                         else
72                                 stucktrace = CL_TraceBox(testorigin, stuckmins, stuckmaxs, targetorigin, pass ? MOVE_WORLDONLY : MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value, pass ? false : true, false, NULL, false);
73                         if (stucktrace.fraction)
74                                 VectorCopy(stucktrace.endpos, testorigin);
75                         else
76                                 break; // Can't move it so no point doing more iterations on this pass.
77                 }
78         }
79         return 0;
80 }