]> icculus.org git repositories - divverent/nexuiz.git/blob - TeamNexuiz/game/gamec/bot_phys.c
Added a Game C folder
[divverent/nexuiz.git] / TeamNexuiz / game / gamec / bot_phys.c
1 /***********************************************\r
2 *                                              *\r
3 *                FrikBot Physics               *\r
4 *        The near-perfect emulation of         *\r
5 *                Client movement               *\r
6 *                                              *\r
7 *         Special Thanks to: Asdf, Frog        *\r
8 *             Alan "Strider" Kivlin            *\r
9 *                                              *\r
10 *                                              *\r
11 ***********************************************/\r
12 \r
13 /*\r
14 \r
15 This program is in the Public Domain. My crack legal\r
16 team would like to add:\r
17 \r
18 RYAN "FRIKAC" SMITH IS PROVIDING THIS SOFTWARE "AS IS"\r
19 AND MAKES NO WARRANTY, EXPRESS OR IMPLIED, AS TO THE\r
20 ACCURACY, CAPABILITY, EFFICIENCY, MERCHANTABILITY, OR\r
21 FUNCTIONING OF THIS SOFTWARE AND/OR DOCUMENTATION. IN\r
22 NO EVENT WILL RYAN "FRIKAC" SMITH BE LIABLE FOR ANY\r
23 GENERAL, CONSEQUENTIAL, INDIRECT, INCIDENTAL,\r
24 EXEMPLARY, OR SPECIAL DAMAGES, EVEN IF RYAN "FRIKAC"\r
25 SMITH HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH\r
26 DAMAGES, IRRESPECTIVE OF THE CAUSE OF SUCH DAMAGES.\r
27 \r
28 You accept this software on the condition that you\r
29 indemnify and hold harmless Ryan "FrikaC" Smith from\r
30 any and all liability or damages to third parties,\r
31 including attorney fees, court costs, and other\r
32 related costs and expenses, arising out of your use\r
33 of this software irrespective of the cause of said\r
34 liability.\r
35 \r
36 The export from the United States or the subsequent\r
37 reexport of this software is subject to compliance\r
38 with United States export control and munitions\r
39 control restrictions. You agree that in the event you\r
40 seek to export this software, you assume full\r
41 responsibility for obtaining all necessary export\r
42 licenses and approvals and for assuring compliance\r
43 with applicable reexport restrictions.\r
44 \r
45 Any reproduction of this software must contain\r
46 this notice in its entirety.\r
47 \r
48 */\r
49 \r
50 /*\r
51 =========================================\r
52 \r
53 Stuff mimicking cl_input.c code\r
54 \r
55 =========================================\r
56 */\r
57 float(float key) CL_KeyState =\r
58 {\r
59         return ((self.keys & key) > 0);\r
60 };\r
61 \r
62 void() CL_KeyMove = // CL_BaseMove + CL_AdjustAngles\r
63 {\r
64         local float anglespeed;\r
65         local vector view;\r
66         if (self.keys != self.oldkeys)\r
67         {\r
68                 self.movement = '0 0 0';\r
69                 self.movement_y = self.movement_y + (350 * CL_KeyState(KEY_MOVERIGHT));\r
70                 // 350 is the default cl_sidespeed\r
71                 self.movement_y = self.movement_y - (350 * CL_KeyState(KEY_MOVELEFT));\r
72                 // 350 is the default cl_sidespeed\r
73                 self.movement_x = self.movement_x + (200 * CL_KeyState(KEY_MOVEFORWARD));\r
74                 // 200 is the default cl_forwardspeed\r
75                 self.movement_x = self.movement_x - (200 * CL_KeyState(KEY_MOVEBACK));\r
76                 // 200 is the default cl_backspeed\r
77                 self.movement_z = self.movement_z + (200 * CL_KeyState(KEY_MOVEUP));\r
78                 // 200 is the default cl_upspeed\r
79                 self.movement_z = self.movement_z - (200 * CL_KeyState(KEY_MOVEDOWN));\r
80                 // 200 is the default cl_upspeed\r
81                 if (!self.b_aiflags & AI_PRECISION)\r
82                         self.movement = self.movement * 2;\r
83                 // 2 is the default cl_movespeedkey & bot always has +speed\r
84         }\r
85         self.oldkeys = self.keys;\r
86 \r
87         if (self.b_skill != 2) // use mouse emulation\r
88         {\r
89                 anglespeed = 1.5 * real_frametime;\r
90                 // 1.5 is the default cl_anglespeedkey & bot always has +speed\r
91                 self.v_angle_y = self.v_angle_y + anglespeed * CL_KeyState(KEY_LOOKLEFT) * 140;\r
92                 // 140 is default cl_yawspeed\r
93                 self.v_angle_y = self.v_angle_y - anglespeed * CL_KeyState(KEY_LOOKRIGHT) * 140;\r
94                 // 140 is default cl_yawspeed\r
95                 self.v_angle_x = self.v_angle_x - anglespeed * CL_KeyState(KEY_LOOKUP) * 150;\r
96                 // 150 is default cl_pitchspeed\r
97                 self.v_angle_x = self.v_angle_x + anglespeed * CL_KeyState(KEY_LOOKDOWN) * 150;\r
98                 // 150 is default cl_pitchspeed\r
99         }\r
100         else\r
101         {\r
102                 view_x = angcomp(self.b_angle_x, self.v_angle_x);\r
103                 view_y = angcomp(self.b_angle_y, self.v_angle_y);\r
104                 if (vlen(view) > 30)\r
105                 {\r
106                         self.mouse_emu = self.mouse_emu + (view * 30);\r
107                         if (vlen(self.mouse_emu) > 180)\r
108                                 self.mouse_emu = normalize(self.mouse_emu) * 180;\r
109                 }\r
110                 else\r
111                         self.mouse_emu = view * (1 / real_frametime);\r
112                 self.v_angle = self.v_angle + self.mouse_emu * real_frametime;\r
113 \r
114 \r
115         }\r
116         if (self.v_angle_x > 80)\r
117                 self.v_angle_x = 80;\r
118         else if (self.v_angle_x < -70)\r
119                 self.v_angle_x = -70;\r
120 \r
121         if (self.v_angle_z > 50)\r
122                 self.v_angle_z = 50;\r
123         else if (self.v_angle_z < -50)\r
124                 self.v_angle_z = -50;\r
125         self.v_angle_y = frik_anglemod(self.v_angle_y);\r
126 \r
127 };\r
128 \r
129 /*\r
130 =========================================\r
131 \r
132 Stuff mimicking sv_user.c\r
133 \r
134 =========================================\r
135 */\r
136 void() SV_UserFriction =\r
137 {\r
138         local vector vel;\r
139         local float sped, friction, newspeed;\r
140 \r
141       vel = self.velocity;\r
142         vel_z =0;\r
143         sped = vlen(vel);\r
144         vel = self.velocity;\r
145 \r
146         if (!sped)\r
147                 return;\r
148 \r
149     friction = sv_friction;\r
150      if (sped < sv_stopspeed)\r
151                 newspeed = sped - real_frametime * sv_stopspeed * friction;\r
152         else\r
153                 newspeed = sped - real_frametime * sped * friction;\r
154 \r
155         if (newspeed < 0)\r
156                 newspeed = 0;\r
157         newspeed = newspeed / sped;\r
158 \r
159         self.velocity_y = vel_y * newspeed;\r
160         self.velocity_x = vel_x * newspeed;\r
161 };\r
162 void() SV_WaterJump =\r
163 {\r
164         if (time > self.teleport_time || !self.waterlevel)\r
165         {\r
166                 self.flags = self.flags - (self.flags & FL_WATERJUMP);\r
167                 self.teleport_time = 0;\r
168         }\r
169         self.velocity_x = self.movedir_x;\r
170         self.velocity_y = self.movedir_y;\r
171 };\r
172 \r
173 void() DropPunchAngle =\r
174 {\r
175         local float len;\r
176         len = vlen(self.punchangle);\r
177         self.punchangle = normalize(self.punchangle);\r
178         len = len - 10 * real_frametime;\r
179         if (len < 0)\r
180                 len = 0;\r
181         self.punchangle = self.punchangle * len;\r
182 };\r
183 \r
184 \r
185 void(vector wishvel) SV_AirAccelerate =\r
186 {\r
187         local float addspeed, wishspd, accelspeed, currentspeed;\r
188 \r
189         wishspd = vlen(wishvel);\r
190         wishvel = normalize(wishvel);\r
191         if (wishspd > 30)\r
192                 wishspd = 30;\r
193         currentspeed = self.velocity * wishvel;\r
194         addspeed = wishspd - currentspeed;\r
195         if (addspeed <= 0)\r
196                 return;\r
197         accelspeed = 10 * sv_accelerate * wishspd * real_frametime;\r
198         if (accelspeed > addspeed)\r
199                 accelspeed = addspeed;\r
200 \r
201         self.velocity = self.velocity + accelspeed * wishvel;\r
202 };\r
203 \r
204 void(vector wishvel) SV_Accelerate =\r
205 {\r
206         local float addspeed, wishspd, accelspeed, currentspeed;\r
207 \r
208         wishspd = vlen(wishvel);\r
209         wishvel = normalize(wishvel);\r
210 \r
211         currentspeed = self.velocity * wishvel;\r
212         addspeed = wishspd - currentspeed;\r
213         if (addspeed <= 0)\r
214                 return;\r
215         accelspeed = sv_accelerate * wishspd * real_frametime;\r
216         if (accelspeed > addspeed)\r
217                 accelspeed = addspeed;\r
218 \r
219         self.velocity = self.velocity + accelspeed * wishvel;\r
220 };\r
221 void() SV_WaterMove =\r
222 {\r
223         local vector wishvel;\r
224         local float wishspeed, addspeed, cspeed, newspeed;\r
225         makevectors(self.v_angle);\r
226         wishvel = v_right * self.movement_y + v_forward * self.movement_x;\r
227 \r
228         if (self.movement == '0 0 0')\r
229                 wishvel_z = wishvel_z - 60;\r
230         else\r
231                 wishvel_z = wishvel_z + self.movement_z;\r
232         wishspeed = vlen(wishvel);\r
233 \r
234         if (wishspeed > sv_maxspeed)\r
235         {\r
236                 wishvel = (sv_maxspeed / wishspeed) * wishvel;\r
237                 wishspeed = sv_maxspeed;\r
238         }\r
239         wishspeed = wishspeed * 0.7;\r
240         cspeed = vlen(self.velocity);\r
241         if (cspeed)\r
242         {\r
243                 newspeed = cspeed - (real_frametime * cspeed * sv_friction);\r
244                 if (newspeed < 0)\r
245                         newspeed = 0;\r
246                self.velocity = self.velocity * (newspeed / cspeed);\r
247 \r
248         }\r
249         else\r
250                 newspeed = 0;\r
251 \r
252         if (!wishspeed)\r
253                 return;\r
254         addspeed = wishspeed - newspeed;\r
255         if (addspeed <= 0)\r
256                 return;\r
257         wishvel = normalize(wishvel);\r
258         cspeed = sv_accelerate * wishspeed * real_frametime;\r
259         if (cspeed > addspeed)\r
260                 cspeed = addspeed;\r
261         self.velocity = self.velocity + cspeed * wishvel;\r
262 };\r
263 void() SV_AirMove =\r
264 {\r
265         local vector wishvel, vangle;\r
266 \r
267         vangle = self.v_angle;\r
268         vangle_x = vangle_z = 0;\r
269         makevectors(vangle);\r
270         if (time < self.teleport_time && (self.movement_x < 0))\r
271                 self.movement_x = 0;\r
272         wishvel = v_right * self.movement_y + v_forward * self.movement_x;\r
273 \r
274 \r
275         if (self.movetype != MOVETYPE_WALK)\r
276                 wishvel_z = self.movement_z;\r
277         else\r
278                 wishvel_z = 0;\r
279         if (vlen(wishvel) > sv_maxspeed)\r
280                 wishvel = normalize(wishvel) * sv_maxspeed;\r
281         if (self.movetype == MOVETYPE_NOCLIP)\r
282                 self.velocity = wishvel;\r
283         else if (self.flags & FL_ONGROUND)\r
284         {\r
285                 SV_UserFriction();\r
286                 SV_Accelerate(wishvel);\r
287         }\r
288         else\r
289                 SV_AirAccelerate (wishvel);\r
290 };\r
291 \r
292 void() SV_ClientThink =\r
293 {\r
294         local vector vangle;\r
295 \r
296         if (self.movetype == MOVETYPE_NONE)\r
297                 return;\r
298         DropPunchAngle();\r
299         if (self.health <= 0)\r
300                 return;\r
301         self.v_angle_z = 0; // V_CalcRoll removed, sucks\r
302         self.angles_z = self.v_angle_z * 4;\r
303         vangle = self.v_angle + self.punchangle;\r
304         if (!self.fixangle)\r
305         {\r
306                 self.angles_x = (vangle_x / -3);\r
307                 self.angles_y = vangle_y;\r
308         } else\r
309         {\r
310                 self.v_angle = self.angles;\r
311                 self.fixangle = 0;\r
312         }\r
313         if (self.flags & FL_WATERJUMP)\r
314         {\r
315                 SV_WaterJump();\r
316                 return;\r
317         }\r
318         if ((self.waterlevel >= 2) && (self.movetype != MOVETYPE_NOCLIP))\r
319         {\r
320                 SV_WaterMove();\r
321                 return;\r
322         }\r
323         SV_AirMove();\r
324 \r
325 };\r
326 /*\r
327 =========================================\r
328 \r
329 Stuff mimicking sv_phys.c\r
330 \r
331 =========================================\r
332 */\r
333 \r
334 float() SV_RunThink  =\r
335 {\r
336         local float thinktime, bkuptime;\r
337         thinktime = self.nextthink;\r
338         bkuptime = time;\r
339         if (thinktime <= 0 || thinktime > (time + real_frametime))\r
340                 return TRUE;\r
341         if (thinktime < time)\r
342                 thinktime = time;\r
343         self.nextthink = 0;\r
344         time = thinktime;\r
345         other = world;\r
346         makevectors(self.v_angle); // hack\r
347         self.think();\r
348         time = bkuptime;\r
349         return TRUE;\r
350 };\r
351 \r
352 void(float scal) SV_AddGravity =\r
353 {\r
354         self.velocity_z = self.velocity_z - (scal * sv_gravity * real_frametime);\r
355 };\r
356 \r
357 float() SV_CheckWater =\r
358 {\r
359         local vector point;\r
360         local float cont;\r
361 \r
362         point_x = self.origin_x;\r
363         point_y = self.origin_y;\r
364         self.waterlevel = 0;\r
365         self.watertype = CONTENT_EMPTY;\r
366         point_z = self.origin_z + self.mins_z + 1;\r
367         cont = pointcontents(point);\r
368         if (cont <= CONTENT_WATER)\r
369         {\r
370                 self.watertype = cont;\r
371                 self.waterlevel = 1;\r
372                 point_z = self.origin_z + (self.mins_z + self.maxs_z) * 0.5;\r
373                 cont = pointcontents(point);\r
374                 if (cont <= CONTENT_WATER)\r
375                 {\r
376                         self.waterlevel = 2;\r
377                         point_z = self.origin_z + self.view_ofs_z;\r
378                         cont = pointcontents(point);\r
379                         if (cont <= CONTENT_WATER)\r
380                                 self.waterlevel = 3;\r
381                 }\r
382         }\r
383         return (self.waterlevel > 1);\r
384 \r
385 };\r
386 void() RemoveThud = // well sometimes\r
387 {\r
388         local entity oself;\r
389         if (other == world)\r
390         {\r
391                 if (self.flags & FL_ONGROUND)\r
392                 {\r
393                         self.flags = self.flags - FL_ONGROUND;\r
394                 }\r
395         }\r
396         else\r
397         {\r
398                 if (other.solid == SOLID_BSP && (self.flags & FL_ONGROUND))\r
399                 {\r
400                         // RM: Does this break anything?\r
401                         // If not, then some more thuds have been removed.\r
402                         self.flags = self.flags - FL_ONGROUND;\r
403                 }\r
404                 if (other == self.owner)\r
405                         return;\r
406                 if (self.owner.solid == SOLID_NOT)\r
407                         return;\r
408                 oself = other;\r
409                 other = self.owner;\r
410                 self = oself;\r
411                 if (self.solid == SOLID_BSP)\r
412                         if (self.touch)\r
413                                 self.touch();\r
414         }\r
415 \r
416 };\r
417 void() SV_CheckOnGround =\r
418 {\r
419         local vector org, v;\r
420         org = self.origin;\r
421         local float currentflags;\r
422         currentflags = self.flags;\r
423         self.flags = self.flags | FL_ONGROUND | FL_PARTIALGROUND;\r
424         walkmove(0,0); // perform C touch function\r
425         self.flags = currentflags | FL_ONGROUND;\r
426         if ((org_x != self.origin_x) || (org_y != self.origin_y))\r
427                 org = self.origin;\r
428         else\r
429                 self.origin = org;\r
430         v = org;\r
431         v_z = self.maxs_z + org_z + 1;\r
432         traceline (org, v, TRUE, self);\r
433         if ((self.waterlevel == 3) && (self.movetype == MOVETYPE_WALK))\r
434                 self.flags = self.flags - FL_ONGROUND;\r
435         else if ((trace_plane_normal_z <= 0.7) && (trace_fraction != 1))\r
436                 self.flags = self.flags - FL_ONGROUND;\r
437         else if (!droptofloor(0,0))\r
438                 self.flags = self.flags - FL_ONGROUND;\r
439         else if (org_z - self.origin_z < 2)\r
440                 self.flags = self.flags | FL_ONGROUND;\r
441         else\r
442                 self.flags = self.flags - FL_ONGROUND;\r
443         setorigin(self, org);\r
444 };\r
445 // Thanks to Alan Kivlin for this function\r
446 // modified heavily by me\r
447 float(vector dir) botCheckForStep =\r
448 {\r
449         local vector currentorigin, v;\r
450         local float currentflags, yaw, stepdistance, movedistance;\r
451         currentorigin = self.origin;\r
452         currentflags = self.flags;\r
453         self.flags = FL_ONGROUND | FL_PARTIALGROUND;\r
454         dir = normalize(dir);\r
455         dir_z = 0;\r
456         yaw = vectoyaw(dir);\r
457         if(walkmove(yaw, 3))\r
458         {\r
459                 if(droptofloor(0,0))\r
460                 {\r
461                         stepdistance = self.origin_z - currentorigin_z;\r
462                         v = self.origin - currentorigin;\r
463                         v_z = 0;\r
464                         movedistance = vlen(v);\r
465                         if((stepdistance > 0 && stepdistance <= 16) && movedistance != 0)\r
466                         {\r
467                                 self.flags = currentflags | FL_PARTIALGROUND;\r
468                                 return 1;\r
469                         }\r
470                 }\r
471         }\r
472         self.flags = currentflags;\r
473         setorigin(self, currentorigin);\r
474         return 0;\r
475 };\r
476 // this is merely here to fix a problem with e3m5\r
477 void(vector dir) BruteForceStep =\r
478 {\r
479         local vector currentorigin;\r
480         local float currentflags, i, len;\r
481 \r
482         currentorigin = self.origin;\r
483         currentflags = self.flags;\r
484         len = vlen(dir);\r
485         if (len > 16)\r
486                 dir = normalize(dir) * 16;\r
487 \r
488         setorigin(self, currentorigin + dir);\r
489 \r
490         while(i < 18 && !walkmove(0, 0))\r
491         {\r
492                 self.origin_z = currentorigin_z + i;\r
493                 i = i + 2;\r
494         }\r
495         self.flags = currentflags;\r
496         if (i >=18)\r
497                 setorigin(self, currentorigin);\r
498 };\r
499 \r
500 void() PostPhysics =\r
501 {\r
502         local vector obstr, org;\r
503         local float back, dst,cflags;\r
504 \r
505         self = self.owner;\r
506 \r
507         self.velocity = self.velocity - self.phys_obj.dest1 + self.phys_obj.velocity;\r
508         if (self.phys_obj.dest2 == self.origin)\r
509         {\r
510                 setorigin(self, self.phys_obj.origin);\r
511                 // might've been moved during other person's physics\r
512                 // (teleporters / plats)\r
513 \r
514                 if (self.movetype == MOVETYPE_WALK)\r
515                 {\r
516 \r
517                         if (self.phys_obj.dest1_x || self.phys_obj.dest1_y)\r
518                         {\r
519                                 if ((self.flags & FL_ONGROUND) || (self.waterlevel <= 2))\r
520                                 {\r
521                                         obstr = self.phys_obj.movedir  - self.origin;\r
522                                         obstr_z = 0;\r
523                                         if (vlen(obstr) > 0.1)\r
524                                         {\r
525                                                 dst = vlen(obstr);\r
526                                                 back = vectoyaw(obstr);\r
527                                                 cflags = self.flags;\r
528                                                 self.flags = self.flags | FL_PARTIALGROUND;\r
529                                                 if(walkmove(back, dst))\r
530                                                 {\r
531                                                         self.flags = cflags;\r
532                                                         self.phys_obj.dest1_z = 0;\r
533                                                         self.velocity = self.velocity + self.phys_obj.dest1 - self.phys_obj.velocity;\r
534                                                 }\r
535                                                 else\r
536                                                 {\r
537                                                         if (dst > 1)\r
538                                                                 frik_obstructed(obstr, FALSE);\r
539 \r
540                                                         org = self.origin;\r
541                                                         self.flags = cflags;\r
542                                                         obstr = self.phys_obj.dest1;\r
543                                                         obstr_x = 0;\r
544                                                         if (!botCheckForStep(obstr))\r
545                                                         {\r
546                                                                 obstr = self.phys_obj.dest1;\r
547                                                                 obstr_y = 0;\r
548                                                                 if (!botCheckForStep(obstr))\r
549                                                                 {\r
550                                                                         // if no steps were found, bot is really obstucted\r
551                                                                         BruteForceStep(self.phys_obj.dest1);\r
552                                                                 }\r
553                                                         }\r
554                                                 }\r
555                                         }\r
556                                 }\r
557                         }\r
558                 }\r
559         }\r
560 \r
561         SV_CheckOnGround();\r
562 \r
563         PlayerPostThink();\r
564         BotAI();\r
565         self.dmg_take = self.dmg_save = 0;\r
566 \r
567 };\r
568 // Avoid calling BotAI and the physics at the same time\r
569 // Can trip the runaway loop counter\r
570 \r
571 void() SV_FlyMove =\r
572 {\r
573         // This is nothing like the Quake function.\r
574 \r
575         if (self.phys_obj == world)\r
576         {\r
577                 self.phys_obj = find(world,classname,"phys_obj");\r
578                 while (self.phys_obj.owner != self)\r
579                 {\r
580                         self.phys_obj = find(self.phys_obj,classname,"phys_obj");\r
581                         if (self.phys_obj == world)\r
582                         {\r
583                                 error("No physics entity spawned!\nMake sure BotInit was called\n");\r
584                         }\r
585                 }\r
586         }\r
587 \r
588         setmodel (self.phys_obj, string_null);\r
589         self.phys_obj.movetype = MOVETYPE_STEP;\r
590 \r
591         self.phys_obj.solid = SOLID_TRIGGER;\r
592         self.phys_obj.touch = RemoveThud;\r
593         setsize(self.phys_obj, self.mins, self.maxs);\r
594         self.phys_obj.dest2 = self.phys_obj.origin = self.origin;\r
595         self.phys_obj.watertype = 0;\r
596         self.phys_obj.movedir = self.origin + real_frametime * self.velocity;\r
597         self.phys_obj.dest1 = self.phys_obj.velocity = self.velocity;\r
598         self.phys_obj.velocity_z = self.phys_obj.velocity_z + sv_gravity * real_frametime;\r
599         self.phys_obj.flags = 0;\r
600         self.phys_obj.think = PostPhysics;\r
601         self.phys_obj.nextthink = time;\r
602 };\r
603 \r
604 \r
605 void() SV_Physics_Toss =\r
606 {\r
607         if (!SV_RunThink())\r
608                 return;\r
609         if (self.flags & FL_ONGROUND)\r
610         {\r
611                 self.velocity = '0 0 0';\r
612                 BotAI();\r
613                 return;\r
614         }\r
615         if (self.movetype != MOVETYPE_FLY)\r
616                 SV_AddGravity(1);\r
617         self.angles = self.angles + real_frametime * self.avelocity;\r
618         SV_FlyMove();\r
619 \r
620 };\r
621 void() SV_Physics_Client =\r
622 {\r
623 \r
624         PlayerPreThink();\r
625 \r
626         if (self.movetype == MOVETYPE_NONE)\r
627         {\r
628                 if (!SV_RunThink())\r
629                         return;\r
630                 PlayerPostThink();\r
631                 BotAI();\r
632 \r
633         }\r
634         else if ((self.movetype == MOVETYPE_WALK) || (self.movetype == MOVETYPE_STEP))\r
635         {\r
636                 if (!SV_RunThink())\r
637                         return;\r
638             if (!(SV_CheckWater()) && (!(self.flags & FL_WATERJUMP)))\r
639                         SV_AddGravity(1);\r
640                 SV_FlyMove();\r
641         }\r
642         else if ((self.movetype == MOVETYPE_TOSS) || (self.movetype == MOVETYPE_BOUNCE))\r
643         {\r
644                 SV_Physics_Toss();\r
645         }\r
646         else if (self.movetype == MOVETYPE_FLY)\r
647         {\r
648                 if (!SV_RunThink())\r
649                         return;\r
650                 SV_FlyMove();\r
651         }\r
652         else if (self.movetype == MOVETYPE_NOCLIP)\r
653         {\r
654                 if (!SV_RunThink())\r
655                         return;\r
656                 self.origin = self.origin + real_frametime * self.velocity;\r
657 \r
658                 PlayerPostThink();\r
659                 BotAI();\r
660         }\r
661         else\r
662                 error ("SV_Physics_Client: Bad Movetype (BOT)");\r
663 \r
664 };\r
665 \r
666 \r