summaryrefslogtreecommitdiff
path: root/apps/plugins/sdl/progs/quake/sv_phys.c
diff options
context:
space:
mode:
authorFranklin Wei <git@fwei.tk>2018-02-11 15:34:30 -0500
committerFranklin Wei <git@fwei.tk>2019-07-19 22:37:40 -0400
commit5d05b9d3e920a6aa5fcb553758e98ed0da8c91e4 (patch)
tree84406e21639529a185556a33e5de7f43cffc277b /apps/plugins/sdl/progs/quake/sv_phys.c
parentb70fecf21ddc21877ec1ae7888d9c18a979e37ad (diff)
downloadrockbox-5d05b9d3e920a6aa5fcb553758e98ed0da8c91e4.tar.gz
rockbox-5d05b9d3e920a6aa5fcb553758e98ed0da8c91e4.zip
Quake!
This ports id Software's Quake to run on the SDL plugin runtime. The source code originated from id under the GPLv2 license. I used https://github.com/ahefner/sdlquake as the base of my port. Performance is, unsurprisingly, not on par with what you're probably used to on PC. I average about 10FPS on ipod6g, but it's still playable. Sound works well enough, but in-game music is not supported. I've written ARM assembly routines for the inner sound loop. Make sure you turn the "brightness" all the way down, or colors will look funky. To run, extract Quake's data files to /.rockbox/quake. Have fun! Change-Id: I4285036e967d7f0722802d43cf2096c808ca5799
Diffstat (limited to 'apps/plugins/sdl/progs/quake/sv_phys.c')
-rw-r--r--apps/plugins/sdl/progs/quake/sv_phys.c1617
1 files changed, 1617 insertions, 0 deletions
diff --git a/apps/plugins/sdl/progs/quake/sv_phys.c b/apps/plugins/sdl/progs/quake/sv_phys.c
new file mode 100644
index 0000000000..e13c0e443d
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/sv_phys.c
@@ -0,0 +1,1617 @@
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
24/*
25
26
27pushmove 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.
28
29onground is set for toss objects when they come to a complete rest. it is set for steping or walking objects
30
31doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
32bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
33corpses are SOLID_NOT and MOVETYPE_TOSS
34crates are SOLID_BBOX and MOVETYPE_TOSS
35walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP
36flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY
37
38solid_edge items only clip against bsp models.
39
40*/
41
42cvar_t sv_friction = {"sv_friction","4",false,true};
43cvar_t sv_stopspeed = {"sv_stopspeed","100"};
44cvar_t sv_gravity = {"sv_gravity","800",false,true};
45cvar_t sv_maxvelocity = {"sv_maxvelocity","2000"};
46cvar_t sv_nostep = {"sv_nostep","0"};
47
48#ifdef QUAKE2
49static vec3_t vec_origin = {0.0, 0.0, 0.0};
50#endif
51
52#define MOVE_EPSILON 0.01
53
54void SV_Physics_Toss (edict_t *ent);
55
56/*
57================
58SV_CheckAllEnts
59================
60*/
61void SV_CheckAllEnts (void)
62{
63 int e;
64 edict_t *check;
65
66// see if any solid entities are inside the final position
67 check = NEXT_EDICT(sv.edicts);
68 for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
69 {
70 if (check->free)
71 continue;
72 if (check->v.movetype == MOVETYPE_PUSH
73 || check->v.movetype == MOVETYPE_NONE
74#ifdef QUAKE2
75 || check->v.movetype == MOVETYPE_FOLLOW
76#endif
77 || check->v.movetype == MOVETYPE_NOCLIP)
78 continue;
79
80 if (SV_TestEntityPosition (check))
81 Con_Printf ("entity in invalid position\n");
82 }
83}
84
85/*
86================
87SV_CheckVelocity
88================
89*/
90void SV_CheckVelocity (edict_t *ent)
91{
92 int i;
93
94//
95// bound velocity
96//
97 for (i=0 ; i<3 ; i++)
98 {
99 if (IS_NAN(ent->v.velocity[i]))
100 {
101 Con_Printf ("Got a NaN velocity on %s\n", pr_strings + ent->v.classname);
102 ent->v.velocity[i] = 0;
103 }
104 if (IS_NAN(ent->v.origin[i]))
105 {
106 Con_Printf ("Got a NaN origin on %s\n", pr_strings + ent->v.classname);
107 ent->v.origin[i] = 0;
108 }
109 if (ent->v.velocity[i] > sv_maxvelocity.value)
110 ent->v.velocity[i] = sv_maxvelocity.value;
111 else if (ent->v.velocity[i] < -sv_maxvelocity.value)
112 ent->v.velocity[i] = -sv_maxvelocity.value;
113 }
114}
115
116/*
117=============
118SV_RunThink
119
120Runs thinking code if time. There is some play in the exact time the think
121function will be called, because it is called before any movement is done
122in a frame. Not used for pushmove objects, because they must be exact.
123Returns false if the entity removed itself.
124=============
125*/
126qboolean SV_RunThink (edict_t *ent)
127{
128 float thinktime;
129
130 thinktime = ent->v.nextthink;
131 if (thinktime <= 0 || thinktime > sv.time + host_frametime)
132 return true;
133
134 if (thinktime < sv.time)
135 thinktime = sv.time; // don't let things stay in the past.
136 // it is possible to start that way
137 // by a trigger with a local time.
138 ent->v.nextthink = 0;
139 pr_global_struct->time = thinktime;
140 pr_global_struct->self = EDICT_TO_PROG(ent);
141 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
142 PR_ExecuteProgram (ent->v.think);
143 return !ent->free;
144}
145
146/*
147==================
148SV_Impact
149
150Two entities have touched, so run their touch functions
151==================
152*/
153void SV_Impact (edict_t *e1, edict_t *e2)
154{
155 int old_self, old_other;
156
157 old_self = pr_global_struct->self;
158 old_other = pr_global_struct->other;
159
160 pr_global_struct->time = sv.time;
161 if (e1->v.touch && e1->v.solid != SOLID_NOT)
162 {
163 pr_global_struct->self = EDICT_TO_PROG(e1);
164 pr_global_struct->other = EDICT_TO_PROG(e2);
165 PR_ExecuteProgram (e1->v.touch);
166 }
167
168 if (e2->v.touch && e2->v.solid != SOLID_NOT)
169 {
170 pr_global_struct->self = EDICT_TO_PROG(e2);
171 pr_global_struct->other = EDICT_TO_PROG(e1);
172 PR_ExecuteProgram (e2->v.touch);
173 }
174
175 pr_global_struct->self = old_self;
176 pr_global_struct->other = old_other;
177}
178
179
180/*
181==================
182ClipVelocity
183
184Slide off of the impacting object
185returns the blocked flags (1 = floor, 2 = step / wall)
186==================
187*/
188#define STOP_EPSILON 0.1
189
190int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
191{
192 float backoff;
193 float change;
194 int i, blocked;
195
196 blocked = 0;
197 if (normal[2] > 0)
198 blocked |= 1; // floor
199 if (!normal[2])
200 blocked |= 2; // step
201
202 backoff = DotProduct (in, normal) * overbounce;
203
204 for (i=0 ; i<3 ; i++)
205 {
206 change = normal[i]*backoff;
207 out[i] = in[i] - change;
208 if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
209 out[i] = 0;
210 }
211
212 return blocked;
213}
214
215
216/*
217============
218SV_FlyMove
219
220The basic solid body movement clip that slides along multiple planes
221Returns the clipflags if the velocity was modified (hit something solid)
2221 = floor
2232 = wall / step
2244 = dead stop
225If steptrace is not NULL, the trace of any vertical wall hit will be stored
226============
227*/
228#define MAX_CLIP_PLANES 5
229int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace)
230{
231 int bumpcount, numbumps;
232 vec3_t dir;
233 float d;
234 int numplanes;
235 vec3_t planes[MAX_CLIP_PLANES];
236 vec3_t primal_velocity, original_velocity, new_velocity;
237 int i, j;
238 trace_t trace;
239 vec3_t end;
240 float time_left;
241 int blocked;
242
243 numbumps = 4;
244
245 blocked = 0;
246 VectorCopy (ent->v.velocity, original_velocity);
247 VectorCopy (ent->v.velocity, primal_velocity);
248 numplanes = 0;
249
250 time_left = time;
251
252 for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
253 {
254 if (!ent->v.velocity[0] && !ent->v.velocity[1] && !ent->v.velocity[2])
255 break;
256
257 for (i=0 ; i<3 ; i++)
258 end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i];
259
260 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);
261
262 if (trace.allsolid)
263 { // entity is trapped in another solid
264 VectorCopy (vec3_origin, ent->v.velocity);
265 return 3;
266 }
267
268 if (trace.fraction > 0)
269 { // actually covered some distance
270 VectorCopy (trace.endpos, ent->v.origin);
271 VectorCopy (ent->v.velocity, original_velocity);
272 numplanes = 0;
273 }
274
275 if (trace.fraction == 1)
276 break; // moved the entire distance
277
278 if (!trace.ent)
279 Sys_Error ("SV_FlyMove: !trace.ent");
280
281 if (trace.plane.normal[2] > 0.7)
282 {
283 blocked |= 1; // floor
284 if (trace.ent->v.solid == SOLID_BSP)
285 {
286 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
287 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
288 }
289 }
290 if (!trace.plane.normal[2])
291 {
292 blocked |= 2; // step
293 if (steptrace)
294 *steptrace = trace; // save for player extrafriction
295 }
296
297//
298// run the impact function
299//
300 SV_Impact (ent, trace.ent);
301 if (ent->free)
302 break; // removed by the impact function
303
304
305 time_left -= time_left * trace.fraction;
306
307 // cliped to another plane
308 if (numplanes >= MAX_CLIP_PLANES)
309 { // this shouldn't really happen
310 VectorCopy (vec3_origin, ent->v.velocity);
311 return 3;
312 }
313
314 VectorCopy (trace.plane.normal, planes[numplanes]);
315 numplanes++;
316
317//
318// modify original_velocity so it parallels all of the clip planes
319//
320 for (i=0 ; i<numplanes ; i++)
321 {
322 ClipVelocity (original_velocity, planes[i], new_velocity, 1);
323 for (j=0 ; j<numplanes ; j++)
324 if (j != i)
325 {
326 if (DotProduct (new_velocity, planes[j]) < 0)
327 break; // not ok
328 }
329 if (j == numplanes)
330 break;
331 }
332
333 if (i != numplanes)
334 { // go along this plane
335 VectorCopy (new_velocity, ent->v.velocity);
336 }
337 else
338 { // go along the crease
339 if (numplanes != 2)
340 {
341// Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
342 VectorCopy (vec3_origin, ent->v.velocity);
343 return 7;
344 }
345 CrossProduct (planes[0], planes[1], dir);
346 d = DotProduct (dir, ent->v.velocity);
347 VectorScale (dir, d, ent->v.velocity);
348 }
349
350//
351// if original velocity is against the original velocity, stop dead
352// to avoid tiny occilations in sloping corners
353//
354 if (DotProduct (ent->v.velocity, primal_velocity) <= 0)
355 {
356 VectorCopy (vec3_origin, ent->v.velocity);
357 return blocked;
358 }
359 }
360
361 return blocked;
362}
363
364
365/*
366============
367SV_AddGravity
368
369============
370*/
371void SV_AddGravity (edict_t *ent)
372{
373 float ent_gravity;
374
375#ifdef QUAKE2
376 if (ent->v.gravity)
377 ent_gravity = ent->v.gravity;
378 else
379 ent_gravity = 1.0;
380#else
381 eval_t *val;
382
383 val = GetEdictFieldValue(ent, "gravity");
384 if (val && val->_float)
385 ent_gravity = val->_float;
386 else
387 ent_gravity = 1.0;
388#endif
389 ent->v.velocity[2] -= ent_gravity * sv_gravity.value * host_frametime;
390}
391
392
393/*
394===============================================================================
395
396PUSHMOVE
397
398===============================================================================
399*/
400
401/*
402============
403SV_PushEntity
404
405Does not change the entities velocity at all
406============
407*/
408trace_t SV_PushEntity (edict_t *ent, vec3_t push)
409{
410 trace_t trace;
411 vec3_t end;
412
413 VectorAdd (ent->v.origin, push, end);
414
415 if (ent->v.movetype == MOVETYPE_FLYMISSILE)
416 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent);
417 else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)
418 // only clip against bmodels
419 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent);
420 else
421 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
422
423 VectorCopy (trace.endpos, ent->v.origin);
424 SV_LinkEdict (ent, true);
425
426 if (trace.ent)
427 SV_Impact (ent, trace.ent);
428
429 return trace;
430}
431
432
433/*
434============
435SV_PushMove
436
437============
438*/
439void SV_PushMove (edict_t *pusher, float movetime)
440{
441 int i, e;
442 edict_t *check, *block;
443 vec3_t mins, maxs, move;
444 vec3_t entorig, pushorig;
445 int num_moved;
446 edict_t *moved_edict[MAX_EDICTS];
447 vec3_t moved_from[MAX_EDICTS];
448
449 if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2])
450 {
451 pusher->v.ltime += movetime;
452 return;
453 }
454
455 for (i=0 ; i<3 ; i++)
456 {
457 move[i] = pusher->v.velocity[i] * movetime;
458 mins[i] = pusher->v.absmin[i] + move[i];
459 maxs[i] = pusher->v.absmax[i] + move[i];
460 }
461
462 VectorCopy (pusher->v.origin, pushorig);
463
464// move the pusher to it's final position
465
466 VectorAdd (pusher->v.origin, move, pusher->v.origin);
467 pusher->v.ltime += movetime;
468 SV_LinkEdict (pusher, false);
469
470
471// see if any solid entities are inside the final position
472 num_moved = 0;
473 check = NEXT_EDICT(sv.edicts);
474 for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
475 {
476 if (check->free)
477 continue;
478 if (check->v.movetype == MOVETYPE_PUSH
479 || check->v.movetype == MOVETYPE_NONE
480#ifdef QUAKE2
481 || check->v.movetype == MOVETYPE_FOLLOW
482#endif
483 || check->v.movetype == MOVETYPE_NOCLIP)
484 continue;
485
486 // if the entity is standing on the pusher, it will definately be moved
487 if ( ! ( ((int)check->v.flags & FL_ONGROUND)
488 && PROG_TO_EDICT(check->v.groundentity) == pusher) )
489 {
490 if ( check->v.absmin[0] >= maxs[0]
491 || check->v.absmin[1] >= maxs[1]
492 || check->v.absmin[2] >= maxs[2]
493 || check->v.absmax[0] <= mins[0]
494 || check->v.absmax[1] <= mins[1]
495 || check->v.absmax[2] <= mins[2] )
496 continue;
497
498 // see if the ent's bbox is inside the pusher's final position
499 if (!SV_TestEntityPosition (check))
500 continue;
501 }
502
503 // remove the onground flag for non-players
504 if (check->v.movetype != MOVETYPE_WALK)
505 check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
506
507 VectorCopy (check->v.origin, entorig);
508 VectorCopy (check->v.origin, moved_from[num_moved]);
509 moved_edict[num_moved] = check;
510 num_moved++;
511
512 // try moving the contacted entity
513 pusher->v.solid = SOLID_NOT;
514 SV_PushEntity (check, move);
515 pusher->v.solid = SOLID_BSP;
516
517 // if it is still inside the pusher, block
518 block = SV_TestEntityPosition (check);
519 if (block)
520 { // fail the move
521 if (check->v.mins[0] == check->v.maxs[0])
522 continue;
523 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
524 { // corpse
525 check->v.mins[0] = check->v.mins[1] = 0;
526 VectorCopy (check->v.mins, check->v.maxs);
527 continue;
528 }
529
530 VectorCopy (entorig, check->v.origin);
531 SV_LinkEdict (check, true);
532
533 VectorCopy (pushorig, pusher->v.origin);
534 SV_LinkEdict (pusher, false);
535 pusher->v.ltime -= movetime;
536
537 // if the pusher has a "blocked" function, call it
538 // otherwise, just stay in place until the obstacle is gone
539 if (pusher->v.blocked)
540 {
541 pr_global_struct->self = EDICT_TO_PROG(pusher);
542 pr_global_struct->other = EDICT_TO_PROG(check);
543 PR_ExecuteProgram (pusher->v.blocked);
544 }
545
546 // move back any entities we already moved
547 for (i=0 ; i<num_moved ; i++)
548 {
549 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
550 SV_LinkEdict (moved_edict[i], false);
551 }
552 return;
553 }
554 }
555
556
557}
558
559#ifdef QUAKE2
560/*
561============
562SV_PushRotate
563
564============
565*/
566void SV_PushRotate (edict_t *pusher, float movetime)
567{
568 int i, e;
569 edict_t *check, *block;
570 vec3_t move, a, amove;
571 vec3_t entorig, pushorig;
572 int num_moved;
573 edict_t *moved_edict[MAX_EDICTS];
574 vec3_t moved_from[MAX_EDICTS];
575 vec3_t org, org2;
576 vec3_t forward, right, up;
577
578 if (!pusher->v.avelocity[0] && !pusher->v.avelocity[1] && !pusher->v.avelocity[2])
579 {
580 pusher->v.ltime += movetime;
581 return;
582 }
583
584 for (i=0 ; i<3 ; i++)
585 amove[i] = pusher->v.avelocity[i] * movetime;
586
587 VectorSubtract (vec3_origin, amove, a);
588 AngleVectors (a, forward, right, up);
589
590 VectorCopy (pusher->v.angles, pushorig);
591
592// move the pusher to it's final position
593
594 VectorAdd (pusher->v.angles, amove, pusher->v.angles);
595 pusher->v.ltime += movetime;
596 SV_LinkEdict (pusher, false);
597
598
599// see if any solid entities are inside the final position
600 num_moved = 0;
601 check = NEXT_EDICT(sv.edicts);
602 for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
603 {
604 if (check->free)
605 continue;
606 if (check->v.movetype == MOVETYPE_PUSH
607 || check->v.movetype == MOVETYPE_NONE
608 || check->v.movetype == MOVETYPE_FOLLOW
609 || check->v.movetype == MOVETYPE_NOCLIP)
610 continue;
611
612 // if the entity is standing on the pusher, it will definately be moved
613 if ( ! ( ((int)check->v.flags & FL_ONGROUND)
614 && PROG_TO_EDICT(check->v.groundentity) == pusher) )
615 {
616 if ( check->v.absmin[0] >= pusher->v.absmax[0]
617 || check->v.absmin[1] >= pusher->v.absmax[1]
618 || check->v.absmin[2] >= pusher->v.absmax[2]
619 || check->v.absmax[0] <= pusher->v.absmin[0]
620 || check->v.absmax[1] <= pusher->v.absmin[1]
621 || check->v.absmax[2] <= pusher->v.absmin[2] )
622 continue;
623
624 // see if the ent's bbox is inside the pusher's final position
625 if (!SV_TestEntityPosition (check))
626 continue;
627 }
628
629 // remove the onground flag for non-players
630 if (check->v.movetype != MOVETYPE_WALK)
631 check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
632
633 VectorCopy (check->v.origin, entorig);
634 VectorCopy (check->v.origin, moved_from[num_moved]);
635 moved_edict[num_moved] = check;
636 num_moved++;
637
638 // calculate destination position
639 VectorSubtract (check->v.origin, pusher->v.origin, org);
640 org2[0] = DotProduct (org, forward);
641 org2[1] = -DotProduct (org, right);
642 org2[2] = DotProduct (org, up);
643 VectorSubtract (org2, org, move);
644
645 // try moving the contacted entity
646 pusher->v.solid = SOLID_NOT;
647 SV_PushEntity (check, move);
648 pusher->v.solid = SOLID_BSP;
649
650 // if it is still inside the pusher, block
651 block = SV_TestEntityPosition (check);
652 if (block)
653 { // fail the move
654 if (check->v.mins[0] == check->v.maxs[0])
655 continue;
656 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
657 { // corpse
658 check->v.mins[0] = check->v.mins[1] = 0;
659 VectorCopy (check->v.mins, check->v.maxs);
660 continue;
661 }
662
663 VectorCopy (entorig, check->v.origin);
664 SV_LinkEdict (check, true);
665
666 VectorCopy (pushorig, pusher->v.angles);
667 SV_LinkEdict (pusher, false);
668 pusher->v.ltime -= movetime;
669
670 // if the pusher has a "blocked" function, call it
671 // otherwise, just stay in place until the obstacle is gone
672 if (pusher->v.blocked)
673 {
674 pr_global_struct->self = EDICT_TO_PROG(pusher);
675 pr_global_struct->other = EDICT_TO_PROG(check);
676 PR_ExecuteProgram (pusher->v.blocked);
677 }
678
679 // move back any entities we already moved
680 for (i=0 ; i<num_moved ; i++)
681 {
682 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
683 VectorSubtract (moved_edict[i]->v.angles, amove, moved_edict[i]->v.angles);
684 SV_LinkEdict (moved_edict[i], false);
685 }
686 return;
687 }
688 else
689 {
690 VectorAdd (check->v.angles, amove, check->v.angles);
691 }
692 }
693
694
695}
696#endif
697
698/*
699================
700SV_Physics_Pusher
701
702================
703*/
704void SV_Physics_Pusher (edict_t *ent)
705{
706 float thinktime;
707 float oldltime;
708 float movetime;
709
710 oldltime = ent->v.ltime;
711
712 thinktime = ent->v.nextthink;
713 if (thinktime < ent->v.ltime + host_frametime)
714 {
715 movetime = thinktime - ent->v.ltime;
716 if (movetime < 0)
717 movetime = 0;
718 }
719 else
720 movetime = host_frametime;
721
722 if (movetime)
723 {
724#ifdef QUAKE2
725 if (ent->v.avelocity[0] || ent->v.avelocity[1] || ent->v.avelocity[2])
726 SV_PushRotate (ent, movetime);
727 else
728#endif
729 SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked
730 }
731
732 if (thinktime > oldltime && thinktime <= ent->v.ltime)
733 {
734 ent->v.nextthink = 0;
735 pr_global_struct->time = sv.time;
736 pr_global_struct->self = EDICT_TO_PROG(ent);
737 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
738 PR_ExecuteProgram (ent->v.think);
739 if (ent->free)
740 return;
741 }
742
743}
744
745
746/*
747===============================================================================
748
749CLIENT MOVEMENT
750
751===============================================================================
752*/
753
754/*
755=============
756SV_CheckStuck
757
758This is a big hack to try and fix the rare case of getting stuck in the world
759clipping hull.
760=============
761*/
762void SV_CheckStuck (edict_t *ent)
763{
764 int i, j;
765 int z;
766 vec3_t org;
767
768 if (!SV_TestEntityPosition(ent))
769 {
770 VectorCopy (ent->v.origin, ent->v.oldorigin);
771 return;
772 }
773
774 VectorCopy (ent->v.origin, org);
775 VectorCopy (ent->v.oldorigin, ent->v.origin);
776 if (!SV_TestEntityPosition(ent))
777 {
778 Con_DPrintf ("Unstuck.\n");
779 SV_LinkEdict (ent, true);
780 return;
781 }
782
783 for (z=0 ; z< 18 ; z++)
784 for (i=-1 ; i <= 1 ; i++)
785 for (j=-1 ; j <= 1 ; j++)
786 {
787 ent->v.origin[0] = org[0] + i;
788 ent->v.origin[1] = org[1] + j;
789 ent->v.origin[2] = org[2] + z;
790 if (!SV_TestEntityPosition(ent))
791 {
792 Con_DPrintf ("Unstuck.\n");
793 SV_LinkEdict (ent, true);
794 return;
795 }
796 }
797
798 VectorCopy (org, ent->v.origin);
799 Con_DPrintf ("player is stuck.\n");
800}
801
802
803/*
804=============
805SV_CheckWater
806=============
807*/
808qboolean SV_CheckWater (edict_t *ent)
809{
810 vec3_t point;
811 int cont;
812#ifdef QUAKE2
813 int truecont;
814#endif
815
816 point[0] = ent->v.origin[0];
817 point[1] = ent->v.origin[1];
818 point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;
819
820 ent->v.waterlevel = 0;
821 ent->v.watertype = CONTENTS_EMPTY;
822 cont = SV_PointContents (point);
823 if (cont <= CONTENTS_WATER)
824 {
825#ifdef QUAKE2
826 truecont = SV_TruePointContents (point);
827#endif
828 ent->v.watertype = cont;
829 ent->v.waterlevel = 1;
830 point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5;
831 cont = SV_PointContents (point);
832 if (cont <= CONTENTS_WATER)
833 {
834 ent->v.waterlevel = 2;
835 point[2] = ent->v.origin[2] + ent->v.view_ofs[2];
836 cont = SV_PointContents (point);
837 if (cont <= CONTENTS_WATER)
838 ent->v.waterlevel = 3;
839 }
840#ifdef QUAKE2
841 if (truecont <= CONTENTS_CURRENT_0 && truecont >= CONTENTS_CURRENT_DOWN)
842 {
843 static vec3_t current_table[] =
844 {
845 {1, 0, 0},
846 {0, 1, 0},
847 {-1, 0, 0},
848 {0, -1, 0},
849 {0, 0, 1},
850 {0, 0, -1}
851 };
852
853 VectorMA (ent->v.basevelocity, 150.0*ent->v.waterlevel/3.0, current_table[CONTENTS_CURRENT_0 - truecont], ent->v.basevelocity);
854 }
855#endif
856 }
857
858 return ent->v.waterlevel > 1;
859}
860
861/*
862============
863SV_WallFriction
864
865============
866*/
867void SV_WallFriction (edict_t *ent, trace_t *trace)
868{
869 vec3_t forward, right, up;
870 float d, i;
871 vec3_t into, side;
872
873 AngleVectors (ent->v.v_angle, forward, right, up);
874 d = DotProduct (trace->plane.normal, forward);
875
876 d += 0.5;
877 if (d >= 0)
878 return;
879
880// cut the tangential velocity
881 i = DotProduct (trace->plane.normal, ent->v.velocity);
882 VectorScale (trace->plane.normal, i, into);
883 VectorSubtract (ent->v.velocity, into, side);
884
885 ent->v.velocity[0] = side[0] * (1 + d);
886 ent->v.velocity[1] = side[1] * (1 + d);
887}
888
889/*
890=====================
891SV_TryUnstick
892
893Player has come to a dead stop, possibly due to the problem with limited
894float precision at some angle joins in the BSP hull.
895
896Try fixing by pushing one pixel in each direction.
897
898This is a hack, but in the interest of good gameplay...
899======================
900*/
901int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
902{
903 int i;
904 vec3_t oldorg;
905 vec3_t dir;
906 int clip;
907 trace_t steptrace;
908
909 VectorCopy (ent->v.origin, oldorg);
910 VectorCopy (vec3_origin, dir);
911
912 for (i=0 ; i<8 ; i++)
913 {
914// try pushing a little in an axial direction
915 switch (i)
916 {
917 case 0: dir[0] = 2; dir[1] = 0; break;
918 case 1: dir[0] = 0; dir[1] = 2; break;
919 case 2: dir[0] = -2; dir[1] = 0; break;
920 case 3: dir[0] = 0; dir[1] = -2; break;
921 case 4: dir[0] = 2; dir[1] = 2; break;
922 case 5: dir[0] = -2; dir[1] = 2; break;
923 case 6: dir[0] = 2; dir[1] = -2; break;
924 case 7: dir[0] = -2; dir[1] = -2; break;
925 }
926
927 SV_PushEntity (ent, dir);
928
929// retry the original move
930 ent->v.velocity[0] = oldvel[0];
931 ent->v. velocity[1] = oldvel[1];
932 ent->v. velocity[2] = 0;
933 clip = SV_FlyMove (ent, 0.1, &steptrace);
934
935 if ( fabs(oldorg[1] - ent->v.origin[1]) > 4
936 || fabs(oldorg[0] - ent->v.origin[0]) > 4 )
937 {
938//Con_DPrintf ("unstuck!\n");
939 return clip;
940 }
941
942// go back to the original pos and try again
943 VectorCopy (oldorg, ent->v.origin);
944 }
945
946 VectorCopy (vec3_origin, ent->v.velocity);
947 return 7; // still not moving
948}
949
950/*
951=====================
952SV_WalkMove
953
954Only used by players
955======================
956*/
957#define STEPSIZE 18
958void SV_WalkMove (edict_t *ent)
959{
960 vec3_t upmove, downmove;
961 vec3_t oldorg, oldvel;
962 vec3_t nosteporg, nostepvel;
963 int clip;
964 int oldonground;
965 trace_t steptrace, downtrace;
966
967//
968// do a regular slide move unless it looks like you ran into a step
969//
970 oldonground = (int)ent->v.flags & FL_ONGROUND;
971 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
972
973 VectorCopy (ent->v.origin, oldorg);
974 VectorCopy (ent->v.velocity, oldvel);
975
976 clip = SV_FlyMove (ent, host_frametime, &steptrace);
977
978 if ( !(clip & 2) )
979 return; // move didn't block on a step
980
981 if (!oldonground && ent->v.waterlevel == 0)
982 return; // don't stair up while jumping
983
984 if (ent->v.movetype != MOVETYPE_WALK)
985 return; // gibbed by a trigger
986
987 if (sv_nostep.value)
988 return;
989
990 if ( (int)sv_player->v.flags & FL_WATERJUMP )
991 return;
992
993 VectorCopy (ent->v.origin, nosteporg);
994 VectorCopy (ent->v.velocity, nostepvel);
995
996//
997// try moving up and forward to go up a step
998//
999 VectorCopy (oldorg, ent->v.origin); // back to start pos
1000
1001 VectorCopy (vec3_origin, upmove);
1002 VectorCopy (vec3_origin, downmove);
1003 upmove[2] = STEPSIZE;
1004 downmove[2] = -STEPSIZE + oldvel[2]*host_frametime;
1005
1006// move up
1007 SV_PushEntity (ent, upmove); // FIXME: don't link?
1008
1009// move forward
1010 ent->v.velocity[0] = oldvel[0];
1011 ent->v. velocity[1] = oldvel[1];
1012 ent->v. velocity[2] = 0;
1013 clip = SV_FlyMove (ent, host_frametime, &steptrace);
1014
1015// check for stuckness, possibly due to the limited precision of floats
1016// in the clipping hulls
1017 if (clip)
1018 {
1019 if ( fabs(oldorg[1] - ent->v.origin[1]) < 0.03125
1020 && fabs(oldorg[0] - ent->v.origin[0]) < 0.03125 )
1021 { // stepping up didn't make any progress
1022 clip = SV_TryUnstick (ent, oldvel);
1023 }
1024 }
1025
1026// extra friction based on view angle
1027 if ( clip & 2 )
1028 SV_WallFriction (ent, &steptrace);
1029
1030// move down
1031 downtrace = SV_PushEntity (ent, downmove); // FIXME: don't link?
1032
1033 if (downtrace.plane.normal[2] > 0.7)
1034 {
1035 if (ent->v.solid == SOLID_BSP)
1036 {
1037 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1038 ent->v.groundentity = EDICT_TO_PROG(downtrace.ent);
1039 }
1040 }
1041 else
1042 {
1043// if the push down didn't end up on good ground, use the move without
1044// the step up. This happens near wall / slope combinations, and can
1045// cause the player to hop up higher on a slope too steep to climb
1046 VectorCopy (nosteporg, ent->v.origin);
1047 VectorCopy (nostepvel, ent->v.velocity);
1048 }
1049}
1050
1051
1052/*
1053================
1054SV_Physics_Client
1055
1056Player character actions
1057================
1058*/
1059void SV_Physics_Client (edict_t *ent, int num)
1060{
1061 if ( ! svs.clients[num-1].active )
1062 return; // unconnected slot
1063
1064//
1065// call standard client pre-think
1066//
1067 pr_global_struct->time = sv.time;
1068 pr_global_struct->self = EDICT_TO_PROG(ent);
1069 PR_ExecuteProgram (pr_global_struct->PlayerPreThink);
1070
1071//
1072// do a move
1073//
1074 SV_CheckVelocity (ent);
1075
1076//
1077// decide which move function to call
1078//
1079 switch ((int)ent->v.movetype)
1080 {
1081 case MOVETYPE_NONE:
1082 if (!SV_RunThink (ent))
1083 return;
1084 break;
1085
1086 case MOVETYPE_WALK:
1087 if (!SV_RunThink (ent))
1088 return;
1089 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1090 SV_AddGravity (ent);
1091 SV_CheckStuck (ent);
1092#ifdef QUAKE2
1093 VectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);
1094#endif
1095 SV_WalkMove (ent);
1096
1097#ifdef QUAKE2
1098 VectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);
1099#endif
1100 break;
1101
1102 case MOVETYPE_TOSS:
1103 case MOVETYPE_BOUNCE:
1104 SV_Physics_Toss (ent);
1105 break;
1106
1107 case MOVETYPE_FLY:
1108 if (!SV_RunThink (ent))
1109 return;
1110 SV_FlyMove (ent, host_frametime, NULL);
1111 break;
1112
1113 case MOVETYPE_NOCLIP:
1114 if (!SV_RunThink (ent))
1115 return;
1116 VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
1117 break;
1118
1119 default:
1120 Sys_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
1121 }
1122
1123//
1124// call standard player post-think
1125//
1126 SV_LinkEdict (ent, true);
1127
1128 pr_global_struct->time = sv.time;
1129 pr_global_struct->self = EDICT_TO_PROG(ent);
1130 PR_ExecuteProgram (pr_global_struct->PlayerPostThink);
1131}
1132
1133//============================================================================
1134
1135/*
1136=============
1137SV_Physics_None
1138
1139Non moving objects can only think
1140=============
1141*/
1142void SV_Physics_None (edict_t *ent)
1143{
1144// regular thinking
1145 SV_RunThink (ent);
1146}
1147
1148#ifdef QUAKE2
1149/*
1150=============
1151SV_Physics_Follow
1152
1153Entities that are "stuck" to another entity
1154=============
1155*/
1156void SV_Physics_Follow (edict_t *ent)
1157{
1158// regular thinking
1159 SV_RunThink (ent);
1160 VectorAdd (PROG_TO_EDICT(ent->v.aiment)->v.origin, ent->v.v_angle, ent->v.origin);
1161 SV_LinkEdict (ent, true);
1162}
1163#endif
1164
1165/*
1166=============
1167SV_Physics_Noclip
1168
1169A moving object that doesn't obey physics
1170=============
1171*/
1172void SV_Physics_Noclip (edict_t *ent)
1173{
1174// regular thinking
1175 if (!SV_RunThink (ent))
1176 return;
1177
1178 VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
1179 VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
1180
1181 SV_LinkEdict (ent, false);
1182}
1183
1184/*
1185==============================================================================
1186
1187TOSS / BOUNCE
1188
1189==============================================================================
1190*/
1191
1192/*
1193=============
1194SV_CheckWaterTransition
1195
1196=============
1197*/
1198void SV_CheckWaterTransition (edict_t *ent)
1199{
1200 int cont;
1201#ifdef QUAKE2
1202 vec3_t point;
1203
1204 point[0] = ent->v.origin[0];
1205 point[1] = ent->v.origin[1];
1206 point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;
1207 cont = SV_PointContents (point);
1208#else
1209 cont = SV_PointContents (ent->v.origin);
1210#endif
1211 if (!ent->v.watertype)
1212 { // just spawned here
1213 ent->v.watertype = cont;
1214 ent->v.waterlevel = 1;
1215 return;
1216 }
1217
1218 if (cont <= CONTENTS_WATER)
1219 {
1220 if (ent->v.watertype == CONTENTS_EMPTY)
1221 { // just crossed into water
1222 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1223 }
1224 ent->v.watertype = cont;
1225 ent->v.waterlevel = 1;
1226 }
1227 else
1228 {
1229 if (ent->v.watertype != CONTENTS_EMPTY)
1230 { // just crossed into water
1231 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1232 }
1233 ent->v.watertype = CONTENTS_EMPTY;
1234 ent->v.waterlevel = cont;
1235 }
1236}
1237
1238/*
1239=============
1240SV_Physics_Toss
1241
1242Toss, bounce, and fly movement. When onground, do nothing.
1243=============
1244*/
1245void SV_Physics_Toss (edict_t *ent)
1246{
1247 trace_t trace;
1248 vec3_t move;
1249 float backoff;
1250#ifdef QUAKE2
1251 edict_t *groundentity;
1252
1253 groundentity = PROG_TO_EDICT(ent->v.groundentity);
1254 if ((int)groundentity->v.flags & FL_CONVEYOR)
1255 VectorScale(groundentity->v.movedir, groundentity->v.speed, ent->v.basevelocity);
1256 else
1257 VectorCopy(vec_origin, ent->v.basevelocity);
1258 SV_CheckWater (ent);
1259#endif
1260 // regular thinking
1261 if (!SV_RunThink (ent))
1262 return;
1263
1264#ifdef QUAKE2
1265 if (ent->v.velocity[2] > 0)
1266 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1267
1268 if ( ((int)ent->v.flags & FL_ONGROUND) )
1269//@@
1270 if (VectorCompare(ent->v.basevelocity, vec_origin))
1271 return;
1272
1273 SV_CheckVelocity (ent);
1274
1275// add gravity
1276 if (! ((int)ent->v.flags & FL_ONGROUND)
1277 && ent->v.movetype != MOVETYPE_FLY
1278 && ent->v.movetype != MOVETYPE_BOUNCEMISSILE
1279 && ent->v.movetype != MOVETYPE_FLYMISSILE)
1280 SV_AddGravity (ent);
1281
1282#else
1283// if onground, return without moving
1284 if ( ((int)ent->v.flags & FL_ONGROUND) )
1285 return;
1286
1287 SV_CheckVelocity (ent);
1288
1289// add gravity
1290 if (ent->v.movetype != MOVETYPE_FLY
1291 && ent->v.movetype != MOVETYPE_FLYMISSILE)
1292 SV_AddGravity (ent);
1293#endif
1294
1295// move angles
1296 VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
1297
1298// move origin
1299#ifdef QUAKE2
1300 VectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);
1301#endif
1302 VectorScale (ent->v.velocity, host_frametime, move);
1303 trace = SV_PushEntity (ent, move);
1304#ifdef QUAKE2
1305 VectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);
1306#endif
1307 if (trace.fraction == 1)
1308 return;
1309 if (ent->free)
1310 return;
1311
1312 if (ent->v.movetype == MOVETYPE_BOUNCE)
1313 backoff = 1.5;
1314#ifdef QUAKE2
1315 else if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)
1316 backoff = 2.0;
1317#endif
1318 else
1319 backoff = 1;
1320
1321 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff);
1322
1323// stop if on ground
1324 if (trace.plane.normal[2] > 0.7)
1325 {
1326#ifdef QUAKE2
1327 if (ent->v.velocity[2] < 60 || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE))
1328#else
1329 if (ent->v.velocity[2] < 60 || ent->v.movetype != MOVETYPE_BOUNCE)
1330#endif
1331 {
1332 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1333 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1334 VectorCopy (vec3_origin, ent->v.velocity);
1335 VectorCopy (vec3_origin, ent->v.avelocity);
1336 }
1337 }
1338
1339// check for in water
1340 SV_CheckWaterTransition (ent);
1341}
1342
1343/*
1344===============================================================================
1345
1346STEPPING MOVEMENT
1347
1348===============================================================================
1349*/
1350
1351/*
1352=============
1353SV_Physics_Step
1354
1355Monsters freefall when they don't have a ground entity, otherwise
1356all movement is done with discrete steps.
1357
1358This is also used for objects that have become still on the ground, but
1359will fall if the floor is pulled out from under them.
1360=============
1361*/
1362#ifdef QUAKE2
1363void SV_Physics_Step (edict_t *ent)
1364{
1365 qboolean wasonground;
1366 qboolean inwater;
1367 qboolean hitsound = false;
1368 float *vel;
1369 float speed, newspeed, control;
1370 float friction;
1371 edict_t *groundentity;
1372
1373 groundentity = PROG_TO_EDICT(ent->v.groundentity);
1374 if ((int)groundentity->v.flags & FL_CONVEYOR)
1375 VectorScale(groundentity->v.movedir, groundentity->v.speed, ent->v.basevelocity);
1376 else
1377 VectorCopy(vec_origin, ent->v.basevelocity);
1378//@@
1379 pr_global_struct->time = sv.time;
1380 pr_global_struct->self = EDICT_TO_PROG(ent);
1381 PF_WaterMove();
1382
1383 SV_CheckVelocity (ent);
1384
1385 wasonground = (int)ent->v.flags & FL_ONGROUND;
1386// ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1387
1388 // add gravity except:
1389 // flying monsters
1390 // swimming monsters who are in the water
1391 inwater = SV_CheckWater(ent);
1392 if (! wasonground)
1393 if (!((int)ent->v.flags & FL_FLY))
1394 if (!(((int)ent->v.flags & FL_SWIM) && (ent->v.waterlevel > 0)))
1395 {
1396 if (ent->v.velocity[2] < sv_gravity.value*-0.1)
1397 hitsound = true;
1398 if (!inwater)
1399 SV_AddGravity (ent);
1400 }
1401
1402 if (!VectorCompare(ent->v.velocity, vec_origin) || !VectorCompare(ent->v.basevelocity, vec_origin))
1403 {
1404 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1405 // apply friction
1406 // let dead monsters who aren't completely onground slide
1407 if (wasonground)
1408 if (!(ent->v.health <= 0.0 && !SV_CheckBottom(ent)))
1409 {
1410 vel = ent->v.velocity;
1411 speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);
1412 if (speed)
1413 {
1414 friction = sv_friction.value;
1415
1416 control = speed < sv_stopspeed.value ? sv_stopspeed.value : speed;
1417 newspeed = speed - host_frametime*control*friction;
1418
1419 if (newspeed < 0)
1420 newspeed = 0;
1421 newspeed /= speed;
1422
1423 vel[0] = vel[0] * newspeed;
1424 vel[1] = vel[1] * newspeed;
1425 }
1426 }
1427
1428 VectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);
1429 SV_FlyMove (ent, host_frametime, NULL);
1430 VectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);
1431
1432 // determine if it's on solid ground at all
1433 {
1434 vec3_t mins, maxs, point;
1435 int x, y;
1436
1437 VectorAdd (ent->v.origin, ent->v.mins, mins);
1438 VectorAdd (ent->v.origin, ent->v.maxs, maxs);
1439
1440 point[2] = mins[2] - 1;
1441 for (x=0 ; x<=1 ; x++)
1442 for (y=0 ; y<=1 ; y++)
1443 {
1444 point[0] = x ? maxs[0] : mins[0];
1445 point[1] = y ? maxs[1] : mins[1];
1446 if (SV_PointContents (point) == CONTENTS_SOLID)
1447 {
1448 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1449 break;
1450 }
1451 }
1452
1453 }
1454
1455 SV_LinkEdict (ent, true);
1456
1457 if ((int)ent->v.flags & FL_ONGROUND)
1458 if (!wasonground)
1459 if (hitsound)
1460 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1461 }
1462
1463// regular thinking
1464 SV_RunThink (ent);
1465 SV_CheckWaterTransition (ent);
1466}
1467#else
1468void SV_Physics_Step (edict_t *ent)
1469{
1470 qboolean hitsound;
1471
1472// freefall if not onground
1473 if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) )
1474 {
1475 if (ent->v.velocity[2] < sv_gravity.value*-0.1)
1476 hitsound = true;
1477 else
1478 hitsound = false;
1479
1480 SV_AddGravity (ent);
1481 SV_CheckVelocity (ent);
1482 SV_FlyMove (ent, host_frametime, NULL);
1483 SV_LinkEdict (ent, true);
1484
1485 if ( (int)ent->v.flags & FL_ONGROUND ) // just hit ground
1486 {
1487 if (hitsound)
1488 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1489 }
1490 }
1491
1492// regular thinking
1493 SV_RunThink (ent);
1494
1495 SV_CheckWaterTransition (ent);
1496}
1497#endif
1498
1499//============================================================================
1500
1501/*
1502================
1503SV_Physics
1504
1505================
1506*/
1507void SV_Physics (void)
1508{
1509 int i;
1510 edict_t *ent;
1511
1512// let the progs know that a new frame has started
1513 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1514 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1515 pr_global_struct->time = sv.time;
1516 PR_ExecuteProgram (pr_global_struct->StartFrame);
1517
1518//SV_CheckAllEnts ();
1519
1520//
1521// treat each object in turn
1522//
1523 ent = sv.edicts;
1524 for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1525 {
1526 if (ent->free)
1527 continue;
1528
1529 if (pr_global_struct->force_retouch)
1530 {
1531 SV_LinkEdict (ent, true); // force retouch even for stationary
1532 }
1533
1534 if (i > 0 && i <= svs.maxclients)
1535 SV_Physics_Client (ent, i);
1536 else if (ent->v.movetype == MOVETYPE_PUSH)
1537 SV_Physics_Pusher (ent);
1538 else if (ent->v.movetype == MOVETYPE_NONE)
1539 SV_Physics_None (ent);
1540#ifdef QUAKE2
1541 else if (ent->v.movetype == MOVETYPE_FOLLOW)
1542 SV_Physics_Follow (ent);
1543#endif
1544 else if (ent->v.movetype == MOVETYPE_NOCLIP)
1545 SV_Physics_Noclip (ent);
1546 else if (ent->v.movetype == MOVETYPE_STEP)
1547 SV_Physics_Step (ent);
1548 else if (ent->v.movetype == MOVETYPE_TOSS
1549 || ent->v.movetype == MOVETYPE_BOUNCE
1550#ifdef QUAKE2
1551 || ent->v.movetype == MOVETYPE_BOUNCEMISSILE
1552#endif
1553 || ent->v.movetype == MOVETYPE_FLY
1554 || ent->v.movetype == MOVETYPE_FLYMISSILE)
1555 SV_Physics_Toss (ent);
1556 else
1557 Sys_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
1558 }
1559
1560 if (pr_global_struct->force_retouch)
1561 pr_global_struct->force_retouch--;
1562
1563 sv.time += host_frametime;
1564}
1565
1566
1567#ifdef QUAKE2
1568trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore)
1569{
1570 edict_t tempent, *tent;
1571 trace_t trace;
1572 vec3_t move;
1573 vec3_t end;
1574 double save_frametime;
1575// extern particle_t *active_particles, *free_particles;
1576// particle_t *p;
1577
1578
1579 save_frametime = host_frametime;
1580 host_frametime = 0.05;
1581
1582 memcpy(&tempent, ent, sizeof(edict_t));
1583 tent = &tempent;
1584
1585 while (1)
1586 {
1587 SV_CheckVelocity (tent);
1588 SV_AddGravity (tent);
1589 VectorMA (tent->v.angles, host_frametime, tent->v.avelocity, tent->v.angles);
1590 VectorScale (tent->v.velocity, host_frametime, move);
1591 VectorAdd (tent->v.origin, move, end);
1592 trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent);
1593 VectorCopy (trace.endpos, tent->v.origin);
1594
1595// p = free_particles;
1596// if (p)
1597// {
1598// free_particles = p->next;
1599// p->next = active_particles;
1600// active_particles = p;
1601//
1602// p->die = 256;
1603// p->color = 15;
1604// p->type = pt_static;
1605// VectorCopy (vec3_origin, p->vel);
1606// VectorCopy (tent->v.origin, p->org);
1607// }
1608
1609 if (trace.ent)
1610 if (trace.ent != ignore)
1611 break;
1612 }
1613// p->color = 224;
1614 host_frametime = save_frametime;
1615 return trace;
1616}
1617#endif