1 /***********************************************
4 * The near-perfect emulation of *
7 * Special Thanks to: Asdf, Frog *
8 * Alan "Strider" Kivlin *
11 ***********************************************/
15 This program is in the Public Domain. My crack legal
16 team would like to add:
18 RYAN "FRIKAC" SMITH IS PROVIDING THIS SOFTWARE "AS IS"
19 AND MAKES NO WARRANTY, EXPRESS OR IMPLIED, AS TO THE
20 ACCURACY, CAPABILITY, EFFICIENCY, MERCHANTABILITY, OR
21 FUNCTIONING OF THIS SOFTWARE AND/OR DOCUMENTATION. IN
22 NO EVENT WILL RYAN "FRIKAC" SMITH BE LIABLE FOR ANY
23 GENERAL, CONSEQUENTIAL, INDIRECT, INCIDENTAL,
24 EXEMPLARY, OR SPECIAL DAMAGES, EVEN IF RYAN "FRIKAC"
25 SMITH HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
26 DAMAGES, IRRESPECTIVE OF THE CAUSE OF SUCH DAMAGES.
28 You accept this software on the condition that you
29 indemnify and hold harmless Ryan "FrikaC" Smith from
30 any and all liability or damages to third parties,
31 including attorney fees, court costs, and other
32 related costs and expenses, arising out of your use
33 of this software irrespective of the cause of said
36 The export from the United States or the subsequent
37 reexport of this software is subject to compliance
38 with United States export control and munitions
39 control restrictions. You agree that in the event you
40 seek to export this software, you assume full
41 responsibility for obtaining all necessary export
42 licenses and approvals and for assuring compliance
43 with applicable reexport restrictions.
45 Any reproduction of this software must contain
46 this notice in its entirety.
51 =========================================
53 Stuff mimicking cl_input.c code
55 =========================================
57 float(float key) CL_KeyState =
59 return ((self.keys & key) > 0);
62 void() CL_KeyMove = // CL_BaseMove + CL_AdjustAngles
64 local float anglespeed;
66 if (self.keys != self.oldkeys)
68 self.movement = '0 0 0';
69 self.movement_y = self.movement_y + (350 * CL_KeyState(KEY_MOVERIGHT));
70 // 350 is the default cl_sidespeed
71 self.movement_y = self.movement_y - (350 * CL_KeyState(KEY_MOVELEFT));
72 // 350 is the default cl_sidespeed
73 self.movement_x = self.movement_x + (200 * CL_KeyState(KEY_MOVEFORWARD));
74 // 200 is the default cl_forwardspeed
75 self.movement_x = self.movement_x - (200 * CL_KeyState(KEY_MOVEBACK));
76 // 200 is the default cl_backspeed
77 self.movement_z = self.movement_z + (200 * CL_KeyState(KEY_MOVEUP));
78 // 200 is the default cl_upspeed
79 self.movement_z = self.movement_z - (200 * CL_KeyState(KEY_MOVEDOWN));
80 // 200 is the default cl_upspeed
81 if (!self.b_aiflags & AI_PRECISION)
82 self.movement = self.movement * 2;
83 // 2 is the default cl_movespeedkey & bot always has +speed
85 self.oldkeys = self.keys;
87 if (self.b_skill != 2) // use mouse emulation
89 anglespeed = 1.5 * real_frametime;
90 // 1.5 is the default cl_anglespeedkey & bot always has +speed
91 self.v_angle_y = self.v_angle_y + anglespeed * CL_KeyState(KEY_LOOKLEFT) * 140;
92 // 140 is default cl_yawspeed
93 self.v_angle_y = self.v_angle_y - anglespeed * CL_KeyState(KEY_LOOKRIGHT) * 140;
94 // 140 is default cl_yawspeed
95 self.v_angle_x = self.v_angle_x - anglespeed * CL_KeyState(KEY_LOOKUP) * 150;
96 // 150 is default cl_pitchspeed
97 self.v_angle_x = self.v_angle_x + anglespeed * CL_KeyState(KEY_LOOKDOWN) * 150;
98 // 150 is default cl_pitchspeed
102 view_x = angcomp(self.b_angle_x, self.v_angle_x);
103 view_y = angcomp(self.b_angle_y, self.v_angle_y);
106 self.mouse_emu = self.mouse_emu + (view * 30);
107 if (vlen(self.mouse_emu) > 180)
108 self.mouse_emu = normalize(self.mouse_emu) * 180;
111 self.mouse_emu = view * (1 / real_frametime);
112 self.v_angle = self.v_angle + self.mouse_emu * real_frametime;
116 if (self.v_angle_x > 80)
118 else if (self.v_angle_x < -70)
119 self.v_angle_x = -70;
121 if (self.v_angle_z > 50)
123 else if (self.v_angle_z < -50)
124 self.v_angle_z = -50;
125 self.v_angle_y = frik_anglemod(self.v_angle_y);
130 =========================================
132 Stuff mimicking sv_user.c
134 =========================================
136 void() SV_UserFriction =
139 local float sped, friction, newspeed;
149 friction = sv_friction;
150 if (sped < sv_stopspeed)
151 newspeed = sped - real_frametime * sv_stopspeed * friction;
153 newspeed = sped - real_frametime * sped * friction;
157 newspeed = newspeed / sped;
159 self.velocity_y = vel_y * newspeed;
160 self.velocity_x = vel_x * newspeed;
162 void() SV_WaterJump =
164 if (time > self.teleport_time || !self.waterlevel)
166 self.flags = self.flags - (self.flags & FL_WATERJUMP);
167 self.teleport_time = 0;
169 self.velocity_x = self.movedir_x;
170 self.velocity_y = self.movedir_y;
173 void() DropPunchAngle =
176 len = vlen(self.punchangle);
177 self.punchangle = normalize(self.punchangle);
178 len = len - 10 * real_frametime;
181 self.punchangle = self.punchangle * len;
185 void(vector wishvel) SV_AirAccelerate =
187 local float addspeed, wishspd, accelspeed, currentspeed;
189 wishspd = vlen(wishvel);
190 wishvel = normalize(wishvel);
193 currentspeed = self.velocity * wishvel;
194 addspeed = wishspd - currentspeed;
197 accelspeed = 10 * sv_accelerate * wishspd * real_frametime;
198 if (accelspeed > addspeed)
199 accelspeed = addspeed;
201 self.velocity = self.velocity + accelspeed * wishvel;
204 void(vector wishvel) SV_Accelerate =
206 local float addspeed, wishspd, accelspeed, currentspeed;
208 wishspd = vlen(wishvel);
209 wishvel = normalize(wishvel);
211 currentspeed = self.velocity * wishvel;
212 addspeed = wishspd - currentspeed;
215 accelspeed = sv_accelerate * wishspd * real_frametime;
216 if (accelspeed > addspeed)
217 accelspeed = addspeed;
219 self.velocity = self.velocity + accelspeed * wishvel;
221 void() SV_WaterMove =
223 local vector wishvel;
224 local float wishspeed, addspeed, cspeed, newspeed;
225 makevectors(self.v_angle);
226 wishvel = v_right * self.movement_y + v_forward * self.movement_x;
228 if (self.movement == '0 0 0')
229 wishvel_z = wishvel_z - 60;
231 wishvel_z = wishvel_z + self.movement_z;
232 wishspeed = vlen(wishvel);
234 if (wishspeed > sv_maxspeed)
236 wishvel = (sv_maxspeed / wishspeed) * wishvel;
237 wishspeed = sv_maxspeed;
239 wishspeed = wishspeed * 0.7;
240 cspeed = vlen(self.velocity);
243 newspeed = cspeed - (real_frametime * cspeed * sv_friction);
246 self.velocity = self.velocity * (newspeed / cspeed);
254 addspeed = wishspeed - newspeed;
257 wishvel = normalize(wishvel);
258 cspeed = sv_accelerate * wishspeed * real_frametime;
259 if (cspeed > addspeed)
261 self.velocity = self.velocity + cspeed * wishvel;
265 local vector wishvel, vangle;
267 vangle = self.v_angle;
268 vangle_x = vangle_z = 0;
270 if (time < self.teleport_time && (self.movement_x < 0))
272 wishvel = v_right * self.movement_y + v_forward * self.movement_x;
275 if (self.movetype != MOVETYPE_WALK)
276 wishvel_z = self.movement_z;
279 if (vlen(wishvel) > sv_maxspeed)
280 wishvel = normalize(wishvel) * sv_maxspeed;
281 if (self.movetype == MOVETYPE_NOCLIP)
282 self.velocity = wishvel;
283 else if (self.flags & FL_ONGROUND)
286 SV_Accelerate(wishvel);
289 SV_AirAccelerate (wishvel);
292 void() SV_ClientThink =
296 if (self.movetype == MOVETYPE_NONE)
299 if (self.health <= 0)
301 self.v_angle_z = 0; // V_CalcRoll removed, sucks
302 self.angles_z = self.v_angle_z * 4;
303 vangle = self.v_angle + self.punchangle;
306 self.angles_x = (vangle_x / -3);
307 self.angles_y = vangle_y;
310 self.v_angle = self.angles;
313 if (self.flags & FL_WATERJUMP)
318 if ((self.waterlevel >= 2) && (self.movetype != MOVETYPE_NOCLIP))
327 =========================================
329 Stuff mimicking sv_phys.c
331 =========================================
334 float() SV_RunThink =
336 local float thinktime, bkuptime;
337 thinktime = self.nextthink;
339 if (thinktime <= 0 || thinktime > (time + real_frametime))
341 if (thinktime < time)
346 makevectors(self.v_angle); // hack
352 void(float scal) SV_AddGravity =
354 self.velocity_z = self.velocity_z - (scal * sv_gravity * real_frametime);
357 float() SV_CheckWater =
362 point_x = self.origin_x;
363 point_y = self.origin_y;
365 self.watertype = CONTENT_EMPTY;
366 point_z = self.origin_z + self.mins_z + 1;
367 cont = pointcontents(point);
368 if (cont <= CONTENT_WATER)
370 self.watertype = cont;
372 point_z = self.origin_z + (self.mins_z + self.maxs_z) * 0.5;
373 cont = pointcontents(point);
374 if (cont <= CONTENT_WATER)
377 point_z = self.origin_z + self.view_ofs_z;
378 cont = pointcontents(point);
379 if (cont <= CONTENT_WATER)
383 return (self.waterlevel > 1);
386 void() RemoveThud = // well sometimes
391 if (self.flags & FL_ONGROUND)
393 self.flags = self.flags - FL_ONGROUND;
398 if (other.solid == SOLID_BSP && (self.flags & FL_ONGROUND))
400 // RM: Does this break anything?
401 // If not, then some more thuds have been removed.
402 self.flags = self.flags - FL_ONGROUND;
404 if (other == self.owner)
406 if (self.owner.solid == SOLID_NOT)
411 if (self.solid == SOLID_BSP)
417 void() SV_CheckOnGround =
421 local float currentflags;
422 currentflags = self.flags;
423 self.flags = self.flags | FL_ONGROUND | FL_PARTIALGROUND;
424 walkmove(0,0); // perform C touch function
425 self.flags = currentflags | FL_ONGROUND;
426 if ((org_x != self.origin_x) || (org_y != self.origin_y))
431 v_z = self.maxs_z + org_z + 1;
432 traceline (org, v, TRUE, self);
433 if ((self.waterlevel == 3) && (self.movetype == MOVETYPE_WALK))
434 self.flags = self.flags - FL_ONGROUND;
435 else if ((trace_plane_normal_z <= 0.7) && (trace_fraction != 1))
436 self.flags = self.flags - FL_ONGROUND;
437 else if (!droptofloor(0,0))
438 self.flags = self.flags - FL_ONGROUND;
439 else if (org_z - self.origin_z < 2)
440 self.flags = self.flags | FL_ONGROUND;
442 self.flags = self.flags - FL_ONGROUND;
443 setorigin(self, org);
445 // Thanks to Alan Kivlin for this function
446 // modified heavily by me
447 float(vector dir) botCheckForStep =
449 local vector currentorigin, v;
450 local float currentflags, yaw, stepdistance, movedistance;
451 currentorigin = self.origin;
452 currentflags = self.flags;
453 self.flags = FL_ONGROUND | FL_PARTIALGROUND;
454 dir = normalize(dir);
461 stepdistance = self.origin_z - currentorigin_z;
462 v = self.origin - currentorigin;
464 movedistance = vlen(v);
465 if((stepdistance > 0 && stepdistance <= 16) && movedistance != 0)
467 self.flags = currentflags | FL_PARTIALGROUND;
472 self.flags = currentflags;
473 setorigin(self, currentorigin);
476 // this is merely here to fix a problem with e3m5
477 void(vector dir) BruteForceStep =
479 local vector currentorigin;
480 local float currentflags, i, len;
482 currentorigin = self.origin;
483 currentflags = self.flags;
486 dir = normalize(dir) * 16;
488 setorigin(self, currentorigin + dir);
490 while(i < 18 && !walkmove(0, 0))
492 self.origin_z = currentorigin_z + i;
495 self.flags = currentflags;
497 setorigin(self, currentorigin);
502 local vector obstr, org;
503 local float back, dst,cflags;
507 self.velocity = self.velocity - self.phys_obj.dest1 + self.phys_obj.velocity;
508 if (self.phys_obj.dest2 == self.origin)
510 setorigin(self, self.phys_obj.origin);
511 // might've been moved during other person's physics
512 // (teleporters / plats)
514 if (self.movetype == MOVETYPE_WALK)
517 if (self.phys_obj.dest1_x || self.phys_obj.dest1_y)
519 if ((self.flags & FL_ONGROUND) || (self.waterlevel <= 2))
521 obstr = self.phys_obj.movedir - self.origin;
523 if (vlen(obstr) > 0.1)
526 back = vectoyaw(obstr);
528 self.flags = self.flags | FL_PARTIALGROUND;
529 if(walkmove(back, dst))
532 self.phys_obj.dest1_z = 0;
533 self.velocity = self.velocity + self.phys_obj.dest1 - self.phys_obj.velocity;
538 frik_obstructed(obstr, FALSE);
542 obstr = self.phys_obj.dest1;
544 if (!botCheckForStep(obstr))
546 obstr = self.phys_obj.dest1;
548 if (!botCheckForStep(obstr))
550 // if no steps were found, bot is really obstucted
551 BruteForceStep(self.phys_obj.dest1);
565 self.dmg_take = self.dmg_save = 0;
568 // Avoid calling BotAI and the physics at the same time
569 // Can trip the runaway loop counter
573 // This is nothing like the Quake function.
575 if (self.phys_obj == world)
577 self.phys_obj = find(world,classname,"phys_obj");
578 while (self.phys_obj.owner != self)
580 self.phys_obj = find(self.phys_obj,classname,"phys_obj");
581 if (self.phys_obj == world)
583 error("No physics entity spawned!\nMake sure BotInit was called\n");
588 setmodel (self.phys_obj, string_null);
589 self.phys_obj.movetype = MOVETYPE_STEP;
591 self.phys_obj.solid = SOLID_TRIGGER;
592 self.phys_obj.touch = RemoveThud;
593 setsize(self.phys_obj, self.mins, self.maxs);
594 self.phys_obj.dest2 = self.phys_obj.origin = self.origin;
595 self.phys_obj.watertype = 0;
596 self.phys_obj.movedir = self.origin + real_frametime * self.velocity;
597 self.phys_obj.dest1 = self.phys_obj.velocity = self.velocity;
598 self.phys_obj.velocity_z = self.phys_obj.velocity_z + sv_gravity * real_frametime;
599 self.phys_obj.flags = 0;
600 self.phys_obj.think = PostPhysics;
601 self.phys_obj.nextthink = time;
605 void() SV_Physics_Toss =
609 if (self.flags & FL_ONGROUND)
611 self.velocity = '0 0 0';
615 if (self.movetype != MOVETYPE_FLY)
617 self.angles = self.angles + real_frametime * self.avelocity;
621 void() SV_Physics_Client =
626 if (self.movetype == MOVETYPE_NONE)
634 else if ((self.movetype == MOVETYPE_WALK) || (self.movetype == MOVETYPE_STEP))
638 if (!(SV_CheckWater()) && (!(self.flags & FL_WATERJUMP)))
642 else if ((self.movetype == MOVETYPE_TOSS) || (self.movetype == MOVETYPE_BOUNCE))
646 else if (self.movetype == MOVETYPE_FLY)
652 else if (self.movetype == MOVETYPE_NOCLIP)
656 self.origin = self.origin + real_frametime * self.velocity;
662 error ("SV_Physics_Client: Bad Movetype (BOT)");