1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20 // sv_phys.c
21
22 #include "bspfile.h"
23 #include "console.h"
24 #include "pmove.h"
25 #include "qwsvdef.h"
26 #include "server.h"
27 #include "world.h"
28
29 /*
30
31
32 pushmove 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.
33
34 onground is set for toss objects when they come to a complete rest. it is set for steping or walking objects
35
36 doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
37 bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
38 corpses are SOLID_NOT and MOVETYPE_TOSS
39 crates are SOLID_BBOX and MOVETYPE_TOSS
40 walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP
41 flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY
42
43 solid_edge items only clip against bsp models.
44
45 */
46
47 cvar_t sv_maxvelocity = { "sv_maxvelocity", "2000" };
48
49 cvar_t sv_gravity = { "sv_gravity", "800" };
50 cvar_t sv_stopspeed = { "sv_stopspeed", "100" };
51 cvar_t sv_maxspeed = { "sv_maxspeed", "320" };
52 cvar_t sv_spectatormaxspeed = { "sv_spectatormaxspeed", "500" };
53 cvar_t sv_accelerate = { "sv_accelerate", "10" };
54 cvar_t sv_airaccelerate = { "sv_airaccelerate", "0.7" };
55 cvar_t sv_wateraccelerate = { "sv_wateraccelerate", "10" };
56 cvar_t sv_friction = { "sv_friction", "4" };
57 cvar_t sv_waterfriction = { "sv_waterfriction", "4" };
58
59
60 #define MOVE_EPSILON 0.01
61
62 void SV_Physics_Toss(edict_t *ent);
63
64 /*
65 ================
66 SV_CheckAllEnts
67 ================
68 */
69 void
SV_CheckAllEnts(void)70 SV_CheckAllEnts(void)
71 {
72 int e;
73 edict_t *check;
74
75 // see if any solid entities are inside the final position
76 check = NEXT_EDICT(sv.edicts);
77 for (e = 1; e < sv.num_edicts; e++, check = NEXT_EDICT(check)) {
78 if (check->free)
79 continue;
80 if (check->v.movetype == MOVETYPE_PUSH
81 || check->v.movetype == MOVETYPE_NONE
82 || check->v.movetype == MOVETYPE_NOCLIP)
83 continue;
84
85 if (SV_TestEntityPosition(check))
86 Con_Printf("entity in invalid position\n");
87 }
88 }
89
90 /*
91 ================
92 SV_CheckVelocity
93 ================
94 */
95 void
SV_CheckVelocity(edict_t * ent)96 SV_CheckVelocity(edict_t *ent)
97 {
98 int i;
99
100 //
101 // bound velocity
102 //
103 for (i = 0; i < 3; i++) {
104 if (IS_NAN(ent->v.velocity[i])) {
105 Con_Printf("Got a NaN velocity on %s\n",
106 PR_GetString(ent->v.classname));
107 ent->v.velocity[i] = 0;
108 }
109 if (IS_NAN(ent->v.origin[i])) {
110 Con_Printf("Got a NaN origin on %s\n",
111 PR_GetString(ent->v.classname));
112 ent->v.origin[i] = 0;
113 }
114 if (ent->v.velocity[i] > sv_maxvelocity.value)
115 ent->v.velocity[i] = sv_maxvelocity.value;
116 else if (ent->v.velocity[i] < -sv_maxvelocity.value)
117 ent->v.velocity[i] = -sv_maxvelocity.value;
118 }
119 }
120
121 /*
122 =============
123 SV_RunThink
124
125 Runs thinking code if time. There is some play in the exact time the think
126 function will be called, because it is called before any movement is done
127 in a frame. Not used for pushmove objects, because they must be exact.
128 Returns false if the entity removed itself.
129 =============
130 */
131 qboolean
SV_RunThink(edict_t * ent)132 SV_RunThink(edict_t *ent)
133 {
134 float thinktime;
135
136 do {
137 thinktime = ent->v.nextthink;
138 if (thinktime <= 0)
139 return true;
140 if (thinktime > sv.time + host_frametime)
141 return true;
142
143 if (thinktime < sv.time)
144 thinktime = sv.time; // don't let things stay in the past.
145 // it is possible to start that way
146 // by a trigger with a local time.
147 ent->v.nextthink = 0;
148 pr_global_struct->time = thinktime;
149 pr_global_struct->self = EDICT_TO_PROG(ent);
150 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
151 PR_ExecuteProgram(ent->v.think);
152
153 if (ent->free)
154 return false;
155 } while (1);
156
157 return true;
158 }
159
160 /*
161 ==================
162 SV_Impact
163
164 Two entities have touched, so run their touch functions
165 ==================
166 */
167 void
SV_Impact(edict_t * e1,edict_t * e2)168 SV_Impact(edict_t *e1, edict_t *e2)
169 {
170 int old_self, old_other;
171
172 old_self = pr_global_struct->self;
173 old_other = pr_global_struct->other;
174
175 pr_global_struct->time = sv.time;
176 if (e1->v.touch && e1->v.solid != SOLID_NOT) {
177 pr_global_struct->self = EDICT_TO_PROG(e1);
178 pr_global_struct->other = EDICT_TO_PROG(e2);
179 PR_ExecuteProgram(e1->v.touch);
180 }
181
182 if (e2->v.touch && e2->v.solid != SOLID_NOT) {
183 pr_global_struct->self = EDICT_TO_PROG(e2);
184 pr_global_struct->other = EDICT_TO_PROG(e1);
185 PR_ExecuteProgram(e2->v.touch);
186 }
187
188 pr_global_struct->self = old_self;
189 pr_global_struct->other = old_other;
190 }
191
192
193 /*
194 ==================
195 ClipVelocity
196
197 Slide off of the impacting object
198 returns the blocked flags (1 = floor, 2 = step / wall)
199 ==================
200 */
201 #define STOP_EPSILON 0.1
202
203 int
ClipVelocity(vec3_t in,vec3_t normal,vec3_t out,float overbounce)204 ClipVelocity(vec3_t in, vec3_t normal, vec3_t out, float overbounce)
205 {
206 float backoff;
207 float change;
208 int i, blocked;
209
210 blocked = 0;
211 if (normal[2] > 0)
212 blocked |= 1; // floor
213 if (!normal[2])
214 blocked |= 2; // step
215
216 backoff = DotProduct(in, normal) * overbounce;
217
218 for (i = 0; i < 3; i++) {
219 change = normal[i] * backoff;
220 out[i] = in[i] - change;
221 if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
222 out[i] = 0;
223 }
224
225 return blocked;
226 }
227
228
229 /*
230 ============
231 SV_FlyMove
232
233 The basic solid body movement clip that slides along multiple planes
234 Returns the clipflags if the velocity was modified (hit something solid)
235 1 = floor
236 2 = wall / step
237 4 = dead stop
238 If steptrace is not NULL, the trace of any vertical wall hit will be stored
239 ============
240 */
241 #define MAX_CLIP_PLANES 5
242 int
SV_FlyMove(edict_t * ent,float time,trace_t * steptrace)243 SV_FlyMove(edict_t *ent, float time, trace_t *steptrace)
244 {
245 int bumpcount, numbumps;
246 vec3_t dir;
247 float d;
248 int numplanes;
249 vec3_t planes[MAX_CLIP_PLANES];
250 vec3_t primal_velocity, original_velocity, new_velocity;
251 int i, j;
252 trace_t trace;
253 vec3_t end;
254 float time_left;
255 int blocked;
256
257 numbumps = 4;
258
259 blocked = 0;
260 VectorCopy(ent->v.velocity, original_velocity);
261 VectorCopy(ent->v.velocity, primal_velocity);
262 numplanes = 0;
263
264 time_left = time;
265
266 for (bumpcount = 0; bumpcount < numbumps; bumpcount++) {
267 for (i = 0; i < 3; i++)
268 end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i];
269
270 trace =
271 SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);
272
273 if (trace.allsolid) { // entity is trapped in another solid
274 VectorCopy(vec3_origin, ent->v.velocity);
275 return 3;
276 }
277
278 if (trace.fraction > 0) { // actually covered some distance
279 VectorCopy(trace.endpos, ent->v.origin);
280 VectorCopy(ent->v.velocity, original_velocity);
281 numplanes = 0;
282 }
283
284 if (trace.fraction == 1)
285 break; // moved the entire distance
286
287 if (!trace.ent)
288 SV_Error("SV_FlyMove: !trace.ent");
289
290 if (trace.plane.normal[2] > 0.7) {
291 blocked |= 1; // floor
292 if (trace.ent->v.solid == SOLID_BSP) {
293 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
294 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
295 }
296 }
297 if (!trace.plane.normal[2]) {
298 blocked |= 2; // step
299 if (steptrace)
300 *steptrace = trace; // save for player extrafriction
301 }
302 //
303 // run the impact function
304 //
305 SV_Impact(ent, trace.ent);
306 if (ent->free)
307 break; // removed by the impact function
308
309
310 time_left -= time_left * trace.fraction;
311
312 // cliped to another plane
313 if (numplanes >= MAX_CLIP_PLANES) { // this shouldn't really happen
314 VectorCopy(vec3_origin, ent->v.velocity);
315 return 3;
316 }
317
318 VectorCopy(trace.plane.normal, planes[numplanes]);
319 numplanes++;
320
321 //
322 // modify original_velocity so it parallels all of the clip planes
323 //
324 for (i = 0; i < numplanes; i++) {
325 ClipVelocity(original_velocity, planes[i], new_velocity, 1);
326 for (j = 0; j < numplanes; j++)
327 if (j != i) {
328 if (DotProduct(new_velocity, planes[j]) < 0)
329 break; // not ok
330 }
331 if (j == numplanes)
332 break;
333 }
334
335 if (i != numplanes) { // go along this plane
336 VectorCopy(new_velocity, ent->v.velocity);
337 } else { // go along the crease
338 if (numplanes != 2) {
339 // Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
340 VectorCopy(vec3_origin, ent->v.velocity);
341 return 7;
342 }
343 CrossProduct(planes[0], planes[1], dir);
344 d = DotProduct(dir, ent->v.velocity);
345 VectorScale(dir, d, ent->v.velocity);
346 }
347
348 //
349 // if original velocity is against the original velocity, stop dead
350 // to avoid tiny occilations in sloping corners
351 //
352 if (DotProduct(ent->v.velocity, primal_velocity) <= 0) {
353 VectorCopy(vec3_origin, ent->v.velocity);
354 return blocked;
355 }
356 }
357
358 return blocked;
359 }
360
361
362 /*
363 ============
364 SV_AddGravity
365
366 ============
367 */
368 void
SV_AddGravity(edict_t * ent,float scale)369 SV_AddGravity(edict_t *ent, float scale)
370 {
371 ent->v.velocity[2] -= scale * movevars.gravity * host_frametime;
372 }
373
374 /*
375 ===============================================================================
376
377 PUSHMOVE
378
379 ===============================================================================
380 */
381
382 /*
383 ============
384 SV_PushEntity
385
386 Does not change the entities velocity at all
387 ============
388 */
389 trace_t
SV_PushEntity(edict_t * ent,vec3_t push)390 SV_PushEntity(edict_t *ent, vec3_t push)
391 {
392 trace_t trace;
393 vec3_t end;
394
395 VectorAdd(ent->v.origin, push, end);
396
397 if (ent->v.movetype == MOVETYPE_FLYMISSILE)
398 trace =
399 SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, end,
400 MOVE_MISSILE, ent);
401 else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)
402 // only clip against bmodels
403 trace =
404 SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, end,
405 MOVE_NOMONSTERS, ent);
406 else
407 trace =
408 SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, end,
409 MOVE_NORMAL, ent);
410
411 VectorCopy(trace.endpos, ent->v.origin);
412 SV_LinkEdict(ent, true);
413
414 if (trace.ent)
415 SV_Impact(ent, trace.ent);
416
417 return trace;
418 }
419
420
421 /*
422 ============
423 SV_Push
424
425 ============
426 */
427 qboolean
SV_Push(edict_t * pusher,vec3_t move)428 SV_Push(edict_t *pusher, vec3_t move)
429 {
430 int i, e;
431 edict_t *check, *block;
432 vec3_t mins, maxs;
433 vec3_t pushorig;
434 int num_moved;
435 edict_t *moved_edict[MAX_EDICTS];
436 vec3_t moved_from[MAX_EDICTS];
437
438 for (i = 0; i < 3; i++) {
439 mins[i] = pusher->v.absmin[i] + move[i];
440 maxs[i] = pusher->v.absmax[i] + move[i];
441 }
442
443 VectorCopy(pusher->v.origin, pushorig);
444
445 // move the pusher to it's final position
446
447 VectorAdd(pusher->v.origin, move, pusher->v.origin);
448 SV_LinkEdict(pusher, false);
449
450 // see if any solid entities are inside the final position
451 num_moved = 0;
452 check = NEXT_EDICT(sv.edicts);
453 for (e = 1; e < sv.num_edicts; e++, check = NEXT_EDICT(check)) {
454 if (check->free)
455 continue;
456 if (check->v.movetype == MOVETYPE_PUSH
457 || check->v.movetype == MOVETYPE_NONE
458 || check->v.movetype == MOVETYPE_NOCLIP)
459 continue;
460
461 pusher->v.solid = SOLID_NOT;
462 block = SV_TestEntityPosition(check);
463 pusher->v.solid = SOLID_BSP;
464 if (block)
465 continue;
466
467 // if the entity is standing on the pusher, it will definately be moved
468 if (!(((int)check->v.flags & FL_ONGROUND)
469 && PROG_TO_EDICT(check->v.groundentity) == pusher)) {
470 if (check->v.absmin[0] >= maxs[0]
471 || check->v.absmin[1] >= maxs[1]
472 || check->v.absmin[2] >= maxs[2]
473 || check->v.absmax[0] <= mins[0]
474 || check->v.absmax[1] <= mins[1]
475 || check->v.absmax[2] <= mins[2])
476 continue;
477
478 // see if the ent's bbox is inside the pusher's final position
479 if (!SV_TestEntityPosition(check))
480 continue;
481 }
482
483 VectorCopy(check->v.origin, moved_from[num_moved]);
484 moved_edict[num_moved] = check;
485 num_moved++;
486
487 // try moving the contacted entity
488 VectorAdd(check->v.origin, move, check->v.origin);
489 block = SV_TestEntityPosition(check);
490 if (!block) { // pushed ok
491 SV_LinkEdict(check, false);
492 continue;
493 }
494 // if it is ok to leave in the old position, do it
495 VectorSubtract(check->v.origin, move, check->v.origin);
496 block = SV_TestEntityPosition(check);
497 if (!block) {
498 num_moved--;
499 continue;
500 }
501 // if it is still inside the pusher, block
502 if (check->v.mins[0] == check->v.maxs[0]) {
503 SV_LinkEdict(check, false);
504 continue;
505 }
506 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER) { // corpse
507 check->v.mins[0] = check->v.mins[1] = 0;
508 VectorCopy(check->v.mins, check->v.maxs);
509 SV_LinkEdict(check, false);
510 continue;
511 }
512
513 VectorCopy(pushorig, pusher->v.origin);
514 SV_LinkEdict(pusher, false);
515
516 // if the pusher has a "blocked" function, call it
517 // otherwise, just stay in place until the obstacle is gone
518 if (pusher->v.blocked) {
519 pr_global_struct->self = EDICT_TO_PROG(pusher);
520 pr_global_struct->other = EDICT_TO_PROG(check);
521 PR_ExecuteProgram(pusher->v.blocked);
522 }
523 // move back any entities we already moved
524 for (i = 0; i < num_moved; i++) {
525 VectorCopy(moved_from[i], moved_edict[i]->v.origin);
526 SV_LinkEdict(moved_edict[i], false);
527 }
528 return false;
529 }
530
531 return true;
532 }
533
534 /*
535 ============
536 SV_PushMove
537
538 ============
539 */
540 void
SV_PushMove(edict_t * pusher,float movetime)541 SV_PushMove(edict_t *pusher, float movetime)
542 {
543 int i;
544 vec3_t move;
545
546 if (!pusher->v.velocity[0] && !pusher->v.velocity[1]
547 && !pusher->v.velocity[2]) {
548 pusher->v.ltime += movetime;
549 return;
550 }
551
552 for (i = 0; i < 3; i++)
553 move[i] = pusher->v.velocity[i] * movetime;
554
555 if (SV_Push(pusher, move))
556 pusher->v.ltime += movetime;
557 }
558
559
560 /*
561 ================
562 SV_Physics_Pusher
563
564 ================
565 */
566 void
SV_Physics_Pusher(edict_t * ent)567 SV_Physics_Pusher(edict_t *ent)
568 {
569 float thinktime;
570 float oldltime;
571 float movetime;
572 vec3_t oldorg, move;
573 float l;
574
575 oldltime = ent->v.ltime;
576
577 thinktime = ent->v.nextthink;
578 if (thinktime < ent->v.ltime + host_frametime) {
579 movetime = thinktime - ent->v.ltime;
580 if (movetime < 0)
581 movetime = 0;
582 } else
583 movetime = host_frametime;
584
585 if (movetime) {
586 SV_PushMove(ent, movetime); // advances ent->v.ltime if not blocked
587 }
588
589 if (thinktime > oldltime && thinktime <= ent->v.ltime) {
590 VectorCopy(ent->v.origin, oldorg);
591 ent->v.nextthink = 0;
592 pr_global_struct->time = sv.time;
593 pr_global_struct->self = EDICT_TO_PROG(ent);
594 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
595 PR_ExecuteProgram(ent->v.think);
596 if (ent->free)
597 return;
598 VectorSubtract(ent->v.origin, oldorg, move);
599
600 l = Length(move);
601 if (l > 1.0 / 64) {
602 // Con_Printf ("**** snap: %f\n", Length (l));
603 VectorCopy(oldorg, ent->v.origin);
604 SV_Push(ent, move);
605 }
606
607 }
608
609 }
610
611
612 /*
613 =============
614 SV_Physics_None
615
616 Non moving objects can only think
617 =============
618 */
619 void
SV_Physics_None(edict_t * ent)620 SV_Physics_None(edict_t *ent)
621 {
622 // regular thinking
623 SV_RunThink(ent);
624 }
625
626 /*
627 =============
628 SV_Physics_Noclip
629
630 A moving object that doesn't obey physics
631 =============
632 */
633 void
SV_Physics_Noclip(edict_t * ent)634 SV_Physics_Noclip(edict_t *ent)
635 {
636 // regular thinking
637 if (!SV_RunThink(ent))
638 return;
639
640 VectorMA(ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
641 VectorMA(ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
642
643 SV_LinkEdict(ent, false);
644 }
645
646 /*
647 ==============================================================================
648
649 TOSS / BOUNCE
650
651 ==============================================================================
652 */
653
654 /*
655 =============
656 SV_CheckWaterTransition
657
658 =============
659 */
660 void
SV_CheckWaterTransition(edict_t * ent)661 SV_CheckWaterTransition(edict_t *ent)
662 {
663 int cont;
664
665 cont = SV_PointContents(ent->v.origin);
666 if (!ent->v.watertype) { // just spawned here
667 ent->v.watertype = cont;
668 ent->v.waterlevel = 1;
669 return;
670 }
671
672 if (cont <= CONTENTS_WATER) {
673 if (ent->v.watertype == CONTENTS_EMPTY) { // just crossed into water
674 SV_StartSound(ent, 0, "misc/h2ohit1.wav", 255, 1);
675 }
676 ent->v.watertype = cont;
677 ent->v.waterlevel = 1;
678 } else {
679 if (ent->v.watertype != CONTENTS_EMPTY) { // just crossed into water
680 SV_StartSound(ent, 0, "misc/h2ohit1.wav", 255, 1);
681 }
682 ent->v.watertype = CONTENTS_EMPTY;
683 ent->v.waterlevel = cont;
684 }
685 }
686
687 /*
688 =============
689 SV_Physics_Toss
690
691 Toss, bounce, and fly movement. When onground, do nothing.
692 =============
693 */
694 void
SV_Physics_Toss(edict_t * ent)695 SV_Physics_Toss(edict_t *ent)
696 {
697 trace_t trace;
698 vec3_t move;
699 float backoff;
700
701 // regular thinking
702 if (!SV_RunThink(ent))
703 return;
704
705 if (ent->v.velocity[2] > 0)
706 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
707
708 // if onground, return without moving
709 if (((int)ent->v.flags & FL_ONGROUND))
710 return;
711
712 SV_CheckVelocity(ent);
713
714 // add gravity
715 if (ent->v.movetype != MOVETYPE_FLY
716 && ent->v.movetype != MOVETYPE_FLYMISSILE)
717 SV_AddGravity(ent, 1.0);
718
719 // move angles
720 VectorMA(ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
721
722 // move origin
723 VectorScale(ent->v.velocity, host_frametime, move);
724 trace = SV_PushEntity(ent, move);
725 if (trace.fraction == 1)
726 return;
727 if (ent->free)
728 return;
729
730 if (ent->v.movetype == MOVETYPE_BOUNCE)
731 backoff = 1.5;
732 else
733 backoff = 1;
734
735 ClipVelocity(ent->v.velocity, trace.plane.normal, ent->v.velocity,
736 backoff);
737
738 // stop if on ground
739 if (trace.plane.normal[2] > 0.7) {
740 if (ent->v.velocity[2] < 60 || ent->v.movetype != MOVETYPE_BOUNCE) {
741 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
742 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
743 VectorCopy(vec3_origin, ent->v.velocity);
744 VectorCopy(vec3_origin, ent->v.avelocity);
745 }
746 }
747 // check for in water
748 SV_CheckWaterTransition(ent);
749 }
750
751 /*
752 ===============================================================================
753
754 STEPPING MOVEMENT
755
756 ===============================================================================
757 */
758
759 /*
760 =============
761 SV_Physics_Step
762
763 Monsters freefall when they don't have a ground entity, otherwise
764 all movement is done with discrete steps.
765
766 This is also used for objects that have become still on the ground, but
767 will fall if the floor is pulled out from under them.
768 FIXME: is this true?
769 =============
770 */
771 void
SV_Physics_Step(edict_t * ent)772 SV_Physics_Step(edict_t *ent)
773 {
774 qboolean hitsound;
775
776 // frefall if not onground
777 if (!((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM))) {
778 if (ent->v.velocity[2] < movevars.gravity * -0.1)
779 hitsound = true;
780 else
781 hitsound = false;
782
783 SV_AddGravity(ent, 1.0);
784 SV_CheckVelocity(ent);
785 SV_FlyMove(ent, host_frametime, NULL);
786 SV_LinkEdict(ent, true);
787
788 if ((int)ent->v.flags & FL_ONGROUND) // just hit ground
789 {
790 if (hitsound)
791 SV_StartSound(ent, 0, "demon/dland2.wav", 255, 1);
792 }
793 }
794 // regular thinking
795 SV_RunThink(ent);
796
797 SV_CheckWaterTransition(ent);
798 }
799
800 //============================================================================
801
802 void
SV_ProgStartFrame(void)803 SV_ProgStartFrame(void)
804 {
805 // let the progs know that a new frame has started
806 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
807 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
808 pr_global_struct->time = sv.time;
809 PR_ExecuteProgram(pr_global_struct->StartFrame);
810 }
811
812 /*
813 ================
814 SV_RunEntity
815
816 ================
817 */
818 void
SV_RunEntity(edict_t * ent)819 SV_RunEntity(edict_t *ent)
820 {
821 if (ent->v.lastruntime == (float)realtime)
822 return;
823 ent->v.lastruntime = (float)realtime;
824
825 switch ((int)ent->v.movetype) {
826 case MOVETYPE_PUSH:
827 SV_Physics_Pusher(ent);
828 break;
829 case MOVETYPE_NONE:
830 SV_Physics_None(ent);
831 break;
832 case MOVETYPE_NOCLIP:
833 SV_Physics_Noclip(ent);
834 break;
835 case MOVETYPE_STEP:
836 SV_Physics_Step(ent);
837 break;
838 case MOVETYPE_TOSS:
839 case MOVETYPE_BOUNCE:
840 case MOVETYPE_FLY:
841 case MOVETYPE_FLYMISSILE:
842 SV_Physics_Toss(ent);
843 break;
844 default:
845 SV_Error("SV_Physics: bad movetype %i", (int)ent->v.movetype);
846 }
847 }
848
849 /*
850 ================
851 SV_RunNewmis
852
853 ================
854 */
855 void
SV_RunNewmis(void)856 SV_RunNewmis(void)
857 {
858 edict_t *ent;
859
860 if (!pr_global_struct->newmis)
861 return;
862 ent = PROG_TO_EDICT(pr_global_struct->newmis);
863 host_frametime = 0.05;
864 pr_global_struct->newmis = 0;
865
866 SV_RunEntity(ent);
867 }
868
869 /*
870 ================
871 SV_Physics
872
873 ================
874 */
875 void
SV_Physics(void)876 SV_Physics(void)
877 {
878 int i;
879 edict_t *ent;
880 static double old_time;
881
882 // don't bother running a frame if sys_ticrate seconds haven't passed
883 host_frametime = realtime - old_time;
884 if (host_frametime < sv_mintic.value)
885 return;
886 if (host_frametime > sv_maxtic.value)
887 host_frametime = sv_maxtic.value;
888 old_time = realtime;
889
890 pr_global_struct->frametime = host_frametime;
891
892 SV_ProgStartFrame();
893
894 //
895 // treat each object in turn
896 // even the world gets a chance to think
897 //
898 ent = sv.edicts;
899 for (i = 0; i < sv.num_edicts; i++, ent = NEXT_EDICT(ent)) {
900 if (ent->free)
901 continue;
902
903 if (pr_global_struct->force_retouch)
904 SV_LinkEdict(ent, true); // force retouch even for stationary
905
906 if (i > 0 && i <= MAX_CLIENTS)
907 continue; // clients are run directly from packets
908
909 SV_RunEntity(ent);
910 SV_RunNewmis();
911 }
912
913 if (pr_global_struct->force_retouch)
914 pr_global_struct->force_retouch--;
915 }
916
917 void
SV_SetMoveVars(void)918 SV_SetMoveVars(void)
919 {
920 movevars.gravity = sv_gravity.value;
921 movevars.stopspeed = sv_stopspeed.value;
922 movevars.maxspeed = sv_maxspeed.value;
923 movevars.spectatormaxspeed = sv_spectatormaxspeed.value;
924 movevars.accelerate = sv_accelerate.value;
925 movevars.airaccelerate = sv_airaccelerate.value;
926 movevars.wateraccelerate = sv_wateraccelerate.value;
927 movevars.friction = sv_friction.value;
928 movevars.waterfriction = sv_waterfriction.value;
929 movevars.entgravity = 1.0;
930 }
931