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 =
138 local vector vel, start, stop;
139 local float sped, friction, newspeed;
149 // if the leading edge is over a dropoff, increase friction
151 start_x = stop_x = self.origin_x + vel_x / (sped * 16);
152 start_y = stop_y = self.origin_y + vel_y / (sped * 16);
153 start_z = self.origin_z + self.mins_z;
154 stop_z = start_z - 34;
156 traceline(start, stop, TRUE, self);
158 if (trace_fraction == 1)
159 friction = sv_friction * 2; // 2 is default edgefriction, removed for QW compatability
161 friction = sv_friction;
162 if (sped < sv_stopspeed)
163 newspeed = sped - real_frametime * sv_stopspeed * friction;
165 newspeed = sped - real_frametime * sped * friction;
169 newspeed = newspeed / sped;
171 self.velocity_y = vel_y * newspeed;
172 self.velocity_x = vel_x * newspeed;
174 void() SV_WaterJump =
176 if (time > self.teleport_time || !self.waterlevel)
178 self.flags = self.flags - (self.flags & FL_WATERJUMP);
179 self.teleport_time = 0;
181 self.velocity_x = self.movedir_x;
182 self.velocity_y = self.movedir_y;
185 void() DropPunchAngle =
188 len = vlen(self.punchangle);
189 self.punchangle = normalize(self.punchangle);
190 len = len - 10 * real_frametime;
193 self.punchangle = self.punchangle * len;
197 void(vector wishvel) SV_AirAccelerate =
199 local float addspeed, wishspd, accelspeed, currentspeed;
201 wishspd = vlen(wishvel);
202 wishvel = normalize(wishvel);
205 currentspeed = self.velocity * wishvel;
206 addspeed = wishspd - currentspeed;
209 accelspeed = 10 * sv_accelerate * wishspd * real_frametime;
210 if (accelspeed > addspeed)
211 accelspeed = addspeed;
213 self.velocity = self.velocity + accelspeed * wishvel;
216 void(vector wishvel) SV_Accelerate =
218 local float addspeed, wishspd, accelspeed, currentspeed;
220 wishspd = vlen(wishvel);
221 wishvel = normalize(wishvel);
223 currentspeed = self.velocity * wishvel;
224 addspeed = wishspd - currentspeed;
227 accelspeed = sv_accelerate * wishspd * real_frametime;
228 if (accelspeed > addspeed)
229 accelspeed = addspeed;
231 self.velocity = self.velocity + accelspeed * wishvel;
233 void() SV_WaterMove =
235 local vector wishvel;
236 local float wishspeed, addspeed, cspeed, newspeed;
237 makevectors(self.v_angle);
238 wishvel = v_right * self.movement_y + v_forward * self.movement_x;
240 if (self.movement == '0 0 0')
241 wishvel_z = wishvel_z - 60;
243 wishvel_z = wishvel_z + self.movement_z;
244 wishspeed = vlen(wishvel);
246 if (wishspeed > sv_maxspeed)
248 wishvel = (sv_maxspeed / wishspeed) * wishvel;
249 wishspeed = sv_maxspeed;
251 wishspeed = wishspeed * 0.7;
252 cspeed = vlen(self.velocity);
255 newspeed = cspeed - (real_frametime * cspeed * sv_friction);
258 self.velocity = self.velocity * (newspeed / cspeed);
266 addspeed = wishspeed - newspeed;
269 wishvel = normalize(wishvel);
270 cspeed = sv_accelerate * wishspeed * real_frametime;
271 if (cspeed > addspeed)
273 self.velocity = self.velocity + cspeed * wishvel;
277 local vector wishvel, vangle;
279 vangle = self.v_angle;
280 vangle_x = vangle_z = 0;
282 if (time < self.teleport_time && (self.movement_x < 0))
284 wishvel = v_right * self.movement_y + v_forward * self.movement_x;
287 if (self.movetype != MOVETYPE_WALK)
288 wishvel_z = self.movement_z;
291 if (vlen(wishvel) > sv_maxspeed)
292 wishvel = normalize(wishvel) * sv_maxspeed;
293 if (self.movetype == MOVETYPE_NOCLIP)
294 self.velocity = wishvel;
295 else if (self.flags & FL_ONGROUND)
298 SV_Accelerate(wishvel);
301 SV_AirAccelerate (wishvel);
304 void() SV_ClientThink =
308 if (self.movetype == MOVETYPE_NONE)
311 if (self.health <= 0)
313 self.v_angle_z = 0; // V_CalcRoll removed, sucks
314 self.angles_z = self.v_angle_z * 4;
315 vangle = self.v_angle + self.punchangle;
318 self.angles_x = (vangle_x / -3);
319 self.angles_y = vangle_y;
322 self.v_angle = self.angles;
325 if (self.flags & FL_WATERJUMP)
330 if ((self.waterlevel >= 2) && (self.movetype != MOVETYPE_NOCLIP))
339 =========================================
341 Stuff mimicking sv_phys.c
343 =========================================
346 float() SV_RunThink =
348 local float thinktime, bkuptime;
349 thinktime = self.nextthink;
351 if (thinktime <= 0 || thinktime > (time + real_frametime))
353 if (thinktime < time)
358 makevectors(self.v_angle); // hack
364 void(float scale) SV_AddGravity =
366 self.velocity_z = self.velocity_z - (scale * sv_gravity * real_frametime);
369 float() SV_CheckWater =
374 point_x = self.origin_x;
375 point_y = self.origin_y;
377 self.watertype = CONTENT_EMPTY;
378 point_z = self.origin_z + self.mins_z + 1;
379 cont = pointcontents(point);
380 if (cont <= CONTENT_WATER)
382 self.watertype = cont;
384 point_z = self.origin_z + (self.mins_z + self.maxs_z) * 0.5;
385 cont = pointcontents(point);
386 if (cont <= CONTENT_WATER)
389 point_z = self.origin_z + self.view_ofs_z;
390 cont = pointcontents(point);
391 if (cont <= CONTENT_WATER)
395 return (self.waterlevel > 1);
398 void() RemoveThud = // well sometimes
403 if (self.flags & FL_ONGROUND)
405 self.flags = self.flags - FL_ONGROUND;
410 if (other.solid == SOLID_BSP && (self.flags & FL_ONGROUND))
412 // RM: Does this break anything?
413 // If not, then some more thuds have been removed.
414 self.flags = self.flags - FL_ONGROUND;
416 if (other == self.owner)
418 if (self.owner.solid == SOLID_NOT)
423 if (self.solid == SOLID_BSP)
429 void() SV_CheckOnGround =
433 local float currentflags;
434 currentflags = self.flags;
435 self.flags = self.flags | FL_ONGROUND | FL_PARTIALGROUND;
436 walkmove(0,0); // perform C touch function
437 self.flags = currentflags | FL_ONGROUND;
438 if ((org_x != self.origin_x) || (org_y != self.origin_y))
443 v_z = self.maxs_z + org_z + 1;
444 traceline (org, v, TRUE, self);
445 if ((self.waterlevel == 3) && (self.movetype == MOVETYPE_WALK))
446 self.flags = self.flags - FL_ONGROUND;
447 else if ((trace_plane_normal_z <= 0.7) && (trace_fraction != 1))
448 self.flags = self.flags - FL_ONGROUND;
449 else if (!droptofloor(0,0))
450 self.flags = self.flags - FL_ONGROUND;
451 else if (org_z - self.origin_z < 2)
452 self.flags = self.flags | FL_ONGROUND;
454 self.flags = self.flags - FL_ONGROUND;
455 setorigin(self, org);
457 // Thanks to Alan Kivlin for this function
458 // modified heavily by me
459 float(vector dir) botCheckForStep =
461 local vector currentorigin, v;
462 local float currentflags, yaw, stepdistance, movedistance;
463 currentorigin = self.origin;
464 currentflags = self.flags;
465 self.flags = FL_ONGROUND | FL_PARTIALGROUND;
466 dir = normalize(dir);
473 stepdistance = self.origin_z - currentorigin_z;
474 v = self.origin - currentorigin;
476 movedistance = vlen(v);
477 if((stepdistance > 0 && stepdistance <= 16) && movedistance != 0)
479 self.flags = currentflags | FL_PARTIALGROUND;
484 self.flags = currentflags;
485 setorigin(self, currentorigin);
488 // this is merely here to fix a problem with e3m5
489 void(vector dir) BruteForceStep =
491 local vector currentorigin;
492 local float currentflags, i, len;
494 currentorigin = self.origin;
495 currentflags = self.flags;
498 dir = normalize(dir) * 16;
500 setorigin(self, currentorigin + dir);
502 while(i < 18 && !walkmove(0, 0))
504 self.origin_z = currentorigin_z + i;
507 self.flags = currentflags;
509 setorigin(self, currentorigin);
514 local vector obstr, org;
515 local float back, dst,cflags;
519 self.velocity = self.velocity - self.phys_obj.dest1 + self.phys_obj.velocity;
520 if (self.phys_obj.dest2 == self.origin)
522 setorigin(self, self.phys_obj.origin);
523 // might've been moved during other person's physics
524 // (teleporters / plats)
526 if (self.movetype == MOVETYPE_WALK)
529 if (self.phys_obj.dest1_x || self.phys_obj.dest1_y)
531 if ((self.flags & FL_ONGROUND) || (self.waterlevel <= 2))
533 obstr = self.phys_obj.movedir - self.origin;
535 if (vlen(obstr) > 0.1)
538 back = vectoyaw(obstr);
540 self.flags = self.flags | FL_PARTIALGROUND;
541 if(walkmove(back, dst))
544 self.phys_obj.dest1_z = 0;
545 self.velocity = self.velocity + self.phys_obj.dest1 - self.phys_obj.velocity;
550 frik_obstructed(obstr, FALSE);
554 obstr = self.phys_obj.dest1;
556 if (!botCheckForStep(obstr))
558 obstr = self.phys_obj.dest1;
560 if (!botCheckForStep(obstr))
562 // if no steps were found, bot is really obstucted
563 BruteForceStep(self.phys_obj.dest1);
577 self.dmg_take = self.dmg_save = 0;
580 // Avoid calling BotAI and the physics at the same time
581 // Can trip the runaway loop counter
585 // This is nothing like the Quake function.
587 if (self.phys_obj == world)
589 self.phys_obj = find(world,classname,"phys_obj");
590 while (self.phys_obj.owner != self)
592 self.phys_obj = find(self.phys_obj,classname,"phys_obj");
593 if (self.phys_obj == world)
595 error("No physics entity spawned!\nMake sure BotInit was called\n");
600 setmodel (self.phys_obj, string_null);
601 self.phys_obj.movetype = MOVETYPE_STEP;
603 self.phys_obj.solid = SOLID_TRIGGER;
604 self.phys_obj.touch = RemoveThud;
605 setsize(self.phys_obj, self.mins, self.maxs);
606 self.phys_obj.dest2 = self.phys_obj.origin = self.origin;
607 self.phys_obj.watertype = 0;
608 self.phys_obj.movedir = self.origin + real_frametime * self.velocity;
609 self.phys_obj.dest1 = self.phys_obj.velocity = self.velocity;
610 self.phys_obj.velocity_z = self.phys_obj.velocity_z + sv_gravity * real_frametime;
611 self.phys_obj.flags = 0;
612 self.phys_obj.think = PostPhysics;
613 self.phys_obj.nextthink = time;
617 void() SV_Physics_Toss =
621 if (self.flags & FL_ONGROUND)
623 self.velocity = '0 0 0';
627 if (self.movetype != MOVETYPE_FLY)
629 self.angles = self.angles + real_frametime * self.avelocity;
633 void() SV_Physics_Client =
638 if (self.movetype == MOVETYPE_NONE)
646 else if ((self.movetype == MOVETYPE_WALK) || (self.movetype == MOVETYPE_STEP))
650 if (!(SV_CheckWater()) && (!(self.flags & FL_WATERJUMP)))
654 else if ((self.movetype == MOVETYPE_TOSS) || (self.movetype == MOVETYPE_BOUNCE))
658 else if (self.movetype == MOVETYPE_FLY)
664 else if (self.movetype == MOVETYPE_NOCLIP)
668 self.origin = self.origin + real_frametime * self.velocity;
674 error ("SV_Physics_Client: Bad Movetype (BOT)");