6 #include <server/antilag.qh>
8 #include <common/physics/player.qh>
12 void bugrigs_SetVars();
14 REGISTER_MUTATOR(bugrigs, cvar("g_bugrigs"))
23 REGISTER_MUTATOR(bugrigs, true);
27 #define PHYS_BUGRIGS(s) STAT(BUGRIGS, s)
28 #define PHYS_BUGRIGS_ACCEL(s) STAT(BUGRIGS_ACCEL, s)
29 #define PHYS_BUGRIGS_AIR_STEERING(s) STAT(BUGRIGS_AIR_STEERING, s)
30 #define PHYS_BUGRIGS_ANGLE_SMOOTHING(s) STAT(BUGRIGS_ANGLE_SMOOTHING, s)
31 #define PHYS_BUGRIGS_CAR_JUMPING(s) STAT(BUGRIGS_CAR_JUMPING, s)
32 #define PHYS_BUGRIGS_FRICTION_AIR(s) STAT(BUGRIGS_FRICTION_AIR, s)
33 #define PHYS_BUGRIGS_FRICTION_BRAKE(s) STAT(BUGRIGS_FRICTION_BRAKE, s)
34 #define PHYS_BUGRIGS_FRICTION_FLOOR(s) STAT(BUGRIGS_FRICTION_FLOOR, s)
35 #define PHYS_BUGRIGS_PLANAR_MOVEMENT(s) STAT(BUGRIGS_PLANAR_MOVEMENT, s)
36 #define PHYS_BUGRIGS_REVERSE_SPEEDING(s) STAT(BUGRIGS_REVERSE_SPEEDING, s)
37 #define PHYS_BUGRIGS_REVERSE_SPINNING(s) STAT(BUGRIGS_REVERSE_SPINNING, s)
38 #define PHYS_BUGRIGS_REVERSE_STOPPING(s) STAT(BUGRIGS_REVERSE_STOPPING, s)
39 #define PHYS_BUGRIGS_SPEED_POW(s) STAT(BUGRIGS_SPEED_POW, s)
40 #define PHYS_BUGRIGS_SPEED_REF(s) STAT(BUGRIGS_SPEED_REF, s)
41 #define PHYS_BUGRIGS_STEER(s) STAT(BUGRIGS_STEER, s)
45 void bugrigs_SetVars()
47 g_bugrigs = cvar("g_bugrigs");
48 g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement");
49 g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping");
50 g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning");
51 g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding");
52 g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping");
53 g_bugrigs_air_steering = cvar("g_bugrigs_air_steering");
54 g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing");
55 g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor");
56 g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake");
57 g_bugrigs_friction_air = cvar("g_bugrigs_friction_air");
58 g_bugrigs_accel = cvar("g_bugrigs_accel");
59 g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref");
60 g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
61 g_bugrigs_steer = cvar("g_bugrigs_steer");
66 float racecar_angle(float forward, float down)
73 float ret = vectoyaw('0 1 0' * down + '1 0 0' * forward);
75 float angle_mult = forward / (800 + forward);
78 return ret * angle_mult + 360 * (1 - angle_mult);
80 return ret * angle_mult;
84 void RaceCarPhysics(entity this, float dt)
86 // using this move type for "big rigs"
87 // the engine does not push the entity!
91 vector angles_save = this.angles;
92 float accel = bound(-1, PHYS_CS(this).movement.x / PHYS_MAXSPEED(this), 1);
93 float steer = bound(-1, PHYS_CS(this).movement.y / PHYS_MAXSPEED(this), 1);
95 if (PHYS_BUGRIGS_REVERSE_SPEEDING(this)) {
97 // back accel is DIGITAL
98 // to prevent speedhack
109 makevectors(this.angles); // new forward direction!
111 if (IS_ONGROUND(this) || PHYS_BUGRIGS_AIR_STEERING(this)) {
112 float myspeed = this.velocity * v_forward;
113 float upspeed = this.velocity * v_up;
115 // responsiveness factor for steering and acceleration
116 float f = 1 / (1 + POW((max(-myspeed, myspeed) / PHYS_BUGRIGS_SPEED_REF(this)), PHYS_BUGRIGS_SPEED_POW(this)));
117 // MAXIMA: f(v) := 1 / (1 + (v / PHYS_BUGRIGS_SPEED_REF(this)) ^ PHYS_BUGRIGS_SPEED_POW(this));
120 if (myspeed < 0 && PHYS_BUGRIGS_REVERSE_SPINNING(this)) {
121 steerfactor = -myspeed * PHYS_BUGRIGS_STEER(this);
123 steerfactor = -myspeed * f * PHYS_BUGRIGS_STEER(this);
127 if (myspeed < 0 && PHYS_BUGRIGS_REVERSE_SPEEDING(this)) {
128 accelfactor = PHYS_BUGRIGS_ACCEL(this);
130 accelfactor = f * PHYS_BUGRIGS_ACCEL(this);
132 // MAXIMA: accel(v) := f(v) * PHYS_BUGRIGS_ACCEL(this);
136 myspeed = max(0, myspeed - dt * (PHYS_BUGRIGS_FRICTION_FLOOR(this) - PHYS_BUGRIGS_FRICTION_BRAKE(this) * accel));
138 if (!PHYS_BUGRIGS_REVERSE_SPEEDING(this)) {
139 myspeed = min(0, myspeed + dt * PHYS_BUGRIGS_FRICTION_FLOOR(this));
144 myspeed = max(0, myspeed - dt * PHYS_BUGRIGS_FRICTION_FLOOR(this));
146 if (PHYS_BUGRIGS_REVERSE_STOPPING(this)) {
149 myspeed = min(0, myspeed + dt * (PHYS_BUGRIGS_FRICTION_FLOOR(this) + PHYS_BUGRIGS_FRICTION_BRAKE(this) * accel));
153 // terminal velocity = velocity at which 50 == accelfactor, that is, 1549 units/sec
154 // MAXIMA: friction(v) := PHYS_BUGRIGS_FRICTION_FLOOR(this);
156 this.angles_y += steer * dt * steerfactor; // apply steering
157 makevectors(this.angles); // new forward direction!
159 myspeed += accel * accelfactor * dt;
161 rigvel = myspeed * v_forward + '0 0 1' * upspeed;
163 float myspeed = vlen(this.velocity);
165 // responsiveness factor for steering and acceleration
166 float f = 1 / (1 + POW(max(0, myspeed / PHYS_BUGRIGS_SPEED_REF(this)), PHYS_BUGRIGS_SPEED_POW(this)));
167 float steerfactor = -myspeed * f;
168 this.angles_y += steer * dt * steerfactor; // apply steering
170 rigvel = this.velocity;
171 makevectors(this.angles); // new forward direction!
174 rigvel *= max(0, 1 - vlen(rigvel) * PHYS_BUGRIGS_FRICTION_AIR(this) * dt);
175 // MAXIMA: airfriction(v) := v * v * PHYS_BUGRIGS_FRICTION_AIR(this);
176 // MAXIMA: total_acceleration(v) := accel(v) - friction(v) - airfriction(v);
177 // MAXIMA: solve(total_acceleration(v) = 0, v);
179 if (PHYS_BUGRIGS_PLANAR_MOVEMENT(this)) {
180 vector rigvel_xy, neworigin, up;
183 rigvel_z -= dt * PHYS_GRAVITY(this); // 4x gravity plays better
184 rigvel_xy = vec2(rigvel);
186 if (PHYS_BUGRIGS_CAR_JUMPING(this)) {
189 mt = MOVE_NOMONSTERS;
192 tracebox(this.origin, this.mins, this.maxs, this.origin + '0 0 1024', mt, this);
193 up = trace_endpos - this.origin;
195 // BUG RIGS: align the move to the surface instead of doing collision testing
197 tracebox(trace_endpos, this.mins, this.maxs, trace_endpos + rigvel_xy * dt, mt, this);
200 tracebox(trace_endpos, this.mins, this.maxs, trace_endpos - up + '0 0 1' * rigvel_z * dt, mt, this);
202 if (trace_fraction < 0.5) {
204 neworigin = this.origin;
206 neworigin = trace_endpos;
209 if (trace_fraction < 1) {
210 // now set angles_x so that the car points parallel to the surface
211 this.angles = vectoangles(
212 '1 0 0' * v_forward.x * trace_plane_normal.z
214 '0 1 0' * v_forward.y * trace_plane_normal.z
216 '0 0 1' * -(v_forward.x * trace_plane_normal.x + v_forward.y * trace_plane_normal.y)
220 // now set angles_x so that the car points forward, but is tilted in velocity direction
221 UNSET_ONGROUND(this);
224 this.velocity = (neworigin - this.origin) * (1.0 / dt);
225 set_movetype(this, MOVETYPE_NOCLIP);
227 rigvel_z -= dt * PHYS_GRAVITY(this); // 4x gravity plays better
228 this.velocity = rigvel;
229 set_movetype(this, MOVETYPE_FLY);
233 tracebox(this.origin, this.mins, this.maxs, this.origin - '0 0 4', MOVE_NORMAL, this);
234 if (trace_fraction != 1) {
235 this.angles = vectoangles2(
236 '1 0 0' * v_forward.x * trace_plane_normal.z
238 '0 1 0' * v_forward.y * trace_plane_normal.z
240 '0 0 1' * -(v_forward.x * trace_plane_normal.x + v_forward.y * trace_plane_normal.y),
246 vel_local.x = v_forward * this.velocity;
247 vel_local.y = v_right * this.velocity;
248 vel_local.z = v_up * this.velocity;
250 this.angles_x = racecar_angle(vel_local.x, vel_local.z);
251 this.angles_z = racecar_angle(-vel_local.y, vel_local.z);
255 vector vf1, vu1, smoothangles;
256 makevectors(this.angles);
257 float f = bound(0, dt * PHYS_BUGRIGS_ANGLE_SMOOTHING(this), 1);
263 makevectors(angles_save);
264 vf1 = vf1 + v_forward * (1 - f);
265 vu1 = vu1 + v_up * (1 - f);
266 smoothangles = vectoangles2(vf1, vu1);
267 this.angles_x = -smoothangles.x;
268 this.angles_z = smoothangles.z;
272 .vector bugrigs_prevangles;
274 MUTATOR_HOOKFUNCTION(bugrigs, PM_Physics)
276 entity player = M_ARGV(0, entity);
277 float dt = M_ARGV(2, float);
279 if (!PHYS_BUGRIGS(player) || !IS_PLAYER(player)) { return; }
282 player.angles = player.bugrigs_prevangles;
285 RaceCarPhysics(player, dt);
289 MUTATOR_HOOKFUNCTION(bugrigs, PlayerPhysics)
291 if (!PHYS_BUGRIGS(M_ARGV(0, entity))) { return; }
293 entity player = M_ARGV(0, entity);
294 player.bugrigs_prevangles = player.angles;
300 MUTATOR_HOOKFUNCTION(bugrigs, ClientConnect)
302 entity player = M_ARGV(0, entity);
304 stuffcmd(player, "cl_cmd settemp chase_active 1\n");
307 MUTATOR_HOOKFUNCTION(bugrigs, BuildMutatorsString)
309 M_ARGV(0, string) = strcat(M_ARGV(0, string), ":bugrigs");
312 MUTATOR_HOOKFUNCTION(bugrigs, BuildMutatorsPrettyString)
314 M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Bug rigs");