DarkPlaces
Game engine based on the Quake 1 engine by id Software, developed by LadyHavoc
 
sv_phys.c
Go to the documentation of this file.
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// sv_phys.c
21
22#include "quakedef.h"
23#include "prvm_cmds.h"
24
25/*
26
27
28pushmove objects do not obey gravity, and do not interact with each other or trigger fields, but block normal movement and push normal objects when they move.
29
30onground is set for toss objects when they come to a complete rest. it is set for steping or walking objects
31
32doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
33bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
34corpses are SOLID_NOT and MOVETYPE_TOSS
35crates are SOLID_BBOX and MOVETYPE_TOSS
36walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP
37flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY
38
39solid_edge items only clip against bsp models.
40
41*/
42
43#define MOVE_EPSILON 0.01
44
46
48{
50 if (
52 ?
53 model->type == mod_alias
54 :
55 (
56 (((unsigned char)PRVM_serveredictfloat(ent, pflags)) & PFLAGS_FULLDYNAMIC)
57 ||
58 ((gamemode == GAME_TENEBRAE) && ((unsigned int)PRVM_serveredictfloat(ent, effects) & (16 | 32)))
59 )
60 )
61 return -1;
62 return 1;
63}
64
65/*
66===============================================================================
67
68LINE TESTING IN HULLS
69
70===============================================================================
71*/
72
98
99/*
100==================
101SV_TracePoint
102==================
103*/
104trace_t SV_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
105{
106 prvm_prog_t *prog = SVVM_prog;
107 int i, bodysupercontents;
108 int passedictprog;
109 float pitchsign = 1;
110 prvm_edict_t *traceowner, *touch;
111 trace_t trace;
112 // temporary storage because prvm_vec_t may differ from vec_t
113 vec3_t touchmins, touchmaxs;
114 // bounding box of entire move area
115 vec3_t clipboxmins, clipboxmaxs;
116 // size when clipping against monsters
117 vec3_t clipmins2, clipmaxs2;
118 // start and end origin of move
119 vec3_t clipstart;
120 // trace results
121 trace_t cliptrace;
122 // matrices to transform into/out of other entity's space
123 matrix4x4_t matrix, imatrix;
124 // model of other entity
125 model_t *model;
126 // list of entities to test for collisions
127 int numtouchedicts;
128 static prvm_edict_t *touchedicts[MAX_EDICTS];
129 int clipgroup;
130
131 //return SV_TraceBox(start, vec3_origin, vec3_origin, end, type, passedict, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
132
133 VectorCopy(start, clipstart);
134 VectorClear(clipmins2);
135 VectorClear(clipmaxs2);
136#if COLLISIONPARANOID >= 3
137 Con_Printf("move(%f %f %f)", clipstart[0], clipstart[1], clipstart[2]);
138#endif
139
140 // clip to world
141 Collision_ClipPointToWorld(&cliptrace, sv.worldmodel, clipstart, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
142 cliptrace.worldstartsolid = cliptrace.bmodelstartsolid = cliptrace.startsolid;
143 if (cliptrace.startsolid || cliptrace.fraction < 1)
144 cliptrace.ent = prog->edicts;
145 if (type == MOVE_WORLDONLY)
146 goto finished;
147
148 if (type == MOVE_MISSILE)
149 {
150 // LadyHavoc: modified this, was = -15, now -= 15
151 for (i = 0;i < 3;i++)
152 {
153 clipmins2[i] -= 15;
154 clipmaxs2[i] += 15;
155 }
156 }
157
158 // create the bounding box of the entire move
159 for (i = 0;i < 3;i++)
160 {
161 clipboxmins[i] = min(clipstart[i], cliptrace.endpos[i]) + clipmins2[i] - 1;
162 clipboxmaxs[i] = max(clipstart[i], cliptrace.endpos[i]) + clipmaxs2[i] + 1;
163 }
164
165 // debug override to test against everything
167 {
168 clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = (vec_t)-999999999;
169 clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] = (vec_t)999999999;
170 }
171
172 // if the passedict is world, make it NULL (to avoid two checks each time)
173 if (passedict == prog->edicts)
174 passedict = NULL;
175 // precalculate prog value for passedict for comparisons
176 passedictprog = PRVM_EDICT_TO_PROG(passedict);
177 // precalculate passedict's owner edict pointer for comparisons
178 traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_serveredictedict(passedict, owner)) : 0;
179
180 clipgroup = passedict ? (int)PRVM_serveredictfloat(passedict, clipgroup) : 0;
181
182 // clip to entities
183 // because this uses World_EntitiestoBox, we know all entity boxes overlap
184 // the clip region, so we can skip culling checks in the loop below
185 numtouchedicts = SV_EntitiesInBox(clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts);
186 if (numtouchedicts > MAX_EDICTS)
187 {
188 // this never happens
189 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
190 numtouchedicts = MAX_EDICTS;
191 }
192 for (i = 0;i < numtouchedicts;i++)
193 {
194 touch = touchedicts[i];
195
197 continue;
199 continue;
200
201 if (passedict)
202 {
203 // don't clip against self
204 if (passedict == touch)
205 continue;
206 // don't clip owned entities against owner
207 if (traceowner == touch)
208 continue;
209 // don't clip owner against owned entities
210 if (passedictprog == PRVM_serveredictedict(touch, owner))
211 continue;
212 // don't clip against any entities in the same clipgroup (DP_RM_CLIPGROUP)
213 if (clipgroup && clipgroup == (int)PRVM_serveredictfloat(touch, clipgroup))
214 continue;
215 // don't clip points against points (they can't collide)
217 continue;
218 }
219
221
222 // might interact, so do an exact clip
223 model = NULL;
224 if ((int) PRVM_serveredictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL)
225 {
227 pitchsign = SV_GetPitchSign(prog, touch);
228 }
229 if (model)
231 else
233 Matrix4x4_Invert_Simple(&imatrix, &matrix);
234 VM_GenerateFrameGroupBlend(prog, touch->priv.server->framegroupblend, touch);
235 VM_FrameBlendFromFrameGroupBlend(touch->priv.server->frameblend, touch->priv.server->framegroupblend, model, sv.time);
236 VM_UpdateEdictSkeleton(prog, touch, model, touch->priv.server->frameblend);
237 VectorCopy(PRVM_serveredictvector(touch, mins), touchmins);
238 VectorCopy(PRVM_serveredictvector(touch, maxs), touchmaxs);
239 if (type == MOVE_MISSILE && (int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)
240 Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipstart, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, 0.0f);
241 else
242 Collision_ClipPointToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
243
244 Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_serveredictfloat(touch, solid) == SOLID_BSP);
245 }
246
247finished:
248 return cliptrace;
249}
250
251/*
252==================
253SV_TraceLine
254==================
255*/
256trace_t SV_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float extend)
257{
258 prvm_prog_t *prog = SVVM_prog;
259 int i, bodysupercontents;
260 int passedictprog;
261 float pitchsign = 1;
262 prvm_edict_t *traceowner, *touch;
263 trace_t trace;
264 // temporary storage because prvm_vec_t may differ from vec_t
265 vec3_t touchmins, touchmaxs;
266 // bounding box of entire move area
267 vec3_t clipboxmins, clipboxmaxs;
268 // size when clipping against monsters
269 vec3_t clipmins2, clipmaxs2;
270 // start and end origin of move
271 vec3_t clipstart, clipend;
272 // trace results
273 trace_t cliptrace;
274 // matrices to transform into/out of other entity's space
275 matrix4x4_t matrix, imatrix;
276 // model of other entity
277 model_t *model;
278 // list of entities to test for collisions
279 int numtouchedicts;
280 static prvm_edict_t *touchedicts[MAX_EDICTS];
281 int clipgroup;
282 if (VectorCompare(start, end))
283 return SV_TracePoint(start, type, passedict, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
284
285 //return SV_TraceBox(start, vec3_origin, vec3_origin, end, type, passedict, hitsupercontentsmask);
286
287 VectorCopy(start, clipstart);
288 VectorCopy(end, clipend);
289 VectorClear(clipmins2);
290 VectorClear(clipmaxs2);
291#if COLLISIONPARANOID >= 3
292 Con_Printf("move(%f %f %f,%f %f %f)", clipstart[0], clipstart[1], clipstart[2], clipend[0], clipend[1], clipend[2]);
293#endif
294
295 // clip to world
296 Collision_ClipLineToWorld(&cliptrace, sv.worldmodel, clipstart, clipend, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend, false);
297 cliptrace.worldstartsolid = cliptrace.bmodelstartsolid = cliptrace.startsolid;
298 if (cliptrace.startsolid || cliptrace.fraction < 1)
299 cliptrace.ent = prog->edicts;
300 if (type == MOVE_WORLDONLY)
301 goto finished;
302
303 if (type == MOVE_MISSILE)
304 {
305 // LadyHavoc: modified this, was = -15, now -= 15
306 for (i = 0;i < 3;i++)
307 {
308 clipmins2[i] -= 15;
309 clipmaxs2[i] += 15;
310 }
311 }
312
313 // create the bounding box of the entire move
314 for (i = 0;i < 3;i++)
315 {
316 clipboxmins[i] = min(clipstart[i], cliptrace.endpos[i]) + clipmins2[i] - 1;
317 clipboxmaxs[i] = max(clipstart[i], cliptrace.endpos[i]) + clipmaxs2[i] + 1;
318 }
319
320 // debug override to test against everything
322 {
323 clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = (vec_t)-999999999;
324 clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] = (vec_t)999999999;
325 }
326
327 // if the passedict is world, make it NULL (to avoid two checks each time)
328 if (passedict == prog->edicts)
329 passedict = NULL;
330 // precalculate prog value for passedict for comparisons
331 passedictprog = PRVM_EDICT_TO_PROG(passedict);
332 // precalculate passedict's owner edict pointer for comparisons
333 traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_serveredictedict(passedict, owner)) : 0;
334
335 clipgroup = passedict ? (int)PRVM_serveredictfloat(passedict, clipgroup) : 0;
336
337 // clip to entities
338 // because this uses World_EntitiestoBox, we know all entity boxes overlap
339 // the clip region, so we can skip culling checks in the loop below
340 numtouchedicts = SV_EntitiesInBox(clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts);
341 if (numtouchedicts > MAX_EDICTS)
342 {
343 // this never happens
344 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
345 numtouchedicts = MAX_EDICTS;
346 }
347 for (i = 0;i < numtouchedicts;i++)
348 {
349 touch = touchedicts[i];
350
352 continue;
354 continue;
355
356 if (passedict)
357 {
358 // don't clip against self
359 if (passedict == touch)
360 continue;
361 // don't clip owned entities against owner
362 if (traceowner == touch)
363 continue;
364 // don't clip owner against owned entities
365 if (passedictprog == PRVM_serveredictedict(touch, owner))
366 continue;
367 // don't clip against any entities in the same clipgroup (DP_RM_CLIPGROUP)
368 if (clipgroup && clipgroup == (int)PRVM_serveredictfloat(touch, clipgroup))
369 continue;
370 // don't clip points against points (they can't collide)
372 continue;
373 }
374
376
377 // might interact, so do an exact clip
378 model = NULL;
379 if ((int) PRVM_serveredictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL)
380 {
382 pitchsign = SV_GetPitchSign(prog, touch);
383 }
384 if (model)
386 else
388 Matrix4x4_Invert_Simple(&imatrix, &matrix);
389 VM_GenerateFrameGroupBlend(prog, touch->priv.server->framegroupblend, touch);
390 VM_FrameBlendFromFrameGroupBlend(touch->priv.server->frameblend, touch->priv.server->framegroupblend, model, sv.time);
391 VM_UpdateEdictSkeleton(prog, touch, model, touch->priv.server->frameblend);
392 VectorCopy(PRVM_serveredictvector(touch, mins), touchmins);
393 VectorCopy(PRVM_serveredictvector(touch, maxs), touchmaxs);
394 if (type == MOVE_MISSILE && (int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)
395 Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend);
396 else
397 Collision_ClipLineToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipend, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend, false);
398
399 Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_serveredictfloat(touch, solid) == SOLID_BSP);
400 }
401
402finished:
403 return cliptrace;
404}
405
406/*
407==================
408SV_Move
409==================
410*/
411#if COLLISIONPARANOID >= 1
412static trace_t SV_TraceBox_(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float extend)
413#else
414trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float extend)
415#endif
416{
417 prvm_prog_t *prog = SVVM_prog;
418 vec3_t hullmins, hullmaxs;
419 int i, bodysupercontents;
420 int passedictprog;
421 float pitchsign = 1;
422 qbool pointtrace;
423 prvm_edict_t *traceowner, *touch;
424 trace_t trace;
425 // temporary storage because prvm_vec_t may differ from vec_t
426 vec3_t touchmins, touchmaxs;
427 // bounding box of entire move area
428 vec3_t clipboxmins, clipboxmaxs;
429 // size of the moving object
430 vec3_t clipmins, clipmaxs;
431 // size when clipping against monsters
432 vec3_t clipmins2, clipmaxs2;
433 // start and end origin of move
434 vec3_t clipstart, clipend;
435 // trace results
436 trace_t cliptrace;
437 // matrices to transform into/out of other entity's space
438 matrix4x4_t matrix, imatrix;
439 // model of other entity
440 model_t *model;
441 // list of entities to test for collisions
442 int numtouchedicts;
443 static prvm_edict_t *touchedicts[MAX_EDICTS];
444 int clipgroup;
445 if (VectorCompare(mins, maxs))
446 {
447 vec3_t shiftstart, shiftend;
448 VectorAdd(start, mins, shiftstart);
449 VectorAdd(end, mins, shiftend);
450 if (VectorCompare(start, end))
451 trace = SV_TracePoint(shiftstart, type, passedict, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
452 else
453 trace = SV_TraceLine(shiftstart, shiftend, type, passedict, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend);
454 VectorSubtract(trace.endpos, mins, trace.endpos);
455 return trace;
456 }
457
458 VectorCopy(start, clipstart);
459 VectorCopy(end, clipend);
460 VectorCopy(mins, clipmins);
461 VectorCopy(maxs, clipmaxs);
462 VectorCopy(mins, clipmins2);
463 VectorCopy(maxs, clipmaxs2);
464#if COLLISIONPARANOID >= 3
465 Con_Printf("move(%f %f %f,%f %f %f)", clipstart[0], clipstart[1], clipstart[2], clipend[0], clipend[1], clipend[2]);
466#endif
467
468 // clip to world
469 Collision_ClipToWorld(&cliptrace, sv.worldmodel, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend);
470 cliptrace.worldstartsolid = cliptrace.bmodelstartsolid = cliptrace.startsolid;
471 if (cliptrace.startsolid || cliptrace.fraction < 1)
472 cliptrace.ent = prog->edicts;
473 if (type == MOVE_WORLDONLY)
474 goto finished;
475
476 if (type == MOVE_MISSILE)
477 {
478 // LadyHavoc: modified this, was = -15, now -= 15
479 for (i = 0;i < 3;i++)
480 {
481 clipmins2[i] -= 15;
482 clipmaxs2[i] += 15;
483 }
484 }
485
486 // get adjusted box for bmodel collisions if the world is q1bsp or hlbsp
487 if (sv.worldmodel && sv.worldmodel->brush.RoundUpToHullSize)
488 sv.worldmodel->brush.RoundUpToHullSize(sv.worldmodel, clipmins, clipmaxs, hullmins, hullmaxs);
489 else
490 {
491 VectorCopy(clipmins, hullmins);
492 VectorCopy(clipmaxs, hullmaxs);
493 }
494
495 // create the bounding box of the entire move
496 for (i = 0;i < 3;i++)
497 {
498 clipboxmins[i] = min(clipstart[i], cliptrace.endpos[i]) + min(hullmins[i], clipmins2[i]) - 1;
499 clipboxmaxs[i] = max(clipstart[i], cliptrace.endpos[i]) + max(hullmaxs[i], clipmaxs2[i]) + 1;
500 }
501
502 // debug override to test against everything
504 {
505 clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = (vec_t)-999999999;
506 clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] = (vec_t)999999999;
507 }
508
509 // if the passedict is world, make it NULL (to avoid two checks each time)
510 if (passedict == prog->edicts)
511 passedict = NULL;
512 // precalculate prog value for passedict for comparisons
513 passedictprog = PRVM_EDICT_TO_PROG(passedict);
514 // figure out whether this is a point trace for comparisons
515 pointtrace = VectorCompare(clipmins, clipmaxs);
516 // precalculate passedict's owner edict pointer for comparisons
517 traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_serveredictedict(passedict, owner)) : 0;
518
519 clipgroup = passedict ? (int)PRVM_serveredictfloat(passedict, clipgroup) : 0;
520
521 // clip to entities
522 // because this uses World_EntitiestoBox, we know all entity boxes overlap
523 // the clip region, so we can skip culling checks in the loop below
524 numtouchedicts = SV_EntitiesInBox(clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts);
525 if (numtouchedicts > MAX_EDICTS)
526 {
527 // this never happens
528 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
529 numtouchedicts = MAX_EDICTS;
530 }
531 for (i = 0;i < numtouchedicts;i++)
532 {
533 touch = touchedicts[i];
534
536 continue;
538 continue;
539
540 if (passedict)
541 {
542 // don't clip against self
543 if (passedict == touch)
544 continue;
545 // don't clip owned entities against owner
546 if (traceowner == touch)
547 continue;
548 // don't clip owner against owned entities
549 if (passedictprog == PRVM_serveredictedict(touch, owner))
550 continue;
551 // don't clip against any entities in the same clipgroup (DP_RM_CLIPGROUP)
552 if (clipgroup && clipgroup == (int)PRVM_serveredictfloat(touch, clipgroup))
553 continue;
554 // don't clip points against points (they can't collide)
555 if (pointtrace && VectorCompare(PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)))
556 continue;
557 }
558
560
561 // might interact, so do an exact clip
562 model = NULL;
563 if ((int) PRVM_serveredictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL)
564 {
566 pitchsign = SV_GetPitchSign(prog, touch);
567 }
568 if (model)
570 else
572 Matrix4x4_Invert_Simple(&imatrix, &matrix);
573 VM_GenerateFrameGroupBlend(prog, touch->priv.server->framegroupblend, touch);
574 VM_FrameBlendFromFrameGroupBlend(touch->priv.server->frameblend, touch->priv.server->framegroupblend, model, sv.time);
575 VM_UpdateEdictSkeleton(prog, touch, model, touch->priv.server->frameblend);
576 VectorCopy(PRVM_serveredictvector(touch, mins), touchmins);
577 VectorCopy(PRVM_serveredictvector(touch, maxs), touchmaxs);
578 if (type == MOVE_MISSILE && (int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)
579 Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend);
580 else
581 Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend);
582
583 Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_serveredictfloat(touch, solid) == SOLID_BSP);
584 }
585
586finished:
587 return cliptrace;
588}
589
590#if COLLISIONPARANOID >= 1
591trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float extend)
592{
593 prvm_prog_t *prog = SVVM_prog;
594 int endstuck;
595 trace_t trace;
596 vec3_t temp;
597 trace = SV_TraceBox_(start, mins, maxs, end, type, passedict, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend);
598 if (passedict)
599 {
600 VectorCopy(trace.endpos, temp);
601 endstuck = SV_TraceBox_(temp, mins, maxs, temp, type, passedict, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend).startsolid;
602#if COLLISIONPARANOID < 3
603 if (trace.startsolid || endstuck)
604#endif
605 Con_Printf("%s{e%i:%f %f %f:%f %f %f:%f:%f %f %f%s%s}\n", (trace.startsolid || endstuck) ? "^3" : "", passedict ? (int)(passedict - prog->edicts) : -1, PRVM_serveredictvector(passedict, origin)[0], PRVM_serveredictvector(passedict, origin)[1], PRVM_serveredictvector(passedict, origin)[2], end[0] - PRVM_serveredictvector(passedict, origin)[0], end[1] - PRVM_serveredictvector(passedict, origin)[1], end[2] - PRVM_serveredictvector(passedict, origin)[2], trace.fraction, trace.endpos[0] - PRVM_serveredictvector(passedict, origin)[0], trace.endpos[1] - PRVM_serveredictvector(passedict, origin)[1], trace.endpos[2] - PRVM_serveredictvector(passedict, origin)[2], trace.startsolid ? " startstuck" : "", endstuck ? " endstuck" : "");
606 }
607 return trace;
608}
609#endif
610
612{
613 prvm_prog_t *prog = SVVM_prog;
614 int supercontents = 0;
615 int i;
616 prvm_edict_t *touch;
617 vec3_t transformed;
618 // matrices to transform into/out of other entity's space
619 matrix4x4_t matrix, imatrix;
620 // model of other entity
621 model_t *model;
622 int frame;
623 // list of entities to test for collisions
624 int numtouchedicts;
625 static prvm_edict_t *touchedicts[MAX_EDICTS];
626
627 // get world supercontents at this point
628 if (sv.worldmodel && sv.worldmodel->PointSuperContents)
629 supercontents = sv.worldmodel->PointSuperContents(sv.worldmodel, 0, point);
630
631 // if sv_gameplayfix_swiminbmodels is off we're done
633 return supercontents;
634
635 // get list of entities at this point
636 numtouchedicts = SV_EntitiesInBox(point, point, MAX_EDICTS, touchedicts);
637 if (numtouchedicts > MAX_EDICTS)
638 {
639 // this never happens
640 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
641 numtouchedicts = MAX_EDICTS;
642 }
643 for (i = 0;i < numtouchedicts;i++)
644 {
645 touch = touchedicts[i];
646
647 // we only care about SOLID_BSP for pointcontents
649 continue;
650
651 // might interact, so do an exact clip
653 if (!model || !model->PointSuperContents)
654 continue;
656 Matrix4x4_Invert_Simple(&imatrix, &matrix);
657 Matrix4x4_Transform(&imatrix, point, transformed);
659 supercontents |= model->PointSuperContents(model, bound(0, frame, (model->numframes - 1)), transformed);
660 }
661
662 return supercontents;
663}
664
665/*
666===============================================================================
667
668Linking entities into the world culling system
669
670===============================================================================
671*/
672
673int SV_EntitiesInBox(const vec3_t mins, const vec3_t maxs, int maxedicts, prvm_edict_t **resultedicts)
674{
675 prvm_prog_t *prog = SVVM_prog;
676 vec3_t paddedmins, paddedmaxs;
677 if (maxedicts < 1 || resultedicts == NULL)
678 return 0;
679 // LadyHavoc: discovered this actually causes its own bugs (dm6 teleporters being too close to info_teleport_destination)
680 //VectorSet(paddedmins, mins[0] - 10, mins[1] - 10, mins[2] - 1);
681 //VectorSet(paddedmaxs, maxs[0] + 10, maxs[1] + 10, maxs[2] + 1);
682 VectorCopy(mins, paddedmins);
683 VectorCopy(maxs, paddedmaxs);
685 {
686 int numresultedicts = 0;
687 int edictindex;
688 prvm_edict_t *ed;
689 for (edictindex = 1;edictindex < prog->num_edicts;edictindex++)
690 {
691 ed = PRVM_EDICT_NUM(edictindex);
692 if (!ed->free && BoxesOverlap(PRVM_serveredictvector(ed, absmin), PRVM_serveredictvector(ed, absmax), paddedmins, paddedmaxs))
693 {
694 resultedicts[numresultedicts++] = ed;
695 if (numresultedicts == maxedicts)
696 break;
697 }
698 }
699 return numresultedicts;
700 }
701 else
702 return World_EntitiesInBox(&sv.world, paddedmins, paddedmaxs, maxedicts, resultedicts);
703}
704
726
728{
729 prvm_prog_t *prog = SVVM_prog;
730 int i, numtouchedicts, old_self, old_other;
731 prvm_edict_t *touch;
732 static prvm_edict_t *touchedicts[MAX_EDICTS];
733
734 if (ent == prog->edicts)
735 return; // don't add the world
736
737 if (ent->free)
738 return;
739
741 return;
742
743 // build a list of edicts to touch, because the link loop can be corrupted
744 // by IncreaseEdicts called during touch functions
745 numtouchedicts = SV_EntitiesInBox(ent->priv.server->areamins, ent->priv.server->areamaxs, MAX_EDICTS, touchedicts);
746 if (numtouchedicts > MAX_EDICTS)
747 {
748 // this never happens
749 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
750 numtouchedicts = MAX_EDICTS;
751 }
752
753 old_self = PRVM_serverglobaledict(self);
754 old_other = PRVM_serverglobaledict(other);
755 for (i = 0;i < numtouchedicts;i++)
756 {
757 touch = touchedicts[i];
758 if (touch != ent && (int)PRVM_serveredictfloat(touch, solid) == SOLID_TRIGGER && PRVM_serveredictfunction(touch, touch))
759 {
761 }
762 }
763 PRVM_serverglobaledict(self) = old_self;
764 PRVM_serverglobaledict(other) = old_other;
765}
766
767static void RotateBBox(const vec3_t mins, const vec3_t maxs, const vec3_t angles, vec3_t rotatedmins, vec3_t rotatedmaxs)
768{
769 vec3_t v, u;
770 matrix4x4_t m;
772
773 v[0] = mins[0]; v[1] = mins[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
774 VectorCopy(u, rotatedmins); VectorCopy(u, rotatedmaxs);
775 v[0] = maxs[0]; v[1] = mins[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
776 if(rotatedmins[0] > u[0]) { rotatedmins[0] = u[0]; } if(rotatedmins[1] > u[1]) { rotatedmins[1] = u[1]; } if(rotatedmins[2] > u[2]) { rotatedmins[2] = u[2]; }
777 if(rotatedmaxs[0] < u[0]) { rotatedmaxs[0] = u[0]; } if(rotatedmaxs[1] < u[1]) { rotatedmaxs[1] = u[1]; } if(rotatedmaxs[2] < u[2]) { rotatedmaxs[2] = u[2]; }
778 v[0] = mins[0]; v[1] = maxs[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
779 if(rotatedmins[0] > u[0]) { rotatedmins[0] = u[0]; } if(rotatedmins[1] > u[1]) { rotatedmins[1] = u[1]; } if(rotatedmins[2] > u[2]) { rotatedmins[2] = u[2]; }
780 if(rotatedmaxs[0] < u[0]) { rotatedmaxs[0] = u[0]; } if(rotatedmaxs[1] < u[1]) { rotatedmaxs[1] = u[1]; } if(rotatedmaxs[2] < u[2]) { rotatedmaxs[2] = u[2]; }
781 v[0] = maxs[0]; v[1] = maxs[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
782 if(rotatedmins[0] > u[0]) { rotatedmins[0] = u[0]; } if(rotatedmins[1] > u[1]) { rotatedmins[1] = u[1]; } if(rotatedmins[2] > u[2]) { rotatedmins[2] = u[2]; }
783 if(rotatedmaxs[0] < u[0]) { rotatedmaxs[0] = u[0]; } if(rotatedmaxs[1] < u[1]) { rotatedmaxs[1] = u[1]; } if(rotatedmaxs[2] < u[2]) { rotatedmaxs[2] = u[2]; }
784 v[0] = mins[0]; v[1] = mins[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
785 if(rotatedmins[0] > u[0]) { rotatedmins[0] = u[0]; } if(rotatedmins[1] > u[1]) { rotatedmins[1] = u[1]; } if(rotatedmins[2] > u[2]) { rotatedmins[2] = u[2]; }
786 if(rotatedmaxs[0] < u[0]) { rotatedmaxs[0] = u[0]; } if(rotatedmaxs[1] < u[1]) { rotatedmaxs[1] = u[1]; } if(rotatedmaxs[2] < u[2]) { rotatedmaxs[2] = u[2]; }
787 v[0] = maxs[0]; v[1] = mins[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
788 if(rotatedmins[0] > u[0]) { rotatedmins[0] = u[0]; } if(rotatedmins[1] > u[1]) { rotatedmins[1] = u[1]; } if(rotatedmins[2] > u[2]) { rotatedmins[2] = u[2]; }
789 if(rotatedmaxs[0] < u[0]) { rotatedmaxs[0] = u[0]; } if(rotatedmaxs[1] < u[1]) { rotatedmaxs[1] = u[1]; } if(rotatedmaxs[2] < u[2]) { rotatedmaxs[2] = u[2]; }
790 v[0] = mins[0]; v[1] = maxs[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
791 if(rotatedmins[0] > u[0]) { rotatedmins[0] = u[0]; } if(rotatedmins[1] > u[1]) { rotatedmins[1] = u[1]; } if(rotatedmins[2] > u[2]) { rotatedmins[2] = u[2]; }
792 if(rotatedmaxs[0] < u[0]) { rotatedmaxs[0] = u[0]; } if(rotatedmaxs[1] < u[1]) { rotatedmaxs[1] = u[1]; } if(rotatedmaxs[2] < u[2]) { rotatedmaxs[2] = u[2]; }
793 v[0] = maxs[0]; v[1] = maxs[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
794 if(rotatedmins[0] > u[0]) { rotatedmins[0] = u[0]; } if(rotatedmins[1] > u[1]) { rotatedmins[1] = u[1]; } if(rotatedmins[2] > u[2]) { rotatedmins[2] = u[2]; }
795 if(rotatedmaxs[0] < u[0]) { rotatedmaxs[0] = u[0]; } if(rotatedmaxs[1] < u[1]) { rotatedmaxs[1] = u[1]; } if(rotatedmaxs[2] < u[2]) { rotatedmaxs[2] = u[2]; }
796}
797
798/*
799===============
800SV_LinkEdict
801
802===============
803*/
805{
806 prvm_prog_t *prog = SVVM_prog;
807 model_t *model;
808 vec3_t mins, maxs, entmins, entmaxs, entangles;
809 int modelindex;
810
811 if (ent == prog->edicts)
812 return; // don't add the world
813
814 if (ent->free)
815 return;
816
819 {
820 Con_Printf("edict %i: SOLID_BSP with invalid modelindex!\n", PRVM_NUM_FOR_EDICT(ent));
821 modelindex = 0;
822 }
824
825 VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent);
826 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model, sv.time);
827 VM_UpdateEdictSkeleton(prog, ent, model, ent->priv.server->frameblend);
828
829// set the abs box
830
832 {
833 // TODO maybe should do this for rotating SOLID_BSP too? Would behave better with rotating doors
834 // TODO special handling for spheres?
835 VectorCopy(PRVM_serveredictvector(ent, mins), entmins);
836 VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs);
837 VectorCopy(PRVM_serveredictvector(ent, angles), entangles);
838 RotateBBox(entmins, entmaxs, entangles, mins, maxs);
841 }
842 else if (PRVM_serveredictfloat(ent, solid) == SOLID_BSP)
843 {
844 if (model != NULL)
845 {
846 if (!model->TraceBox)
847 Con_DPrintf("edict %i: SOLID_BSP with non-collidable model\n", PRVM_NUM_FOR_EDICT(ent));
848
850 {
851 VectorAdd(PRVM_serveredictvector(ent, origin), model->rotatedmins, mins);
852 VectorAdd(PRVM_serveredictvector(ent, origin), model->rotatedmaxs, maxs);
853 }
855 {
858 }
859 else
860 {
861 VectorAdd(PRVM_serveredictvector(ent, origin), model->normalmins, mins);
862 VectorAdd(PRVM_serveredictvector(ent, origin), model->normalmaxs, maxs);
863 }
864 }
865 else
866 {
867 // SOLID_BSP with no model is valid, mainly because some QC setup code does so temporarily
870 }
871 }
872 else
873 {
876 }
877
879 {
880 if ((int)PRVM_serveredictfloat(ent, flags) & FL_ITEM)
881 {
882 // to make items easier to pick up and allow them to be grabbed off
883 // of shelves, the abs sizes are expanded
884 mins[0] -= 15;
885 mins[1] -= 15;
886 mins[2] -= 1;
887 maxs[0] += 15;
888 maxs[1] += 15;
889 maxs[2] += 1;
890 }
891 else
892 {
893 // because movement is clipped an epsilon away from an actual edge,
894 // we must fully check even when bounding boxes don't quite touch
895 mins[0] -= 1;
896 mins[1] -= 1;
897 mins[2] -= 1;
898 maxs[0] += 1;
899 maxs[1] += 1;
900 maxs[2] += 1;
901 }
902 }
903
906
908}
909
910/*
911===============================================================================
912
913Utility functions
914
915===============================================================================
916*/
917
918// DRESK - Support for Entity Contents Transition Event
919/*
920================
921SV_CheckContentsTransition
922
923returns true if entity had a valid contentstransition function call
924================
925*/
926static int SV_CheckContentsTransition(prvm_edict_t *ent, const int nContents)
927{
928 prvm_prog_t *prog = SVVM_prog;
929 int bValidFunctionCall;
930
931 // Default Valid Function Call to False
932 bValidFunctionCall = false;
933
934 if(PRVM_serveredictfloat(ent, watertype) != nContents)
935 { // Changed Contents
936 // Acquire Contents Transition Function from QC
937 if(PRVM_serveredictfunction(ent, contentstransition))
938 { // Valid Function; Execute
939 // Assign Valid Function
940 bValidFunctionCall = true;
941 // Prepare Parameters (Original Contents, New Contents)
942 // Original Contents
944 // New Contents
945 PRVM_G_FLOAT(OFS_PARM1) = nContents;
946 // Assign Self
948 // Set Time
950 // Execute VM Function
951 prog->ExecuteProgram(prog, PRVM_serveredictfunction(ent, contentstransition), "contentstransition: NULL function");
952 }
953 }
954
955 // Return if Function Call was Valid
956 return bValidFunctionCall;
957}
958
959
960/*
961================
962SV_CheckVelocity
963================
964*/
966{
967 prvm_prog_t *prog = SVVM_prog;
968 int i;
969 float wishspeed;
970
971//
972// bound velocity
973//
974 for (i=0 ; i<3 ; i++)
975 {
976 if (isnan(PRVM_serveredictvector(ent, velocity)[i]))
977 {
978 Con_Printf("Got a NaN velocity on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
980 }
981 if (isnan(PRVM_serveredictvector(ent, origin)[i]))
982 {
983 Con_Printf("Got a NaN origin on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
985 }
986 }
987
988 // LadyHavoc: a hack to ensure that the (rather silly) id1 quakec
989 // player_run/player_stand1 does not horribly malfunction if the
990 // velocity becomes a denormalized float
991 if (VectorLength2(PRVM_serveredictvector(ent, velocity)) < 0.0000001)
993
994 // LadyHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster
997 {
1002 }
1003}
1004
1005/*
1006=============
1007SV_RunThink
1008
1009Runs thinking code if time. There is some play in the exact time the think
1010function will be called, because it is called before any movement is done
1011in a frame. Not used for pushmove objects, because they must be exact.
1012Returns false if the entity removed itself.
1013=============
1014*/
1016{
1017 prvm_prog_t *prog = SVVM_prog;
1018 int iterations;
1019
1020 // don't let things stay in the past.
1021 // it is possible to start that way by a trigger with a local time.
1023 return true;
1024
1025 for (iterations = 0;iterations < 128 && !ent->free;iterations++)
1026 {
1031 prog->ExecuteProgram(prog, PRVM_serveredictfunction(ent, think), "QC function self.think is missing");
1032 // mods often set nextthink to time to cause a think every frame,
1033 // we don't want to loop in that case, so exit if the new nextthink is
1034 // <= the time the qc was told, also exit if it is past the end of the
1035 // frame
1037 break;
1038 }
1039 return !ent->free;
1040}
1041
1042/*
1043==================
1044SV_Impact
1045
1046Two entities have touched, so run their touch functions
1047Returns true if the push did not result in the entity being teleported by QC code.
1048==================
1049*/
1051{
1052 prvm_prog_t *prog = SVVM_prog;
1053 int restorevm_tempstringsbuf_cursize;
1054 int old_self, old_other;
1055 prvm_edict_t *e2 = (prvm_edict_t *)trace->ent;
1056
1057 e1->priv.required->mark = PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN; // -2: setorigin running
1058
1059 old_self = PRVM_serverglobaledict(self);
1060 old_other = PRVM_serverglobaledict(other);
1061 restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
1062
1063 VM_SetTraceGlobals(prog, trace);
1064
1065 if (!e1->free && !e2->free && PRVM_serveredictfunction(e1, touch) && PRVM_serveredictfloat(e1, solid) != SOLID_NOT)
1066 {
1070 prog->ExecuteProgram(prog, PRVM_serveredictfunction(e1, touch), "QC function self.touch is missing");
1071 }
1072
1073 if (!e1->free && !e2->free && PRVM_serveredictfunction(e2, touch) && PRVM_serveredictfloat(e2, solid) != SOLID_NOT)
1074 {
1086 prog->ExecuteProgram(prog, PRVM_serveredictfunction(e2, touch), "QC function self.touch is missing");
1087 }
1088
1089 PRVM_serverglobaledict(self) = old_self;
1090 PRVM_serverglobaledict(other) = old_other;
1091 prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1092
1094 {
1095 e1->priv.required->mark = 0;
1096 return false;
1097 }
1099 {
1100 e1->priv.required->mark = 0;
1101 return true;
1102 }
1103 else
1104 {
1105 Con_Printf(CON_ERROR "The edict mark had been overwritten! Please debug this.\n");
1106 return true;
1107 }
1108}
1109
1110
1111/*
1112==================
1113ClipVelocity
1114
1115Slide off of the impacting object
1116returns the blocked flags (1 = floor, 2 = step / wall)
1117==================
1118*/
1119#define STOP_EPSILON 0.1
1121{
1122 int i;
1123 float backoff;
1124
1125 backoff = -DotProduct (in, normal) * overbounce;
1126 VectorMA(in, backoff, normal, out);
1127
1128 for (i = 0;i < 3;i++)
1129 if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
1130 out[i] = 0;
1131}
1132
1133
1134/*
1135============
1136SV_FlyMove
1137
1138The basic solid body movement clip that slides along multiple planes
1139Returns the clipflags if the velocity was modified (hit something solid)
11401 = floor
11412 = wall / step
11424 = dead stop
11438 = teleported by touch method
1144If stepnormal is not NULL, the plane normal of any vertical wall hit will be stored
1145============
1146*/
1147static float SV_Gravity (prvm_edict_t *ent);
1148static qbool SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qbool dotouch, qbool checkstuck);
1149#define MAX_CLIP_PLANES 5
1150static int SV_FlyMove (prvm_edict_t *ent, float time, qbool applygravity, float *stepnormal, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float stepheight)
1151{
1152 prvm_prog_t *prog = SVVM_prog;
1153 unsigned int i, j, numplanes, blocked, bumpcount;
1154 float d, time_left, gravity;
1155 vec3_t dir, push, planes[MAX_CLIP_PLANES];
1156 prvm_vec3_t primal_velocity, original_velocity, new_velocity, restore_velocity;
1157#if 0
1158 vec3_t end;
1159#endif
1160 trace_t trace;
1161 if (time <= 0)
1162 return 0;
1163 gravity = 0;
1164
1165 VectorCopy(PRVM_serveredictvector(ent, velocity), restore_velocity);
1166
1167 if(applygravity)
1168 {
1169 gravity = SV_Gravity(ent);
1170
1172 {
1174 PRVM_serveredictvector(ent, velocity)[2] -= gravity * 0.5f;
1175 else
1176 PRVM_serveredictvector(ent, velocity)[2] -= gravity;
1177 }
1178 }
1179
1180 blocked = 0;
1181 VectorCopy(PRVM_serveredictvector(ent, velocity), original_velocity);
1182 VectorCopy(PRVM_serveredictvector(ent, velocity), primal_velocity);
1183 numplanes = 0;
1184 time_left = time;
1185 for (bumpcount = 0;bumpcount < MAX_CLIP_PLANES;bumpcount++)
1186 {
1188 break;
1189
1190 VectorScale(PRVM_serveredictvector(ent, velocity), time_left, push);
1191 if(!SV_PushEntity(&trace, ent, push, sv_gameplayfix_impactbeforeonground.integer, true))
1192 {
1193 // we got teleported by a touch function
1194 // let's abort the move
1195 blocked |= 8;
1196 break;
1197 }
1198
1199 // this code is used by MOVETYPE_WALK and MOVETYPE_STEP and SV_UnstickEntity
1200 // abort move if we're stuck in the world (and didn't make it out)
1201 if (trace.worldstartsolid && trace.allsolid)
1202 {
1203 VectorCopy(restore_velocity, PRVM_serveredictvector(ent, velocity));
1204 return 3;
1205 }
1206
1207 if (trace.fraction == 1)
1208 break;
1209
1210 time_left *= 1 - trace.fraction;
1211
1212 if (trace.plane.normal[2])
1213 {
1214 if (trace.plane.normal[2] > 0.7)
1215 {
1216 // floor
1217 blocked |= 1;
1218
1219 if (!trace.ent)
1220 {
1221 Con_Printf ("SV_FlyMove: !trace.ent");
1222 trace.ent = prog->edicts;
1223 }
1224
1227 }
1228 }
1229 else if (stepheight)
1230 {
1231 // step - handle it immediately
1232 vec3_t org;
1233 vec3_t steppush;
1234 trace_t steptrace;
1235 trace_t steptrace2;
1236 trace_t steptrace3;
1237 //Con_Printf("step %f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1238 VectorSet(steppush, 0, 0, stepheight);
1239 VectorScale(PRVM_serveredictvector(ent, velocity), time_left, push);
1241 if(!SV_PushEntity(&steptrace, ent, steppush, false, true))
1242 {
1243 blocked |= 8;
1244 break;
1245 }
1246 //Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1247 if(!SV_PushEntity(&steptrace2, ent, push, false, true))
1248 {
1249 blocked |= 8;
1250 break;
1251 }
1252 //Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1253 VectorSet(steppush, 0, 0, org[2] - PRVM_serveredictvector(ent, origin)[2]);
1254 if(!SV_PushEntity(&steptrace3, ent, steppush, false, true))
1255 {
1256 blocked |= 8;
1257 break;
1258 }
1259 //Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1260 // accept the new position if it made some progress...
1261 // previously this checked if absolute distance >= 0.03125 which made stepping up unreliable
1262 if (PRVM_serveredictvector(ent, origin)[0] - org[0] || PRVM_serveredictvector(ent, origin)[1] - org[1])
1263 {
1264 //Con_Printf("accepted (delta %f %f %f)\n", PRVM_serveredictvector(ent, origin)[0] - org[0], PRVM_serveredictvector(ent, origin)[1] - org[1], PRVM_serveredictvector(ent, origin)[2] - org[2]);
1265 trace = steptrace2;
1267 time_left *= 1 - trace.fraction;
1268 numplanes = 0;
1269 continue;
1270 }
1271 else
1272 {
1273 //Con_Printf("REJECTED (delta %f %f %f)\n", PRVM_serveredictvector(ent, origin)[0] - org[0], PRVM_serveredictvector(ent, origin)[1] - org[1], PRVM_serveredictvector(ent, origin)[2] - org[2]);
1275 }
1276 }
1277 else
1278 {
1279 // step - return it to caller
1280 blocked |= 2;
1281 // save the trace for player extrafriction
1282 if (stepnormal)
1283 VectorCopy(trace.plane.normal, stepnormal);
1284 }
1285
1287 {
1288 // Unlike some other movetypes Quake's SV_FlyMove calls SV_Impact only after setting ONGROUND which id1 fiends rely on.
1289 // If we stepped up (sv_gameplayfix_stepmultipletimes) this will impact the steptrace2 plane instead of the original.
1290 if (PRVM_serveredictfloat(ent, solid) >= SOLID_TRIGGER && trace.ent)
1291 if (!SV_Impact(ent, &trace))
1292 {
1293 blocked |= 8;
1294 break;
1295 }
1296 if (ent->free)
1297 return blocked; // removed by the impact function
1298 }
1299
1300 if (trace.fraction >= 0.001)
1301 {
1302 // actually covered some distance
1303 VectorCopy(PRVM_serveredictvector(ent, velocity), original_velocity);
1304 numplanes = 0;
1305 }
1306
1307 // clipped to another plane
1308 if (numplanes >= MAX_CLIP_PLANES)
1309 {
1310 // this shouldn't really happen
1312 blocked = 3;
1313 break;
1314 }
1315
1316 /*
1317 for (i = 0;i < numplanes;i++)
1318 if (DotProduct(trace.plane.normal, planes[i]) > 0.99)
1319 break;
1320 if (i < numplanes)
1321 {
1322 VectorAdd(PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity));
1323 continue;
1324 }
1325 */
1326
1327 VectorCopy(trace.plane.normal, planes[numplanes]);
1328 numplanes++;
1329
1330 // modify original_velocity so it parallels all of the clip planes
1331 for (i = 0;i < numplanes;i++)
1332 {
1333 ClipVelocity(original_velocity, planes[i], new_velocity, 1);
1334 for (j = 0;j < numplanes;j++)
1335 {
1336 if (j != i)
1337 {
1338 // not ok
1339 if (DotProduct(new_velocity, planes[j]) < 0)
1340 break;
1341 }
1342 }
1343 if (j == numplanes)
1344 break;
1345 }
1346
1347 if (i != numplanes)
1348 {
1349 // go along this plane
1350 VectorCopy(new_velocity, PRVM_serveredictvector(ent, velocity));
1351 }
1352 else
1353 {
1354 // go along the crease
1355 if (numplanes != 2)
1356 {
1358 blocked = 7;
1359 break;
1360 }
1361 CrossProduct(planes[0], planes[1], dir);
1362 // LadyHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners
1366 }
1367
1368 // if current velocity is against the original velocity,
1369 // stop dead to avoid tiny occilations in sloping corners
1370 if (DotProduct(PRVM_serveredictvector(ent, velocity), primal_velocity) <= 0)
1371 {
1373 break;
1374 }
1375 }
1376
1377 //Con_Printf("entity %i final: blocked %i velocity %f %f %f\n", ent - prog->edicts, blocked, PRVM_serveredictvector(ent, velocity)[0], PRVM_serveredictvector(ent, velocity)[1], PRVM_serveredictvector(ent, velocity)[2]);
1378
1379 /*
1380 if ((blocked & 1) == 0 && bumpcount > 1)
1381 {
1382 // LadyHavoc: fix the 'fall to your death in a wedge corner' glitch
1383 // flag ONGROUND if there's ground under it
1384 trace = SV_TraceBox(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), end, MOVE_NORMAL, ent, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
1385 }
1386 */
1387
1388 // LadyHavoc: this came from QW and allows you to get out of water more easily
1389 if (sv_gameplayfix_easierwaterjump.integer && ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP) && !(blocked & 8))
1390 VectorCopy(primal_velocity, PRVM_serveredictvector(ent, velocity));
1391
1392 if(applygravity)
1393 {
1395 {
1397 PRVM_serveredictvector(ent, velocity)[2] -= gravity * 0.5f;
1398 }
1399 }
1400
1401 return blocked;
1402}
1403
1404/*
1405============
1406SV_Gravity
1407
1408============
1409*/
1410static float SV_Gravity (prvm_edict_t *ent)
1411{
1412 prvm_prog_t *prog = SVVM_prog;
1413 float ent_gravity;
1414
1415 ent_gravity = PRVM_serveredictfloat(ent, gravity);
1416 if (!ent_gravity)
1417 ent_gravity = 1.0f;
1418 return ent_gravity * sv_gravity.value * sv.frametime;
1419}
1420
1421
1422/*
1423===============================================================================
1424
1425PUSHMOVE
1426
1427===============================================================================
1428*/
1429
1431{
1432 prvm_prog_t *prog = SVVM_prog;
1433 int bump;
1434 trace_t stucktrace;
1435 vec3_t stuckorigin;
1436 vec3_t stuckmins, stuckmaxs;
1437 vec3_t goodmins, goodmaxs;
1438 vec3_t testorigin;
1439 vec_t nudge;
1440 vec3_t move;
1441 VectorCopy(PRVM_serveredictvector(ent, origin), stuckorigin);
1442 VectorCopy(PRVM_serveredictvector(ent, mins), stuckmins);
1443 VectorCopy(PRVM_serveredictvector(ent, maxs), stuckmaxs);
1444 VectorCopy(pivot, goodmins);
1445 VectorCopy(pivot, goodmaxs);
1446 for (bump = 0;bump < 6;bump++)
1447 {
1448 int coord = 2-(bump >> 1);
1449 //int coord = (bump >> 1);
1450 int dir = (bump & 1);
1451 int subbump;
1452
1453 for(subbump = 0; ; ++subbump)
1454 {
1455 VectorCopy(stuckorigin, testorigin);
1456 if(dir)
1457 {
1458 // pushing maxs
1459 testorigin[coord] += stuckmaxs[coord] - goodmaxs[coord];
1460 }
1461 else
1462 {
1463 // pushing mins
1464 testorigin[coord] += stuckmins[coord] - goodmins[coord];
1465 }
1466
1467 stucktrace = SV_TraceBox(stuckorigin, goodmins, goodmaxs, testorigin, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
1468 if (stucktrace.bmodelstartsolid)
1469 {
1470 // BAD BAD, can't fix that
1471 return false;
1472 }
1473
1474 if (stucktrace.fraction >= 1)
1475 break; // it WORKS!
1476
1477 if(subbump >= 10)
1478 {
1479 // BAD BAD, can't fix that
1480 return false;
1481 }
1482
1483 // we hit something... let's move out of it
1484 VectorSubtract(stucktrace.endpos, testorigin, move);
1485 nudge = DotProduct(stucktrace.plane.normal, move) + 0.03125f; // FIXME cvar this constant
1486 VectorMA(stuckorigin, nudge, stucktrace.plane.normal, stuckorigin);
1487 }
1488 /*
1489 if(subbump > 0)
1490 Con_Printf("subbump: %d\n", subbump);
1491 */
1492
1493 if(dir)
1494 {
1495 // pushing maxs
1496 goodmaxs[coord] = stuckmaxs[coord];
1497 }
1498 else
1499 {
1500 // pushing mins
1501 goodmins[coord] = stuckmins[coord];
1502 }
1503 }
1504
1505 // WE WIN
1506 VectorCopy(stuckorigin, PRVM_serveredictvector(ent, origin));
1507
1508 return true;
1509}
1510
1511/*
1512============
1513SV_PushEntity
1514
1515Does not change the entities velocity at all
1516The trace struct is filled with the trace that has been done.
1517Returns true if the push did not result in the entity being teleported by QC code.
1518============
1519*/
1520static qbool SV_UnstickEntity (prvm_edict_t *ent);
1521static qbool SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qbool dotouch, qbool checkstuck)
1522{
1523 prvm_prog_t *prog = SVVM_prog;
1524 int solid;
1525 int movetype;
1526 int type;
1527 vec3_t mins, maxs;
1528 vec3_t start;
1529 vec3_t end;
1530
1535
1537 VectorAdd(start, push, end);
1538
1541 else if (movetype == MOVETYPE_FLY_WORLDONLY)
1543 else if (solid == SOLID_TRIGGER || solid == SOLID_NOT)
1544 type = MOVE_NOMONSTERS; // only clip against bmodels
1545 else
1546 type = MOVE_NORMAL;
1547
1549 if (trace->allsolid && checkstuck)
1550 {
1551 if (SV_UnstickEntity(ent))
1552 {
1554 VectorAdd(start, push, end);
1556 }
1557 // abort move if we're stuck in the world (and didn't make it out)
1558 else if (trace->worldstartsolid)
1559 return true;
1560 }
1561
1563 VectorCopy(trace->endpos, PRVM_serveredictvector(ent, oldorigin)); // for SV_UnstickEntity()
1564
1565 SV_LinkEdict(ent);
1566
1567#if 0
1568 if(!trace->startsolid)
1570 {
1571 Con_Printf("something eeeeevil happened\n");
1572 }
1573#endif
1574
1575 if (dotouch)
1576 {
1578
1580 return SV_Impact (ent, trace);
1581 }
1582
1583 return true;
1584}
1585
1586
1587/*
1588============
1589SV_PushMove
1590
1591============
1592*/
1593static void SV_PushMove (prvm_edict_t *pusher, float movetime)
1594{
1595 prvm_prog_t *prog = SVVM_prog;
1596 int i, e, index;
1597 int pusherowner, pusherprog;
1598 int checkcontents;
1599 qbool rotated;
1600 float savesolid, movetime2, pushltime;
1601 vec3_t mins, maxs, move, move1, moveangle, pushorig, pushang, a, forward, left, up, org, pushermins, pushermaxs, checkorigin, checkmins, checkmaxs;
1602 int num_moved;
1603 int numcheckentities;
1604 static prvm_edict_t *checkentities[MAX_EDICTS];
1605 model_t *pushermodel;
1606 trace_t trace, trace2;
1607 matrix4x4_t pusherfinalmatrix, pusherfinalimatrix;
1608 static unsigned short moved_edicts[MAX_EDICTS];
1609 vec3_t pivot;
1610
1612 {
1613 PRVM_serveredictfloat(pusher, ltime) += movetime;
1614 return;
1615 }
1616
1617 switch ((int) PRVM_serveredictfloat(pusher, solid))
1618 {
1619 // LadyHavoc: valid pusher types
1620 case SOLID_BSP:
1621 case SOLID_BBOX:
1622 case SOLID_SLIDEBOX:
1623 case SOLID_CORPSE: // LadyHavoc: this would be weird...
1624 break;
1625 // LadyHavoc: no collisions
1626 case SOLID_NOT:
1627 case SOLID_TRIGGER:
1630 PRVM_serveredictvector(pusher, angles)[0] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[0] * (1.0 / 360.0));
1631 PRVM_serveredictvector(pusher, angles)[1] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[1] * (1.0 / 360.0));
1632 PRVM_serveredictvector(pusher, angles)[2] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[2] * (1.0 / 360.0));
1633 PRVM_serveredictfloat(pusher, ltime) += movetime;
1634 SV_LinkEdict(pusher);
1635 return;
1636 default:
1637 Con_Printf("SV_PushMove: entity #%i, unrecognized solid type %f\n", PRVM_NUM_FOR_EDICT(pusher), PRVM_serveredictfloat(pusher, solid));
1638 return;
1639 }
1642 {
1643 Con_Printf("SV_PushMove: entity #%i has an invalid modelindex %f\n", PRVM_NUM_FOR_EDICT(pusher), PRVM_serveredictfloat(pusher, modelindex));
1644 return;
1645 }
1646 pushermodel = SV_GetModelByIndex(index);
1647 pusherowner = PRVM_serveredictedict(pusher, owner);
1648 pusherprog = PRVM_EDICT_TO_PROG(pusher);
1649
1651
1652 movetime2 = movetime;
1653 VectorScale(PRVM_serveredictvector(pusher, velocity), movetime2, move1);
1654 VectorScale(PRVM_serveredictvector(pusher, avelocity), movetime2, moveangle);
1655 if (moveangle[0] || moveangle[2])
1656 {
1657 for (i = 0;i < 3;i++)
1658 {
1659 if (move1[i] > 0)
1660 {
1661 mins[i] = pushermodel->rotatedmins[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1662 maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1663 }
1664 else
1665 {
1666 mins[i] = pushermodel->rotatedmins[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1667 maxs[i] = pushermodel->rotatedmaxs[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1668 }
1669 }
1670 }
1671 else if (moveangle[1])
1672 {
1673 for (i = 0;i < 3;i++)
1674 {
1675 if (move1[i] > 0)
1676 {
1677 mins[i] = pushermodel->yawmins[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1678 maxs[i] = pushermodel->yawmaxs[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1679 }
1680 else
1681 {
1682 mins[i] = pushermodel->yawmins[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1683 maxs[i] = pushermodel->yawmaxs[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1684 }
1685 }
1686 }
1687 else
1688 {
1689 for (i = 0;i < 3;i++)
1690 {
1691 if (move1[i] > 0)
1692 {
1693 mins[i] = pushermodel->normalmins[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1694 maxs[i] = pushermodel->normalmaxs[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1695 }
1696 else
1697 {
1698 mins[i] = pushermodel->normalmins[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1699 maxs[i] = pushermodel->normalmaxs[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1700 }
1701 }
1702 }
1703
1704 VectorNegate (moveangle, a);
1705 AngleVectorsFLU (a, forward, left, up);
1706
1707 VectorCopy (PRVM_serveredictvector(pusher, origin), pushorig);
1708 VectorCopy (PRVM_serveredictvector(pusher, angles), pushang);
1709 pushltime = PRVM_serveredictfloat(pusher, ltime);
1710
1711// move the pusher to its final position
1712
1715 PRVM_serveredictfloat(pusher, ltime) += movetime;
1716 SV_LinkEdict(pusher);
1717
1718 pushermodel = SV_GetModelFromEdict(pusher);
1720 Matrix4x4_Invert_Simple(&pusherfinalimatrix, &pusherfinalmatrix);
1721
1722 savesolid = PRVM_serveredictfloat(pusher, solid);
1723
1724// see if any solid entities are inside the final position
1725 num_moved = 0;
1726
1727 if (PRVM_serveredictfloat(pusher, movetype) == MOVETYPE_FAKEPUSH) // Tenebrae's MOVETYPE_PUSH variant that doesn't push...
1728 numcheckentities = 0;
1729 else // MOVETYPE_PUSH
1730 numcheckentities = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, checkentities);
1731 for (e = 0;e < numcheckentities;e++)
1732 {
1733 prvm_edict_t *check = checkentities[e];
1735 switch(movetype)
1736 {
1737 case MOVETYPE_NONE:
1738 case MOVETYPE_PUSH:
1739 case MOVETYPE_FOLLOW:
1740 case MOVETYPE_NOCLIP:
1742 continue;
1743 default:
1744 break;
1745 }
1746
1747 if (PRVM_serveredictedict(check, owner) == pusherprog)
1748 continue;
1749
1750 if (pusherowner == PRVM_EDICT_TO_PROG(check))
1751 continue;
1752
1753 //Con_Printf("%i %s ", PRVM_NUM_FOR_EDICT(check), PRVM_GetString(PRVM_serveredictstring(check, classname)));
1754
1755 // tell any MOVETYPE_STEP entity that it may need to check for water transitions
1756 check->priv.server->waterposition_forceupdate = true;
1757
1758 checkcontents = SV_GenericHitSuperContentsMask(check);
1759
1760 // if the entity is standing on the pusher, it will definitely be moved
1761 // if the entity is not standing on the pusher, but is in the pusher's
1762 // final position, move it
1764 {
1765 VectorCopy(PRVM_serveredictvector(pusher, mins), pushermins);
1766 VectorCopy(PRVM_serveredictvector(pusher, maxs), pushermaxs);
1767 VectorCopy(PRVM_serveredictvector(check, origin), checkorigin);
1768 VectorCopy(PRVM_serveredictvector(check, mins), checkmins);
1769 VectorCopy(PRVM_serveredictvector(check, maxs), checkmaxs);
1770 Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, pushermins, pushermaxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, checkorigin, checkmins, checkmaxs, checkorigin, checkcontents, 0, 0, collision_extendmovelength.value);
1771 //trace = SV_TraceBox(PRVM_serveredictvector(check, origin), PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs), PRVM_serveredictvector(check, origin), MOVE_NOMONSTERS, check, checkcontents);
1772 if (!trace.startsolid)
1773 {
1774 // Con_Printf("- not in solid\n");
1775 continue;
1776 }
1777 }
1778
1779 VectorLerp(PRVM_serveredictvector(check, mins), 0.5f, PRVM_serveredictvector(check, maxs), pivot);
1780 //VectorClear(pivot);
1781
1782 if (rotated)
1783 {
1784 vec3_t org2;
1786 VectorAdd (org, pivot, org);
1787 org2[0] = DotProduct (org, forward);
1788 org2[1] = DotProduct (org, left);
1789 org2[2] = DotProduct (org, up);
1790 VectorSubtract (org2, org, move);
1791 VectorAdd (move, move1, move);
1792 }
1793 else
1794 VectorCopy (move1, move);
1795
1796 //Con_Printf("- pushing %f %f %f\n", move[0], move[1], move[2]);
1797
1798 VectorCopy (PRVM_serveredictvector(check, origin), check->priv.server->moved_from);
1799 VectorCopy (PRVM_serveredictvector(check, angles), check->priv.server->moved_fromangles);
1800 moved_edicts[num_moved++] = PRVM_NUM_FOR_EDICT(check);
1801
1802 // physics objects need better collisions than this code can do
1804 {
1806 SV_LinkEdict(check);
1808 continue;
1809 }
1810
1811 // try moving the contacted entity
1813 if(!SV_PushEntity(&trace, check, move, true, true))
1814 {
1815 // entity "check" got teleported
1816 PRVM_serveredictvector(check, angles)[1] += trace.fraction * moveangle[1];
1817 PRVM_serveredictfloat(pusher, solid) = savesolid; // was SOLID_BSP
1818 continue; // pushed enough
1819 }
1820 // FIXME: turn players specially
1821 PRVM_serveredictvector(check, angles)[1] += trace.fraction * moveangle[1];
1822 PRVM_serveredictfloat(pusher, solid) = savesolid; // was SOLID_BSP
1823 //Con_Printf("%s:%d frac %f startsolid %d bmodelstartsolid %d allsolid %d\n", __FILE__, __LINE__, trace.fraction, trace.startsolid, trace.bmodelstartsolid, trace.allsolid);
1824
1825 // this trace.fraction < 1 check causes items to fall off of pushers
1826 // if they pass under or through a wall
1827 // the groundentity check causes items to fall off of ledges
1829 PRVM_serveredictfloat(check, flags) = (int)PRVM_serveredictfloat(check, flags) & ~FL_ONGROUND;
1830
1831 // if it is still inside the pusher, block
1832 VectorCopy(PRVM_serveredictvector(pusher, mins), pushermins);
1833 VectorCopy(PRVM_serveredictvector(pusher, maxs), pushermaxs);
1834 VectorCopy(PRVM_serveredictvector(check, origin), checkorigin);
1835 VectorCopy(PRVM_serveredictvector(check, mins), checkmins);
1836 VectorCopy(PRVM_serveredictvector(check, maxs), checkmaxs);
1837 Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, pushermins, pushermaxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, checkorigin, checkmins, checkmaxs, checkorigin, checkcontents, 0, 0, collision_extendmovelength.value);
1838 if (trace.startsolid)
1839 {
1840 vec3_t move2;
1841 if(SV_NudgeOutOfSolid_PivotIsKnownGood(check, pivot))
1842 {
1843 // hack to invoke all necessary movement triggers
1844 VectorClear(move2);
1845 if(!SV_PushEntity(&trace2, check, move2, true, true))
1846 {
1847 // entity "check" got teleported
1848 continue;
1849 }
1850 // we could fix it
1851 continue;
1852 }
1853
1854 // still inside pusher, so it's really blocked
1855
1856 // fail the move
1857 if (PRVM_serveredictvector(check, mins)[0] == PRVM_serveredictvector(check, maxs)[0])
1858 continue;
1860 {
1861 // corpse
1863 {
1864 // When sv_gameplayfix_nosquashentities is disabled, entity hitboxes will be squashed when
1865 // the entity is crushed by a mover, preventing it from being interacted with again
1866 PRVM_serveredictvector(check, mins)[0] = PRVM_serveredictvector(check, mins)[1] = 0;
1868 }
1869 continue;
1870 }
1871
1872 VectorCopy (pushorig, PRVM_serveredictvector(pusher, origin));
1873 VectorCopy (pushang, PRVM_serveredictvector(pusher, angles));
1874 PRVM_serveredictfloat(pusher, ltime) = pushltime;
1875 SV_LinkEdict(pusher);
1876
1877 // move back any entities we already moved
1878 for (i = 0;i < num_moved;i++)
1879 {
1880 prvm_edict_t *ed = PRVM_EDICT_NUM(moved_edicts[i]);
1881 VectorCopy (ed->priv.server->moved_from, PRVM_serveredictvector(ed, origin));
1882 VectorCopy (ed->priv.server->moved_fromangles, PRVM_serveredictvector(ed, angles));
1883 SV_LinkEdict(ed);
1884 }
1885
1886 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
1887 if (PRVM_serveredictfunction(pusher, blocked))
1888 {
1892 prog->ExecuteProgram(prog, PRVM_serveredictfunction(pusher, blocked), "QC function self.blocked is missing");
1893 }
1894 break;
1895 }
1896 }
1897 PRVM_serveredictvector(pusher, angles)[0] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[0] * (1.0 / 360.0));
1898 PRVM_serveredictvector(pusher, angles)[1] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[1] * (1.0 / 360.0));
1899 PRVM_serveredictvector(pusher, angles)[2] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[2] * (1.0 / 360.0));
1900}
1901
1902/*
1903================
1904SV_Physics_Pusher
1905
1906================
1907*/
1909{
1910 prvm_prog_t *prog = SVVM_prog;
1911 prvm_vec_t thinktime, oldltime, movetime;
1912
1913 oldltime = PRVM_serveredictfloat(ent, ltime);
1914
1915 thinktime = PRVM_serveredictfloat(ent, nextthink);
1916 if (thinktime < PRVM_serveredictfloat(ent, ltime) + sv.frametime)
1917 {
1918 movetime = thinktime - PRVM_serveredictfloat(ent, ltime);
1919 if (movetime < 0)
1920 movetime = 0;
1921 }
1922 else
1923 movetime = sv.frametime;
1924
1925 if (movetime)
1926 // advances PRVM_serveredictfloat(ent, ltime) if not blocked
1927 SV_PushMove (ent, movetime);
1928
1929 if (thinktime > oldltime && thinktime <= PRVM_serveredictfloat(ent, ltime))
1930 {
1935 prog->ExecuteProgram(prog, PRVM_serveredictfunction(ent, think), "QC function self.think is missing");
1936 }
1937}
1938
1939
1940/*
1941===============================================================================
1942
1943CLIENT MOVEMENT
1944
1945===============================================================================
1946*/
1947
1948/*
1949=============
1950SV_CheckStuck
1951
1952This is a big hack to try and fix the rare case of getting stuck in the world
1953clipping hull.
1954=============
1955*/
1957{
1958 prvm_prog_t *prog = SVVM_prog;
1959 vec3_t offset;
1960
1962 {
1964 switch (PHYS_NudgeOutOfSolid(prog, ent))
1965 {
1966 case UNSTICK_GOOD:
1967 return true;
1968 case UNSTICK_UNSTUCK:
1970 Con_DPrintf("NudgeOutOfSolid fixed stuck entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)), offset[0], offset[1], offset[2]);
1971 return true;
1972 case UNSTICK_STUCK:
1973 Con_DPrintf(CON_WARN "NudgeOutOfSolid couldn't fix stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
1974 return false;
1975 default:
1976 Con_Printf("NudgeOutOfSolid returned a value outside its enum.\n");
1977 return false;
1978 }
1979 }
1980
1982 return false;
1983
1984 switch(PHYS_UnstickEntityReturnOffset(prog, ent, offset))
1985 {
1986 case UNSTICK_GOOD:
1987 return true;
1988 case UNSTICK_UNSTUCK:
1989 Con_DPrintf("Unstuck entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)), offset[0], offset[1], offset[2]);
1990 return true;
1991 case UNSTICK_STUCK:
1993 if (!PHYS_TestEntityPosition(prog, ent, offset))
1994 {
1995 Con_DPrintf("Unstuck entity %i (classname \"%s\") by restoring oldorigin.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
1996 return true;
1997 }
1998 Con_DPrintf(CON_WARN "Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
1999 return false;
2000 default:
2001 Con_Printf("UnstickEntityReturnOffset returned a value outside its enum.\n");
2002 return false;
2003 }
2004}
2005
2006
2007/*
2008=============
2009SV_CheckWater
2010=============
2011*/
2013{
2014 prvm_prog_t *prog = SVVM_prog;
2015 int cont;
2016 int nNativeContents;
2017 vec3_t point;
2018
2019 point[0] = PRVM_serveredictvector(ent, origin)[0];
2020 point[1] = PRVM_serveredictvector(ent, origin)[1];
2021 point[2] = PRVM_serveredictvector(ent, origin)[2] + PRVM_serveredictvector(ent, mins)[2] + 1;
2022
2023 // DRESK - Support for Entity Contents Transition Event
2024 // NOTE: Some logic needed to be slightly re-ordered
2025 // to not affect performance and allow for the feature.
2026
2027 // Acquire Super Contents Prior to Resets
2028 cont = SV_PointSuperContents(point);
2029 // Acquire Native Contents Here
2030 nNativeContents = Mod_Q1BSP_NativeContentsFromSuperContents(cont);
2031
2032 // DRESK - Support for Entity Contents Transition Event
2034 // Entity did NOT Spawn; Check
2035 SV_CheckContentsTransition(ent, nNativeContents);
2036
2037
2040 cont = SV_PointSuperContents(point);
2041 if (cont & (SUPERCONTENTS_LIQUIDSMASK))
2042 {
2043 PRVM_serveredictfloat(ent, watertype) = nNativeContents;
2045 point[2] = PRVM_serveredictvector(ent, origin)[2] + (PRVM_serveredictvector(ent, mins)[2] + PRVM_serveredictvector(ent, maxs)[2])*0.5;
2047 {
2049 point[2] = PRVM_serveredictvector(ent, origin)[2] + PRVM_serveredictvector(ent, view_ofs)[2];
2052 }
2053 }
2054
2055 return PRVM_serveredictfloat(ent, waterlevel) > 1;
2056}
2057
2058/*
2059============
2060SV_WallFriction
2061
2062============
2063*/
2064static void SV_WallFriction (prvm_edict_t *ent, float *stepnormal)
2065{
2066 prvm_prog_t *prog = SVVM_prog;
2067 float d, i;
2068 vec3_t forward, into, side, v_angle;
2069
2072 if ((d = DotProduct (stepnormal, forward) + 0.5) < 0)
2073 {
2074 // cut the tangential velocity
2075 i = DotProduct (stepnormal, PRVM_serveredictvector(ent, velocity));
2076 VectorScale (stepnormal, i, into);
2078 PRVM_serveredictvector(ent, velocity)[0] = side[0] * (1 + d);
2079 PRVM_serveredictvector(ent, velocity)[1] = side[1] * (1 + d);
2080 }
2081}
2082
2083#if 0
2084/*
2085=====================
2086SV_TryUnstick
2087
2088Player has come to a dead stop, possibly due to the problem with limited
2089float precision at some angle joins in the BSP hull.
2090
2091Try fixing by pushing one pixel in each direction.
2092
2093This is a hack, but in the interest of good gameplay...
2094======================
2095*/
2096int SV_TryUnstick (prvm_edict_t *ent, vec3_t oldvel)
2097{
2098 int i, clip;
2099 vec3_t oldorg, dir;
2100
2102 VectorClear (dir);
2103
2104 for (i=0 ; i<8 ; i++)
2105 {
2106 // try pushing a little in an axial direction
2107 switch (i)
2108 {
2109 case 0: dir[0] = 2; dir[1] = 0; break;
2110 case 1: dir[0] = 0; dir[1] = 2; break;
2111 case 2: dir[0] = -2; dir[1] = 0; break;
2112 case 3: dir[0] = 0; dir[1] = -2; break;
2113 case 4: dir[0] = 2; dir[1] = 2; break;
2114 case 5: dir[0] = -2; dir[1] = 2; break;
2115 case 6: dir[0] = 2; dir[1] = -2; break;
2116 case 7: dir[0] = -2; dir[1] = -2; break;
2117 }
2118
2119 SV_PushEntity (&trace, ent, dir, false, true);
2120
2121 // retry the original move
2122 PRVM_serveredictvector(ent, velocity)[0] = oldvel[0];
2123 PRVM_serveredictvector(ent, velocity)[1] = oldvel[1];
2124 PRVM_serveredictvector(ent, velocity)[2] = 0;
2125 clip = SV_FlyMove (ent, 0.1, NULL, SV_GenericHitSuperContentsMask(ent), 0);
2126
2127 if (fabs(oldorg[1] - PRVM_serveredictvector(ent, origin)[1]) > 4
2128 || fabs(oldorg[0] - PRVM_serveredictvector(ent, origin)[0]) > 4)
2129 {
2130 Con_DPrint("TryUnstick - success.\n");
2131 return clip;
2132 }
2133
2134 // go back to the original pos and try again
2136 }
2137
2138 // still not moving
2140 Con_DPrint("TryUnstick - failure.\n");
2141 return 7;
2142}
2143#endif
2144
2145/*
2146=====================
2147SV_WalkMove
2148
2149Only used by players
2150======================
2151*/
2152static void SV_WalkMove (prvm_edict_t *ent)
2153{
2154 prvm_prog_t *prog = SVVM_prog;
2155 int clip;
2156 int oldonground;
2157 //int originalmove_clip;
2158 int originalmove_flags;
2159 int originalmove_groundentity;
2160 int hitsupercontentsmask = SV_GenericHitSuperContentsMask(ent);
2161 int skipsupercontentsmask = 0;
2162 int skipmaterialflagsmask = 0;
2163 int type;
2164 vec3_t upmove, downmove, start_origin, start_velocity, stepnormal, originalmove_origin, originalmove_velocity, entmins, entmaxs;
2165 trace_t downtrace, trace;
2166 qbool applygravity;
2167
2168 // if frametime is 0 (due to client sending the same timestamp twice),
2169 // don't move
2170 if (sv.frametime <= 0)
2171 return;
2172
2173 applygravity = !SV_CheckWater (ent) && PRVM_serveredictfloat(ent, movetype) == MOVETYPE_WALK && ! ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP);
2174
2175 SV_CheckVelocity(ent);
2176
2177 // do a regular slide move unless it looks like you ran into a step
2178 oldonground = (int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND;
2179
2180 VectorCopy (PRVM_serveredictvector(ent, origin), start_origin);
2181 VectorCopy (PRVM_serveredictvector(ent, velocity), start_velocity);
2182
2183 clip = SV_FlyMove (ent, sv.frametime, applygravity, NULL, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, sv_gameplayfix_stepmultipletimes.integer ? sv_stepheight.value : 0);
2184
2186 if(!(clip & 1))
2187 {
2188 // only try this if there was no floor in the way in the trace (no,
2189 // this check seems to be not REALLY necessary, because if clip & 1,
2190 // our trace will hit that thing too)
2198 type = MOVE_NOMONSTERS; // only clip against bmodels
2199 else
2200 type = MOVE_NORMAL;
2201 VectorCopy(PRVM_serveredictvector(ent, mins), entmins);
2202 VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs);
2203 trace = SV_TraceBox(upmove, entmins, entmaxs, downmove, type, ent, SV_GenericHitSuperContentsMask(ent), skipsupercontentsmask, skipmaterialflagsmask, collision_extendmovelength.value);
2204 if(trace.fraction < 1 && trace.plane.normal[2] > 0.7)
2205 {
2206 clip |= 1; // but we HAVE found a floor
2207 // set groundentity so we get carried when walking onto a mover with sv_gameplayfix_nogravityonground
2209 }
2210 }
2211
2212 // if the move did not hit the ground at any point, we're not on ground
2213 if(!(clip & 1))
2214 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2215
2216 SV_CheckVelocity(ent);
2217 SV_LinkEdict(ent);
2219
2220 if(clip & 8) // teleport
2221 return;
2222
2223 if ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP)
2224 return;
2225
2226 if (sv_nostep.integer)
2227 return;
2228
2229 VectorCopy(PRVM_serveredictvector(ent, origin), originalmove_origin);
2230 VectorCopy(PRVM_serveredictvector(ent, velocity), originalmove_velocity);
2231 //originalmove_clip = clip;
2232 originalmove_flags = (int)PRVM_serveredictfloat(ent, flags);
2233 originalmove_groundentity = PRVM_serveredictedict(ent, groundentity);
2234
2235 // if move didn't block on a step, return
2236 if (clip & 2)
2237 {
2238 // if move was not trying to move into the step, return
2239 if (fabs(start_velocity[0]) < 0.03125 && fabs(start_velocity[1]) < 0.03125)
2240 return;
2241
2243 {
2244 // return if gibbed by a trigger
2246 return;
2247
2248 // return if attempting to jump while airborn (unless sv_jumpstep)
2249 if (!sv_jumpstep.integer)
2250 if (!oldonground && PRVM_serveredictfloat(ent, waterlevel) == 0)
2251 return;
2252 }
2253
2254 // try moving up and forward to go up a step
2255 // back to start pos
2256 VectorCopy (start_origin, PRVM_serveredictvector(ent, origin));
2257 VectorCopy (start_velocity, PRVM_serveredictvector(ent, velocity));
2258
2259 // move up
2260 VectorClear (upmove);
2261 upmove[2] = sv_stepheight.value;
2262 if(!SV_PushEntity(&trace, ent, upmove, true, true))
2263 {
2264 // we got teleported when upstepping... must abort the move
2265 return;
2266 }
2267
2268 // move forward
2269 PRVM_serveredictvector(ent, velocity)[2] = 0;
2270 clip = SV_FlyMove (ent, sv.frametime, applygravity, stepnormal, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, 0);
2271 PRVM_serveredictvector(ent, velocity)[2] += start_velocity[2];
2272 if(clip & 8)
2273 {
2274 // we got teleported when upstepping... must abort the move
2275 // note that z velocity handling may not be what QC expects here, but we cannot help it
2276 return;
2277 }
2278
2279 SV_CheckVelocity(ent);
2280 SV_LinkEdict(ent);
2282
2283 // check for stuckness, possibly due to the limited precision of floats
2284 // in the clipping hulls
2285 if (clip
2286 && fabs(originalmove_origin[1] - PRVM_serveredictvector(ent, origin)[1]) < 0.03125
2287 && fabs(originalmove_origin[0] - PRVM_serveredictvector(ent, origin)[0]) < 0.03125)
2288 {
2289 //Con_Printf("wall\n");
2290 // stepping up didn't make any progress, revert to original move
2291 VectorCopy(originalmove_origin, PRVM_serveredictvector(ent, origin));
2292 VectorCopy(originalmove_velocity, PRVM_serveredictvector(ent, velocity));
2293 //clip = originalmove_clip;
2294 PRVM_serveredictfloat(ent, flags) = originalmove_flags;
2295 PRVM_serveredictedict(ent, groundentity) = originalmove_groundentity;
2296 // now try to unstick if needed
2297 //clip = SV_TryUnstick (ent, oldvel);
2298 return;
2299 }
2300
2301 //Con_Printf("step - ");
2302
2303 // extra friction based on view angle
2304 if (clip & 2 && sv_wallfriction.integer)
2305 SV_WallFriction (ent, stepnormal);
2306 }
2307 // don't do the down move if stepdown is disabled, moving upward, not in water, or the move started offground or ended onground
2308 else if (!sv_gameplayfix_stepdown.integer || PRVM_serveredictfloat(ent, waterlevel) >= 3 || start_velocity[2] >= (1.0 / 32.0) || !oldonground || ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND))
2309 return;
2310
2311 // move down
2312 VectorClear (downmove);
2313 downmove[2] = -sv_stepheight.value + start_velocity[2]*sv.frametime;
2314 if(!SV_PushEntity(&downtrace, ent, downmove, true, true))
2315 {
2316 // we got teleported when downstepping... must abort the move
2317 return;
2318 }
2319
2320 if (downtrace.fraction < 1 && downtrace.plane.normal[2] > 0.7)
2321 {
2322 // this has been disabled so that you can't jump when you are stepping
2323 // up while already jumping (also known as the Quake2 double jump bug)
2324#if 0
2325 // LadyHavoc: disabled this check so you can walk on monsters/players
2326 //if (PRVM_serveredictfloat(ent, solid) == SOLID_BSP)
2327 {
2328 //Con_Printf("onground\n");
2331 }
2332#endif
2333 }
2334 else
2335 {
2336 //Con_Printf("slope\n");
2337 // if the push down didn't end up on good ground, use the move without
2338 // the step up. This happens near wall / slope combinations, and can
2339 // cause the player to hop up higher on a slope too steep to climb
2340 VectorCopy(originalmove_origin, PRVM_serveredictvector(ent, origin));
2341 VectorCopy(originalmove_velocity, PRVM_serveredictvector(ent, velocity));
2342 //clip = originalmove_clip;
2343 PRVM_serveredictfloat(ent, flags) = originalmove_flags;
2344 PRVM_serveredictedict(ent, groundentity) = originalmove_groundentity;
2345 }
2346
2347 SV_CheckVelocity(ent);
2348 SV_LinkEdict(ent);
2350}
2351
2352//============================================================================
2353
2354/*
2355=============
2356SV_Physics_Follow
2357
2358Entities that are "stuck" to another entity
2359=============
2360*/
2362{
2363 prvm_prog_t *prog = SVVM_prog;
2364 vec3_t vf, vr, vu, angles, v;
2365 prvm_edict_t *e;
2366
2367 // LadyHavoc: implemented rotation on MOVETYPE_FOLLOW objects
2370 {
2371 // quick case for no rotation
2373 }
2374 else
2375 {
2379 AngleVectors (angles, vf, vr, vu);
2380 v[0] = PRVM_serveredictvector(ent, view_ofs)[0] * vf[0] + PRVM_serveredictvector(ent, view_ofs)[1] * vr[0] + PRVM_serveredictvector(ent, view_ofs)[2] * vu[0];
2381 v[1] = PRVM_serveredictvector(ent, view_ofs)[0] * vf[1] + PRVM_serveredictvector(ent, view_ofs)[1] * vr[1] + PRVM_serveredictvector(ent, view_ofs)[2] * vu[1];
2382 v[2] = PRVM_serveredictvector(ent, view_ofs)[0] * vf[2] + PRVM_serveredictvector(ent, view_ofs)[1] * vr[2] + PRVM_serveredictvector(ent, view_ofs)[2] * vu[2];
2386 AngleVectors (angles, vf, vr, vu);
2387 PRVM_serveredictvector(ent, origin)[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + PRVM_serveredictvector(e, origin)[0];
2388 PRVM_serveredictvector(ent, origin)[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + PRVM_serveredictvector(e, origin)[1];
2389 PRVM_serveredictvector(ent, origin)[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + PRVM_serveredictvector(e, origin)[2];
2390 }
2392 SV_LinkEdict(ent);
2393 //SV_LinkEdict_TouchAreaGrid(ent);
2394}
2395
2396/*
2397==============================================================================
2398
2399TOSS / BOUNCE
2400
2401==============================================================================
2402*/
2403
2404/*
2405=============
2406SV_CheckWaterTransition
2407
2408=============
2409*/
2411{
2412 vec3_t entorigin;
2413 prvm_prog_t *prog = SVVM_prog;
2414 // LadyHavoc: bugfixes in this function are keyed to the sv_gameplayfix_bugfixedcheckwatertransition cvar - if this cvar is 0 then all the original bugs should be reenabled for compatibility
2415 int cont;
2416 VectorCopy(PRVM_serveredictvector(ent, origin), entorigin);
2419 {
2420 // just spawned here
2422 {
2423 PRVM_serveredictfloat(ent, watertype) = cont;
2425 return;
2426 }
2427 }
2428 // DRESK - Support for Entity Contents Transition Event
2429 // NOTE: Call here BEFORE updating the watertype below,
2430 // and suppress watersplash sound if a valid function
2431 // call was made to allow for custom "splash" sounds.
2432 else if( !SV_CheckContentsTransition(ent, cont) )
2433 { // Contents Transition Function Invalid; Potentially Play Water Sound
2434 // check if the entity crossed into or out of water
2436 SV_StartSound (ent, 0, sv_sound_watersplash.string, 255, 1, false, 1.0f);
2437 }
2438
2439 if (cont <= CONTENTS_WATER)
2440 {
2441 PRVM_serveredictfloat(ent, watertype) = cont;
2443 }
2444 else
2445 {
2448 }
2449}
2450
2451/*
2452=============
2453SV_Physics_Toss
2454
2455Toss, bounce, and fly movement. When onground, do nothing.
2456=============
2457*/
2458
2460{
2461 prvm_prog_t *prog = SVVM_prog;
2462 trace_t trace;
2463 vec3_t move;
2464 vec_t movetime;
2465 int bump;
2467 float d, ent_gravity;
2468 float bouncefactor;
2469 float bouncestop;
2470
2471// if onground, return without moving
2472 if ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
2473 {
2476 {
2477 // don't stick to ground if onground and moving upward
2479 }
2481 {
2482 // we can trust FL_ONGROUND if groundentity is world because it never moves
2483 return;
2484 }
2485 else if (ent->priv.server->suspendedinairflag && groundentity->free)
2486 {
2487 // if ent was supported by a brush model on previous frame,
2488 // and groundentity is now freed, set groundentity to 0 (world)
2489 // which leaves it suspended in the air
2492 return;
2493 }
2494 else if (BoxesOverlap(ent->priv.server->cullmins, ent->priv.server->cullmaxs, groundentity->priv.server->cullmins, groundentity->priv.server->cullmaxs))
2495 {
2496 // don't slide if still touching the groundentity
2497 return;
2498 }
2499 }
2500 ent->priv.server->suspendedinairflag = false;
2501
2502 SV_CheckVelocity (ent);
2503
2504// add gravity
2507
2508// move angles
2510
2511 movetime = sv.frametime;
2512 for (bump = 0;bump < MAX_CLIP_PLANES && movetime > 0;bump++)
2513 {
2514 // move origin
2515 VectorScale(PRVM_serveredictvector(ent, velocity), movetime, move);
2516 // The buzzsaw traps in r2m6 and r2m7 use MOVETYPE_FLY and rely on moving while stuck in the world.
2517 // Quake movetypes checked allsolid only in SV_FlyMove().
2518 if(!SV_PushEntity(&trace, ent, move, true, PRVM_serveredictfloat(ent, movetype) != MOVETYPE_FLY))
2519 return; // teleported
2520 if (ent->free)
2521 return;
2522 if (trace.fraction == 1)
2523 break;
2524 movetime *= 1 - min(1, trace.fraction);
2525 switch((int)PRVM_serveredictfloat(ent, movetype))
2526 {
2529 if (!bouncefactor)
2530 bouncefactor = 1.0f;
2531
2533 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2535 movetime = 0;
2536 break;
2537 case MOVETYPE_BOUNCE:
2539 if (!bouncefactor)
2540 bouncefactor = 0.5f;
2541
2543 if (!bouncestop)
2544 bouncestop = 60.0f / 800.0f;
2545
2547 ent_gravity = PRVM_serveredictfloat(ent, gravity);
2548 if (!ent_gravity)
2549 ent_gravity = 1.0f;
2550 // LadyHavoc: fixed grenades not bouncing when fired down a slope
2553 else
2554 d = PRVM_serveredictvector(ent, velocity)[2];
2555 if (trace.plane.normal[2] > 0.7 && d < sv_gravity.value * bouncestop * ent_gravity)
2556 {
2561 movetime = 0;
2562 }
2563 else
2564 {
2565 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2567 movetime = 0;
2568 }
2569 break;
2570 default:
2572 if (trace.plane.normal[2] > 0.7)
2573 {
2577 ent->priv.server->suspendedinairflag = true;
2580 movetime = 0;
2581 }
2582 else
2583 {
2584 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2586 movetime = 0;
2587 }
2588 break;
2589 }
2590 }
2591
2592// check for in water
2594}
2595
2596/*
2597===============================================================================
2598
2599STEPPING MOVEMENT
2600
2601===============================================================================
2602*/
2603
2604/*
2605=============
2606SV_Physics_Step
2607
2608Monsters freefall when they don't have a ground entity, otherwise
2609all movement is done with discrete steps.
2610
2611This is also used for objects that have become still on the ground, but
2612will fall if the floor is pulled out from under them.
2613=============
2614*/
2616{
2617 prvm_prog_t *prog = SVVM_prog;
2618 int flags = (int)PRVM_serveredictfloat(ent, flags);
2619
2620 // DRESK
2621 // Backup Velocity in the event that movetypesteplandevent is called,
2622 // to provide a parameter with the entity's velocity at impact.
2623 vec3_t backupVelocity;
2624 VectorCopy(PRVM_serveredictvector(ent, velocity), backupVelocity);
2625 // don't fall at all if fly/swim
2626 if (!(flags & (FL_FLY | FL_SWIM)))
2627 {
2628 if (flags & FL_ONGROUND)
2629 {
2630 // freefall if onground and moving upward
2631 // freefall if not standing on a world surface (it may be a lift or trap door)
2633 {
2635 SV_CheckVelocity(ent);
2636 SV_FlyMove(ent, sv.frametime, true, NULL, SV_GenericHitSuperContentsMask(ent), 0, 0, 0);
2637 SV_LinkEdict(ent);
2639 ent->priv.server->waterposition_forceupdate = true;
2640 }
2641 }
2642 else
2643 {
2644 // freefall if not onground
2645 int hitsound = PRVM_serveredictvector(ent, velocity)[2] < sv_gravity.value * -0.1;
2646
2647 SV_CheckVelocity(ent);
2648 SV_FlyMove(ent, sv.frametime, true, NULL, SV_GenericHitSuperContentsMask(ent), 0, 0, 0);
2649 SV_LinkEdict(ent);
2651
2652 // just hit ground
2653 if (hitsound && (int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
2654 {
2655 // DRESK - Check for Entity Land Event Function
2656 if(PRVM_serveredictfunction(ent, movetypesteplandevent))
2657 { // Valid Function; Execute
2658 // Prepare Parameters
2659 // Assign Velocity at Impact
2660 PRVM_G_VECTOR(OFS_PARM0)[0] = backupVelocity[0];
2661 PRVM_G_VECTOR(OFS_PARM0)[1] = backupVelocity[1];
2662 PRVM_G_VECTOR(OFS_PARM0)[2] = backupVelocity[2];
2663 // Assign Self
2665 // Set Time
2667 // Execute VM Function
2668 prog->ExecuteProgram(prog, PRVM_serveredictfunction(ent, movetypesteplandevent), "movetypesteplandevent: NULL function");
2669 }
2670 else
2671 // Check for Engine Landing Sound
2673 SV_StartSound(ent, 0, sv_sound_land.string, 255, 1, false, 1.0f);
2674 }
2675 ent->priv.server->waterposition_forceupdate = true;
2676 }
2677 }
2678}
2679
2680//============================================================================
2681
2683{
2684 prvm_prog_t *prog = SVVM_prog;
2685 // don't run think/move on newly spawned projectiles as it messes up
2686 // movement interpolation and rocket trails, and is inconsistent with
2687 // respect to entities spawned in the same frame
2688 // (if an ent spawns a higher numbered ent, it moves in the same frame,
2689 // but if it spawns a lower numbered ent, it doesn't - this never moves
2690 // ents in the first frame regardless)
2691 qbool runmove = ent->priv.server->move;
2692 ent->priv.server->move = true;
2693 if (!runmove && sv_gameplayfix_delayprojectiles.integer > 0)
2694 return;
2695 switch ((int) PRVM_serveredictfloat(ent, movetype))
2696 {
2697 case MOVETYPE_PUSH:
2698 case MOVETYPE_FAKEPUSH:
2699 SV_Physics_Pusher (ent);
2700 break;
2701 case MOVETYPE_NONE:
2702 // LadyHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
2704 SV_RunThink (ent);
2705 break;
2706 case MOVETYPE_FOLLOW:
2707 if(SV_RunThink(ent))
2708 SV_Physics_Follow (ent);
2709 break;
2710 case MOVETYPE_NOCLIP:
2711 if (SV_RunThink(ent))
2712 {
2713 SV_CheckWater(ent);
2716 }
2717 SV_LinkEdict(ent);
2718 break;
2719 case MOVETYPE_STEP:
2720 SV_Physics_Step (ent);
2721 // regular thinking
2722 if (SV_RunThink(ent))
2723 if (ent->priv.server->waterposition_forceupdate || !VectorCompare(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin))
2724 {
2725 ent->priv.server->waterposition_forceupdate = false;
2726 VectorCopy(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin);
2728 }
2729 break;
2730 case MOVETYPE_WALK:
2731 if (SV_RunThink (ent))
2732 SV_WalkMove (ent);
2733 break;
2734 case MOVETYPE_TOSS:
2735 case MOVETYPE_BOUNCE:
2738 case MOVETYPE_FLY:
2740 // regular thinking
2741 if (SV_RunThink (ent))
2742 SV_Physics_Toss (ent);
2743 break;
2744 case MOVETYPE_PHYSICS:
2745 if (SV_RunThink(ent))
2746 {
2747 SV_LinkEdict(ent);
2749 }
2750 break;
2751 default:
2753 break;
2754 Con_Printf ("SV_Physics: bad movetype %i\n", (int)PRVM_serveredictfloat(ent, movetype));
2755 break;
2756 }
2757}
2758
2760{
2761 prvm_prog_t *prog = SVVM_prog;
2762
2763 // don't run think at all, that is done during server frames
2764 // instead, call the movetypes directly so they match client input
2765
2766 // This probably only makes sense for CSQC-networked (SendEntity field set) player entities
2767 switch ((int) PRVM_serveredictfloat(ent, movetype))
2768 {
2769 case MOVETYPE_PUSH:
2770 case MOVETYPE_FAKEPUSH:
2771 // push physics relies heavily on think times and calls, and so cannot be predicted currently
2772 Con_Printf ("SV_Physics_ClientEntity_NoThink: bad movetype %i\n", (int)PRVM_serveredictfloat(ent, movetype));
2773 break;
2774 case MOVETYPE_NONE:
2775 break;
2776 case MOVETYPE_FOLLOW:
2777 SV_Physics_Follow (ent);
2778 break;
2779 case MOVETYPE_NOCLIP:
2782 break;
2783 case MOVETYPE_STEP:
2784 SV_Physics_Step (ent);
2785 break;
2786 case MOVETYPE_WALK:
2787 SV_WalkMove (ent);
2788 break;
2789 case MOVETYPE_TOSS:
2790 case MOVETYPE_BOUNCE:
2793 SV_Physics_Toss (ent);
2794 break;
2795 case MOVETYPE_FLY:
2797 SV_WalkMove (ent);
2798 break;
2799 case MOVETYPE_PHYSICS:
2800 break;
2801 default:
2803 break;
2804 Con_Printf ("SV_Physics_ClientEntity_NoThink: bad movetype %i\n", (int)PRVM_serveredictfloat(ent, movetype));
2805 break;
2806 }
2807}
2808
2809// asynchronous path
2811{
2812 prvm_prog_t *prog = SVVM_prog;
2813 prvm_edict_t *ent;
2814 ent = host_client->edict;
2815
2816 // call player physics, this needs the proper frametime
2819
2820 // call standard client pre-think, with frametime = 0
2824 prog->ExecuteProgram(prog, PRVM_serverfunction(PlayerPreThink), "QC function PlayerPreThink is missing");
2826
2827 // make sure the velocity is sane (not a NaN)
2828 SV_CheckVelocity(ent);
2829
2830 // perform movetype behaviour
2831 // note: will always be MOVETYPE_WALK if disableclientprediction = 0
2833
2834 // call standard player post-think, with frametime = 0
2838 prog->ExecuteProgram(prog, PRVM_serverfunction(PlayerPostThink), "QC function PlayerPostThink is missing");
2840
2842 {
2843 // angle fixing was requested by physics code...
2844 // so store the current angles for later use
2847
2848 // and clear fixangle for the next frame
2850 }
2851}
2852
2854{
2855 prvm_prog_t *prog = SVVM_prog;
2856 // don't do physics on disconnected clients, FrikBot relies on this
2857 if (!host_client->begun)
2858 return;
2859
2860 // make sure the velocity is sane (not a NaN)
2861 SV_CheckVelocity(ent);
2862
2863 // don't run physics here if running asynchronously
2865 {
2867 //host_client->cmd.time = max(host_client->cmd.time, sv.time);
2868 }
2869
2870 // make sure the velocity is still sane (not a NaN)
2871 SV_CheckVelocity(ent);
2872
2873 // call standard client pre-think
2876 prog->ExecuteProgram(prog, PRVM_serverfunction(PlayerPreThink), "QC function PlayerPreThink is missing");
2877
2878 // make sure the velocity is still sane (not a NaN)
2879 SV_CheckVelocity(ent);
2880}
2881
2883{
2884 prvm_prog_t *prog = SVVM_prog;
2885 // don't do physics on disconnected clients, FrikBot relies on this
2886 if (!host_client->begun)
2887 return;
2888
2889 // make sure the velocity is sane (not a NaN)
2890 SV_CheckVelocity(ent);
2891
2892 // call standard player post-think
2895 prog->ExecuteProgram(prog, PRVM_serverfunction(PlayerPostThink), "QC function PlayerPostThink is missing");
2896
2897 // make sure the velocity is still sane (not a NaN)
2898 SV_CheckVelocity(ent);
2899
2901 {
2902 // angle fixing was requested by physics code...
2903 // so store the current angles for later use
2906
2907 // and clear fixangle for the next frame
2909 }
2910
2911 // decrement the countdown variable used to decide when to go back to
2912 // synchronous physics
2915 else
2917}
2918
2920{
2921 prvm_prog_t *prog = SVVM_prog;
2922 // don't do physics on disconnected clients, FrikBot relies on this
2923 if (!host_client->begun)
2924 {
2925 memset(&host_client->cmd, 0, sizeof(host_client->cmd));
2926 return;
2927 }
2928
2929 // make sure the velocity is sane (not a NaN)
2930 SV_CheckVelocity(ent);
2931
2932 switch ((int) PRVM_serveredictfloat(ent, movetype))
2933 {
2934 case MOVETYPE_PUSH:
2935 case MOVETYPE_FAKEPUSH:
2936 SV_Physics_Pusher (ent);
2937 break;
2938 case MOVETYPE_NONE:
2939 // LadyHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
2941 SV_RunThink (ent);
2942 break;
2943 case MOVETYPE_FOLLOW:
2944 SV_RunThink (ent);
2945 if (host_client->clmovement_inputtimeout <= 0) // don't run physics here if running asynchronously
2946 SV_Physics_Follow (ent);
2947 break;
2948 case MOVETYPE_NOCLIP:
2949 SV_RunThink(ent);
2950 if (host_client->clmovement_inputtimeout <= 0) // don't run physics here if running asynchronously
2951 {
2952 SV_CheckWater(ent);
2955 }
2956 break;
2957 case MOVETYPE_STEP:
2958 if (host_client->clmovement_inputtimeout <= 0) // don't run physics here if running asynchronously
2959 SV_Physics_Step (ent);
2960 if (SV_RunThink(ent))
2961 if (ent->priv.server->waterposition_forceupdate || !VectorCompare(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin))
2962 {
2963 ent->priv.server->waterposition_forceupdate = false;
2964 VectorCopy(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin);
2966 }
2967 break;
2968 case MOVETYPE_WALK:
2969 SV_RunThink (ent);
2970 // don't run physics here if running asynchronously
2972 SV_WalkMove (ent);
2973 break;
2974 case MOVETYPE_TOSS:
2975 case MOVETYPE_BOUNCE:
2978 // regular thinking
2979 SV_RunThink (ent);
2980 if (host_client->clmovement_inputtimeout <= 0) // don't run physics here if running asynchronously
2981 SV_Physics_Toss (ent);
2982 break;
2983 case MOVETYPE_FLY:
2985 SV_RunThink (ent);
2986 if (host_client->clmovement_inputtimeout <= 0) // don't run physics here if running asynchronously
2987 SV_WalkMove (ent);
2988 break;
2989 case MOVETYPE_PHYSICS:
2990 SV_RunThink (ent);
2991 break;
2992 default:
2994 break;
2995 Con_Printf ("SV_Physics_ClientEntity: bad movetype %i\n", (int)PRVM_serveredictfloat(ent, movetype));
2996 break;
2997 }
2998
2999 SV_CheckVelocity (ent);
3000
3001 SV_LinkEdict(ent);
3003
3004 SV_CheckVelocity (ent);
3005}
3006
3007/*
3008================
3009SV_Physics
3010
3011================
3012*/
3013void SV_Physics (void)
3014{
3015 prvm_prog_t *prog = SVVM_prog;
3016 int i;
3017 prvm_edict_t *ent;
3018
3019 // free memory for resources that are no longer referenced
3021
3022// let the progs know that a new frame has started
3027 prog->ExecuteProgram(prog, PRVM_serverfunction(StartFrame), "QC function StartFrame is missing");
3028
3029#ifdef USEODE
3030 // run physics engine
3032#endif
3033
3034//
3035// treat each object in turn
3036//
3037
3038 // if force_retouch, relink all the entities
3040 for (i = 1, ent = PRVM_EDICT_NUM(i);i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
3041 if (!ent->free)
3042 SV_LinkEdict_TouchAreaGrid(ent); // force retouch even for stationary
3043
3045 {
3046 // run physics on the client entities in 3 stages
3047 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3048 if (!ent->free)
3050
3051 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3052 if (!ent->free)
3054
3055 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3056 if (!ent->free)
3058 }
3059 else
3060 {
3061 // run physics on the client entities
3062 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3063 {
3064 if (!ent->free)
3065 {
3069 }
3070 }
3071 }
3072
3073 // run physics on all the non-client entities
3075 {
3076 for (;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
3077 if (!ent->free)
3078 SV_Physics_Entity(ent);
3079 // make a second pass to see if any ents spawned this frame and make
3080 // sure they run their move/think
3082 for (i = svs.maxclients + 1, ent = PRVM_EDICT_NUM(i);i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
3083 if (!ent->priv.server->move && !ent->free)
3084 SV_Physics_Entity(ent);
3085 }
3086
3089
3090 // LadyHavoc: endframe support
3091 if (PRVM_serverfunction(EndFrame))
3092 {
3096 prog->ExecuteProgram(prog, PRVM_serverfunction(EndFrame), "QC function EndFrame is missing");
3097 }
3098
3099 // decrement prog->num_edicts if the highest number entities died
3100 for (;PRVM_ED_CanAlloc(prog, PRVM_EDICT_NUM(prog->num_edicts - 1));prog->num_edicts--);
3101
3103 sv.time += sv.frametime;
3104}
#define SUPERCONTENTS_BODY
Definition bspfile.h:201
#define SUPERCONTENTS_MONSTERCLIP
Definition bspfile.h:205
#define SUPERCONTENTS_SOLID
Definition bspfile.h:196
#define SUPERCONTENTS_LIQUIDSMASK
Definition bspfile.h:218
#define SUPERCONTENTS_CORPSE
Definition bspfile.h:202
#define SUPERCONTENTS_PLAYERCLIP
Definition bspfile.h:204
#define CONTENTS_SLIME
Definition bspfile.h:136
#define CONTENTS_WATER
Definition bspfile.h:135
#define CONTENTS_EMPTY
Definition bspfile.h:133
void Collision_ClipToWorld(trace_t *trace, model_t *model, const vec3_t tstart, const vec3_t mins, const vec3_t maxs, const vec3_t tend, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float extend)
Definition collision.c:1834
void Collision_ClipLineToWorld(trace_t *trace, model_t *model, const vec3_t tstart, const vec3_t tend, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float extend, qbool hitsurfaces)
Definition collision.c:1870
void Collision_CombineTraces(trace_t *cliptrace, const trace_t *trace, void *touch, qbool isbmodel)
Definition collision.c:1914
void Collision_ClipLineToGenericEntity(trace_t *trace, model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t tstart, const vec3_t tend, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float extend, qbool hitsurfaces)
Definition collision.c:1844
void Collision_ClipToGenericEntity(trace_t *trace, model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t tstart, const vec3_t mins, const vec3_t maxs, const vec3_t tend, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float extend)
Definition collision.c:1791
cvar_t collision_extendmovelength
Definition collision.c:14
void Collision_ClipPointToWorld(trace_t *trace, model_t *model, const vec3_t start, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
Definition collision.c:1905
void Collision_ClipPointToGenericEntity(trace_t *trace, model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
Definition collision.c:1883
gamemode_t gamemode
Definition com_game.c:26
@ GAME_TENEBRAE
full of evil hackery
Definition com_game.h:41
void Con_DPrintf(const char *fmt,...)
A Con_Printf that only shows up if the "developer" cvar is set.
Definition console.c:1544
void Con_Printf(const char *fmt,...)
Prints to all appropriate console targets.
Definition console.c:1514
void Con_DPrint(const char *msg)
A Con_Print that only shows up if the "developer" cvar is set.
Definition console.c:1531
#define CON_WARN
Definition console.h:101
#define CON_ERROR
Definition console.h:102
string classname
float movetype
float flags
float trace_dphitcontents
entity trace_ent
entity other
float modelindex
entity self
vector avelocity
float frametime
entity owner
vector mins
float clipgroup
float trace_dpstartcontents
vector velocity
string trace_dphittexturename
float effects
float time
vector trace_endpos
float trace_startsolid
vector maxs
float nextthink
float trace_inopen
vector angles
float trace_dphitq3surfaceflags
vector absmax
vector origin
string model
float trace_fraction
vector oldorigin
float solid
vector absmin
float frame
float trace_allsolid
vector trace_plane_normal
float trace_plane_dist
float trace_inwater
float dphitcontentsmask
float pflags
float bouncefactor
float bouncestop
static int(ZEXPORT *qz_inflate)(z_stream *strm
const GLdouble * v
Definition glquake.h:762
GLuint GLuint GLintptr offset
Definition glquake.h:632
GLuint index
Definition glquake.h:629
GLenum type
Definition glquake.h:656
void AngleVectorsFLU(const vec3_t angles, vec3_t forward, vec3_t left, vec3_t up)
LadyHavoc: proper matrix version of AngleVectors.
Definition mathlib.c:498
void AngleVectors(const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
Definition mathlib.c:444
#define VectorLerp(v1, lerp, v2, out)
Definition mathlib.h:120
#define max(A, B)
Definition mathlib.h:38
#define VectorNegate(a, b)
Definition mathlib.h:95
#define min(A, B)
Definition mathlib.h:37
#define BoxesOverlap(a, b, c, d)
Definition mathlib.h:122
#define VectorNormalize(v)
Definition mathlib.h:104
#define VectorClear(a)
Definition mathlib.h:97
#define bound(min, num, max)
Definition mathlib.h:34
#define VectorLength2(a)
Definition mathlib.h:110
#define VectorSet(vec, x, y, z)
Definition mathlib.h:96
#define VectorSubtract(a, b, out)
Definition mathlib.h:99
#define CrossProduct(a, b, out)
Definition mathlib.h:103
#define VectorCompare(a, b)
Definition mathlib.h:113
#define DotProduct(a, b)
Definition mathlib.h:98
#define VectorCopy(in, out)
Definition mathlib.h:101
#define VectorScale(in, scale, out)
Definition mathlib.h:111
#define VectorAdd(a, b, out)
Definition mathlib.h:100
#define VectorMA(a, scale, b, out)
Definition mathlib.h:114
void Matrix4x4_Transform(const matrix4x4_t *in, const float v[3], float out[3])
Definition matrixlib.c:1657
void Matrix4x4_CreateTranslate(matrix4x4_t *out, double x, double y, double z)
Definition matrixlib.c:584
void Matrix4x4_CreateFromQuakeEntity(matrix4x4_t *out, double x, double y, double z, double pitch, double yaw, double roll, double scale)
Definition matrixlib.c:715
void Matrix4x4_Invert_Simple(matrix4x4_t *out, const matrix4x4_t *in1)
Definition matrixlib.c:422
float sqrt(float f)
float fabs(float f)
float floor(float f)
int Mod_Q1BSP_NativeContentsFromSuperContents(int supercontents)
@ mod_alias
unstickresult_t PHYS_UnstickEntityReturnOffset(prvm_prog_t *prog, prvm_edict_t *ent, vec3_t offset)
Definition phys.c:102
unstickresult_t PHYS_NudgeOutOfSolid(prvm_prog_t *prog, prvm_edict_t *ent)
Definition phys.c:136
qbool PHYS_TestEntityPosition(prvm_prog_t *prog, prvm_edict_t *ent, vec3_t offset)
Definition phys.c:24
@ UNSTICK_GOOD
didn't need to be unstuck
Definition phys.h:13
@ UNSTICK_STUCK
Definition phys.h:12
@ UNSTICK_UNSTUCK
Definition phys.h:14
#define OFS_PARM0
Definition pr_comp.h:34
#define OFS_PARM1
Definition pr_comp.h:35
vector punchangle
Definition progsdefs.qc:117
vector v_angle
Definition progsdefs.qc:161
vector view_ofs
Definition progsdefs.qc:151
float watertype
Definition progsdefs.qc:182
float waterlevel
Definition progsdefs.qc:181
float force_retouch
Definition progsdefs.qc:19
entity groundentity
Definition progsdefs.qc:134
entity aiment
Definition progsdefs.qc:187
float fixangle
Definition progsdefs.qc:160
float ltime
Definition progsdefs.qc:107
#define PRVM_serveredictvector(ed, fieldname)
Definition progsvm.h:173
#define PRVM_serverglobaledict(fieldname)
Definition progsvm.h:180
#define PRVM_serveredictedict(ed, fieldname)
Definition progsvm.h:175
void VM_UpdateEdictSkeleton(prvm_prog_t *prog, prvm_edict_t *ed, const struct model_s *edmodel, const struct frameblend_s *frameblend)
#define PRVM_EDICT_TO_PROG(e)
Definition progsvm.h:875
#define PRVM_EDICT_NUM(n)
Definition progsvm.h:867
#define PRVM_NEXT_EDICT(e)
Definition progsvm.h:873
const char * PRVM_GetString(prvm_prog_t *prog, int num)
#define PRVM_EDICT_MARK_SETORIGIN_CAUGHT
Definition progsvm.h:79
void VM_GenerateFrameGroupBlend(prvm_prog_t *prog, struct framegroupblend_s *framegroupblend, const prvm_edict_t *ed)
#define PRVM_NUM_FOR_EDICT(e)
Definition progsvm.h:870
void PRVM_GarbageCollection(prvm_prog_t *prog)
#define PRVM_PROG_TO_EDICT(n)
Definition progsvm.h:877
#define PRVM_serverglobalfloat(fieldname)
Definition progsvm.h:177
#define PRVM_serveredictfloat(ed, fieldname)
Definition progsvm.h:172
#define PRVM_serverfunction(funcname)
Definition progsvm.h:182
#define PRVM_serverglobalstring(fieldname)
Definition progsvm.h:179
#define PRVM_serveredictstring(ed, fieldname)
Definition progsvm.h:174
void VM_FrameBlendFromFrameGroupBlend(struct frameblend_s *frameblend, const struct framegroupblend_s *framegroupblend, const struct model_s *model, double curtime)
#define PRVM_serveredictfunction(ed, fieldname)
Definition progsvm.h:176
#define PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN
Definition progsvm.h:78
#define PRVM_G_FLOAT(o)
Definition progsvm.h:882
#define PRVM_serverglobalvector(fieldname)
Definition progsvm.h:178
#define PRVM_G_VECTOR(o)
Definition progsvm.h:886
#define SVVM_prog
Definition progsvm.h:766
qbool PRVM_ED_CanAlloc(prvm_prog_t *prog, prvm_edict_t *e)
Definition prvm_edict.c:243
#define PFLAGS_FULLDYNAMIC
Definition protocol.h:108
void VM_SetTraceGlobals(prvm_prog_t *prog, const trace_t *trace)
Definition prvm_cmds.c:5228
int i
#define MAX_EDICTS
max number of objects in game world at once (32768 protocol limit)
Definition qdefs.h:105
#define MAX_MODELS
max number of models loaded at once (including during level transitions)
Definition qdefs.h:106
#define NULL
Definition qtypes.h:12
float vec_t
Definition qtypes.h:68
vec_t vec3_t[3]
Definition qtypes.h:71
prvm_vec_t prvm_vec3_t[3]
Definition qtypes.h:63
bool qbool
Definition qtypes.h:9
#define YAW
Definition qtypes.h:19
#define PITCH
Definition qtypes.h:16
float prvm_vec_t
Definition qtypes.h:55
#define ROLL
Definition qtypes.h:22
#define MOVETYPE_PHYSICS
indicates this object is physics controlled
Definition server.h:326
#define FL_WATERJUMP
player jumping out of water
Definition server.h:368
cvar_t sv_gameplayfix_swiminbmodels
Definition sv_main.c:126
#define FL_MONSTER
movement is smoothed on the client side by step based interpolation
Definition server.h:362
void SV_PlayerPhysics(void)
Definition sv_user.c:571
server_t sv
local server
Definition sv_main.c:223
#define MOVETYPE_FAKEPUSH
tenebrae's push that doesn't push
Definition server.h:325
cvar_t sv_gameplayfix_nudgeoutofsolid_separation
Definition sv_main.c:118
cvar_t sv_gameplayfix_delayprojectiles
Definition sv_main.c:106
cvar_t sv_gameplayfix_noairborncorpse_allowsuspendeditems
Definition sv_main.c:116
#define SOLID_BBOX
touch on edge, block
Definition server.h:334
#define SOLID_SLIDEBOX
touch on edge, but not an onground
Definition server.h:335
cvar_t sv_gameplayfix_consistentplayerprethink
Definition sv_main.c:105
#define MOVETYPE_TOSS
gravity
Definition server.h:318
#define MOVETYPE_NOCLIP
Definition server.h:320
cvar_t sv_areadebug
Definition sv_main.c:164
cvar_t sv_gameplayfix_easierwaterjump
Definition sv_main.c:109
#define MOVETYPE_BOUNCE
Definition server.h:322
cvar_t sv_debugmove
Definition sv_main.c:97
#define FL_FLY
Definition server.h:357
cvar_t sv_areagrid_link_SOLID_NOT
Definition sv_main.c:74
cvar_t sv_gameplayfix_impactbeforeonground
Definition sv_main.c:113
cvar_t sv_gameplayfix_unstickplayers
Definition sv_main.c:130
cvar_t sv_sound_land
Definition sv_main.c:151
cvar_t sv_gameplayfix_nudgeoutofsolid
Definition sv_main.c:117
void SV_StartSound(prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation, qbool reliable, float speed)
Definition sv_send.c:228
cvar_t sv_freezenonclients
Definition sv_main.c:102
#define MOVETYPE_WALK
gravity
Definition server.h:315
#define SOLID_CORPSE
same as SOLID_BBOX, except it behaves as SOLID_NOT against SOLID_SLIDEBOX objects (players/monsters)
Definition server.h:338
cvar_t sv_gameplayfix_nogravityonground
Definition sv_main.c:120
model_t * SV_GetModelByIndex(int modelindex)
Definition sv_main.c:1607
cvar_t sv_jumpstep
Definition sv_main.c:137
#define MOVETYPE_NONE
never moves
Definition server.h:312
#define MOVETYPE_FOLLOW
track movement of aiment
Definition server.h:324
cvar_t sv_wallfriction
Definition sv_main.c:155
#define MOVETYPE_BOUNCEMISSILE
bounce w/o gravity
Definition server.h:323
cvar_t sv_legacy_bbox_expand
Definition sv_main.c:139
#define MOVETYPE_FLY
Definition server.h:317
cvar_t sv_sound_watersplash
Definition sv_main.c:152
cvar_t sv_gameplayfix_noairborncorpse
Definition sv_main.c:115
#define SOLID_NOT
no interaction with other objects
Definition server.h:332
cvar_t sv_nostep
Definition sv_main.c:144
cvar_t sv_gameplayfix_nosquashentities
Definition sv_main.c:133
cvar_t sv_gameplayfix_gravityunaffectedbyticrate
Definition sv_main.c:111
#define FL_ITEM
Definition server.h:365
cvar_t sv_gameplayfix_fixedcheckwatertransition
Definition sv_main.c:132
cvar_t sv_gameplayfix_slidemoveprojectiles
Definition sv_main.c:122
#define MOVETYPE_USER_FIRST
user defined movetypes
Definition server.h:328
cvar_t sv_gameplayfix_upwardvelocityclearsongroundflag
Definition sv_main.c:127
model_t * SV_GetModelFromEdict(prvm_edict_t *ed)
Definition sv_main.c:1612
cvar_t sv_stepheight
Definition sv_main.c:153
#define MOVETYPE_FLY_WORLDONLY
like MOVETYPE_FLY, but uses MOVE_WORLDONLY for all its traces; objects of this movetype better be SOL...
Definition server.h:327
server_static_t svs
persistant server info
Definition sv_main.c:224
cvar_t sv_gravity
Definition sv_main.c:134
cvar_t sv_gameplayfix_unstickentities
Definition sv_main.c:131
cvar_t sv_maxvelocity
Definition sv_main.c:143
#define MOVETYPE_PUSH
no clip to world, push and crush
Definition server.h:319
#define FL_ONGROUND
Definition server.h:366
#define MOVETYPE_USER_LAST
Definition server.h:329
cvar_t sv_gameplayfix_downtracesupportsongroundflag
Definition sv_main.c:128
#define MOVETYPE_STEP
gravity, special edge handling, special step based client side interpolation
Definition server.h:316
client_t * host_client
Definition sv_main.c:29
cvar_t sv_gameplayfix_stepmultipletimes
Definition sv_main.c:124
#define SOLID_TRIGGER
touch on edge, but not blocking
Definition server.h:333
#define MOVETYPE_FLYMISSILE
extra size to monsters
Definition server.h:321
#define SOLID_BSP
bsp clip, touch on edge, block
Definition server.h:336
cvar_t sv_gameplayfix_grenadebouncedownslopes
Definition sv_main.c:112
#define FL_SWIM
Definition server.h:358
cvar_t sv_gameplayfix_stepdown
Definition sv_main.c:123
cvar_t sv_gameplayfix_multiplethinksperframe
Definition sv_main.c:114
vec2 dir
vec3 normal
ret a
float clmovement_inputtimeout
this is used by sv_clmovement_inputtimeout code
Definition server.h:229
qbool begun
false = don't send datagrams
Definition server.h:193
qbool fixangle_angles_set
Definition server.h:293
vec3_t fixangle_angles
Definition server.h:294
prvm_edict_t * edict
PRVM_EDICT_NUM(clientnum+1)
Definition server.h:221
usercmd_t cmd
movement
Definition server.h:216
float value
Definition cvar.h:74
int integer
Definition cvar.h:73
const char * string
Definition cvar.h:71
vec3_t rotatedmins
vec3_t yawmaxs
vec3_t rotatedmaxs
vec3_t normalmaxs
vec3_t yawmins
vec3_t normalmins
int mark
mark for the leak detector
Definition progsvm.h:85
qbool free
true if this edict is unused
Definition progsvm.h:93
union prvm_edict_t::@29 priv
struct edict_engineprivate_s * server
FIXME: this server pointer really means world, not server (it is used by both server qc and client qc...
Definition progsvm.h:106
prvm_edict_private_t * required
Definition progsvm.h:101
int num_edicts
copies of some vars that were former read from sv
Definition progsvm.h:671
prvm_edict_t * edicts
Definition progsvm.h:680
void(* ExecuteProgram)(struct prvm_prog_s *prog, func_t fnum, const char *errormessage)
pointer to one of the *VM_ExecuteProgram functions
Definition progsvm.h:749
sizebuf_t tempstringsbuf
buffer for storing all tempstrings created during one invocation of ExecuteProgram
Definition progsvm.h:644
struct client_s * clients
client slots
Definition server.h:30
int maxclients
number of svs.clients slots (updated by maxplayers command)
Definition server.h:28
double time
Definition server.h:76
double frametime
Definition server.h:77
world_t world
collision culling data
Definition server.h:106
struct model_s * worldmodel
Definition server.h:112
int cursize
Definition common.h:54
void * ent
Definition collision.h:47
qbool bmodelstartsolid
Definition collision.h:30
double fraction
Definition collision.h:40
qbool worldstartsolid
Definition collision.h:28
double endpos[3]
Definition collision.h:42
qbool allsolid
Definition collision.h:24
plane_t plane
Definition collision.h:44
qbool startsolid
Definition collision.h:26
static void SV_Physics_Pusher(prvm_edict_t *ent)
Definition sv_phys.c:1908
#define MAX_CLIP_PLANES
Definition sv_phys.c:1149
static void SV_Physics_ClientEntity_PreThink(prvm_edict_t *ent)
Definition sv_phys.c:2853
trace_t SV_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
Definition sv_phys.c:104
static qbool SV_CheckWater(prvm_edict_t *ent)
Definition sv_phys.c:2012
static void ClipVelocity(prvm_vec3_t in, vec3_t normal, prvm_vec3_t out, prvm_vec_t overbounce)
Definition sv_phys.c:1120
static void SV_WalkMove(prvm_edict_t *ent)
Definition sv_phys.c:2152
static qbool SV_Impact(prvm_edict_t *e1, trace_t *trace)
Definition sv_phys.c:1050
static qbool SV_RunThink(prvm_edict_t *ent)
Definition sv_phys.c:1015
static void SV_Physics_Step(prvm_edict_t *ent)
Definition sv_phys.c:2615
int SV_GenericHitSuperContentsMask(const prvm_edict_t *passedict)
calculates hitsupercontentsmask for a generic qc entity
Definition sv_phys.c:73
void SV_Physics_Toss(prvm_edict_t *ent)
Definition sv_phys.c:2459
void SV_LinkEdict_TouchAreaGrid_Call(prvm_edict_t *touch, prvm_edict_t *ent)
Definition sv_phys.c:705
static void SV_Physics_Follow(prvm_edict_t *ent)
Definition sv_phys.c:2361
trace_t SV_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float extend)
Definition sv_phys.c:256
static void SV_Physics_ClientEntity_NoThink(prvm_edict_t *ent)
Definition sv_phys.c:2759
void SV_LinkEdict(prvm_edict_t *ent)
Definition sv_phys.c:804
int SV_EntitiesInBox(const vec3_t mins, const vec3_t maxs, int maxedicts, prvm_edict_t **resultedicts)
Definition sv_phys.c:673
static float SV_Gravity(prvm_edict_t *ent)
Definition sv_phys.c:1410
void SV_CheckVelocity(prvm_edict_t *ent)
Definition sv_phys.c:965
static void SV_Physics_ClientEntity_PostThink(prvm_edict_t *ent)
Definition sv_phys.c:2882
int SV_GetPitchSign(prvm_prog_t *prog, prvm_edict_t *ent)
Definition sv_phys.c:47
static void SV_CheckWaterTransition(prvm_edict_t *ent)
Definition sv_phys.c:2410
#define STOP_EPSILON
Definition sv_phys.c:1119
static int SV_FlyMove(prvm_edict_t *ent, float time, qbool applygravity, float *stepnormal, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float stepheight)
Definition sv_phys.c:1150
int SV_PointSuperContents(const vec3_t point)
Definition sv_phys.c:611
static void SV_PushMove(prvm_edict_t *pusher, float movetime)
Definition sv_phys.c:1593
static int SV_CheckContentsTransition(prvm_edict_t *ent, const int nContents)
Definition sv_phys.c:926
static qbool SV_NudgeOutOfSolid_PivotIsKnownGood(prvm_edict_t *ent, vec3_t pivot)
Definition sv_phys.c:1430
void SV_Physics(void)
Definition sv_phys.c:3013
static qbool SV_PushEntity(trace_t *trace, prvm_edict_t *ent, vec3_t push, qbool dotouch, qbool checkstuck)
Definition sv_phys.c:1521
static void SV_Physics_ClientEntity(prvm_edict_t *ent)
Definition sv_phys.c:2919
static qbool SV_UnstickEntity(prvm_edict_t *ent)
Definition sv_phys.c:1956
static void SV_WallFriction(prvm_edict_t *ent, float *stepnormal)
Definition sv_phys.c:2064
trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float extend)
traces a box move against worldmodel and all entities in the specified area
Definition sv_phys.c:414
static void RotateBBox(const vec3_t mins, const vec3_t maxs, const vec3_t angles, vec3_t rotatedmins, vec3_t rotatedmaxs)
Definition sv_phys.c:767
static void SV_Physics_Entity(prvm_edict_t *ent)
Definition sv_phys.c:2682
void SV_Physics_ClientMove(void)
Definition sv_phys.c:2810
void SV_LinkEdict_TouchAreaGrid(prvm_edict_t *ent)
Definition sv_phys.c:727
static float wishspeed
Definition sv_user.c:306
static vec3_t forward
Definition sv_user.c:305
static vec3_t up
Definition sv_user.c:305
vec_t dist
Definition collision.h:14
vec3_t normal
Definition collision.h:13
int World_EntitiesInBox(world_t *world, const vec3_t requestmins, const vec3_t requestmaxs, int maxlist, prvm_edict_t **list)
Definition world.c:188
void World_LinkEdict(world_t *world, prvm_edict_t *ent, const vec3_t mins, const vec3_t maxs, qbool link_solid_not)
Definition world.c:320
#define MOVE_MISSILE
Definition world.h:30
void World_Physics_Frame(world_t *world, double frametime, double gravity)
#define MOVE_HITMODEL
Definition world.h:32
#define MOVE_WORLDONLY
Definition world.h:31
#define MOVE_NORMAL
Definition world.h:28
#define MOVE_NOMONSTERS
Definition world.h:29