Xonotic
bugrigs.qc
Go to the documentation of this file.
1 #include "bugrigs.qh"
2 
3 #ifdef SVQC // NOTE: disabled on the client side until prediction can be fixed!
4 
5 #ifdef GAMEQC
6 
7 #ifdef SVQC
8  #include <server/antilag.qh>
9 #endif
10 #include <common/physics/player.qh>
11 
12 
13 #if defined(SVQC)
14 void bugrigs_SetVars();
15 
16 REGISTER_MUTATOR(bugrigs, cvar("g_bugrigs"))
17 {
19  {
20  bugrigs_SetVars();
21  }
22  return false;
23 }
24 #elif defined(CSQC)
25 REGISTER_MUTATOR(bugrigs, true);
26 #endif
27 
28 
29 #if 0
30 #define PHYS_BUGRIGS(s) STAT(BUGRIGS, s)
31 #define PHYS_BUGRIGS_ACCEL(s) STAT(BUGRIGS_ACCEL, s)
32 #define PHYS_BUGRIGS_AIR_STEERING(s) STAT(BUGRIGS_AIR_STEERING, s)
33 #define PHYS_BUGRIGS_ANGLE_SMOOTHING(s) STAT(BUGRIGS_ANGLE_SMOOTHING, s)
34 #define PHYS_BUGRIGS_CAR_JUMPING(s) STAT(BUGRIGS_CAR_JUMPING, s)
35 #define PHYS_BUGRIGS_FRICTION_AIR(s) STAT(BUGRIGS_FRICTION_AIR, s)
36 #define PHYS_BUGRIGS_FRICTION_BRAKE(s) STAT(BUGRIGS_FRICTION_BRAKE, s)
37 #define PHYS_BUGRIGS_FRICTION_FLOOR(s) STAT(BUGRIGS_FRICTION_FLOOR, s)
38 #define PHYS_BUGRIGS_PLANAR_MOVEMENT(s) STAT(BUGRIGS_PLANAR_MOVEMENT, s)
39 #define PHYS_BUGRIGS_REVERSE_SPEEDING(s) STAT(BUGRIGS_REVERSE_SPEEDING, s)
40 #define PHYS_BUGRIGS_REVERSE_SPINNING(s) STAT(BUGRIGS_REVERSE_SPINNING, s)
41 #define PHYS_BUGRIGS_REVERSE_STOPPING(s) STAT(BUGRIGS_REVERSE_STOPPING, s)
42 #define PHYS_BUGRIGS_SPEED_POW(s) STAT(BUGRIGS_SPEED_POW, s)
43 #define PHYS_BUGRIGS_SPEED_REF(s) STAT(BUGRIGS_SPEED_REF, s)
44 #define PHYS_BUGRIGS_STEER(s) STAT(BUGRIGS_STEER, s)
45 #else
46 #define PHYS_BUGRIGS(s) g_bugrigs
47 #define PHYS_BUGRIGS_ACCEL(s) g_bugrigs_accel
48 #define PHYS_BUGRIGS_AIR_STEERING(s) g_bugrigs_air_steering
49 #define PHYS_BUGRIGS_ANGLE_SMOOTHING(s) g_bugrigs_angle_smoothing
50 #define PHYS_BUGRIGS_CAR_JUMPING(s) g_bugrigs_planar_movement_car_jumping
51 #define PHYS_BUGRIGS_FRICTION_AIR(s) g_bugrigs_friction_air
52 #define PHYS_BUGRIGS_FRICTION_BRAKE(s) g_bugrigs_friction_brake
53 #define PHYS_BUGRIGS_FRICTION_FLOOR(s) g_bugrigs_friction_floor
54 #define PHYS_BUGRIGS_PLANAR_MOVEMENT(s) g_bugrigs_planar_movement
55 #define PHYS_BUGRIGS_REVERSE_SPEEDING(s) g_bugrigs_reverse_speeding
56 #define PHYS_BUGRIGS_REVERSE_SPINNING(s) g_bugrigs_reverse_spinning
57 #define PHYS_BUGRIGS_REVERSE_STOPPING(s) g_bugrigs_reverse_stopping
58 #define PHYS_BUGRIGS_SPEED_POW(s) g_bugrigs_speed_pow
59 #define PHYS_BUGRIGS_SPEED_REF(s) g_bugrigs_speed_ref
60 #define PHYS_BUGRIGS_STEER(s) g_bugrigs_steer
61 #endif
62 
63 #if defined(SVQC)
64 
65 void bugrigs_SetVars()
66 {
67  g_bugrigs = cvar("g_bugrigs");
68  g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement");
69  g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping");
70  g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning");
71  g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding");
72  g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping");
73  g_bugrigs_air_steering = cvar("g_bugrigs_air_steering");
74  g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing");
75  g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor");
76  g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake");
77  g_bugrigs_friction_air = cvar("g_bugrigs_friction_air");
78  g_bugrigs_accel = cvar("g_bugrigs_accel");
79  g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref");
80  g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
81  g_bugrigs_steer = cvar("g_bugrigs_steer");
82 }
83 
84 #endif
85 
86 float racecar_angle(float forward, float down)
87 {
88  if (forward < 0)
89  {
90  forward = -forward;
91  down = -down;
92  }
93 
94  float ret = vectoyaw('0 1 0' * down + '1 0 0' * forward);
95 
96  float angle_mult = forward / (800 + forward);
97 
98  if (ret > 180)
99  return ret * angle_mult + 360 * (1 - angle_mult);
100  else
101  return ret * angle_mult;
102 }
103 
104 void RaceCarPhysics(entity this, float dt)
105 {
106  // using this move type for "big rigs"
107  // the engine does not push the entity!
108 
109  vector rigvel;
110 
111  vector angles_save = this.angles;
112  float accel = bound(-1, PHYS_CS(this).movement.x / PHYS_MAXSPEED(this), 1);
113  float steer = bound(-1, PHYS_CS(this).movement.y / PHYS_MAXSPEED(this), 1);
114 
115  if (PHYS_BUGRIGS_REVERSE_SPEEDING(this))
116  {
117  if (accel < 0)
118  {
119  // back accel is DIGITAL
120  // to prevent speedhack
121  if (accel < -0.5)
122  accel = -1;
123  else
124  accel = 0;
125  }
126  }
127 
128  this.angles_x = 0;
129  this.angles_z = 0;
130  makevectors(this.angles); // new forward direction!
131 
132  if (IS_ONGROUND(this) || PHYS_BUGRIGS_AIR_STEERING(this))
133  {
134  float myspeed = this.velocity * v_forward;
135  float upspeed = this.velocity * v_up;
136 
137  // responsiveness factor for steering and acceleration
138  float f = 1 / (1 + ((max(-myspeed, myspeed) / PHYS_BUGRIGS_SPEED_REF(this)) ** PHYS_BUGRIGS_SPEED_POW(this)));
139  //MAXIMA: f(v) := 1 / (1 + (v / PHYS_BUGRIGS_SPEED_REF(this)) ^ PHYS_BUGRIGS_SPEED_POW(this));
140 
141  float steerfactor;
142  if (myspeed < 0 && PHYS_BUGRIGS_REVERSE_SPINNING(this))
143  steerfactor = -myspeed * PHYS_BUGRIGS_STEER(this);
144  else
145  steerfactor = -myspeed * f * PHYS_BUGRIGS_STEER(this);
146 
147  float accelfactor;
148  if (myspeed < 0 && PHYS_BUGRIGS_REVERSE_SPEEDING(this))
149  accelfactor = PHYS_BUGRIGS_ACCEL(this);
150  else
151  accelfactor = f * PHYS_BUGRIGS_ACCEL(this);
152  //MAXIMA: accel(v) := f(v) * PHYS_BUGRIGS_ACCEL(this);
153 
154  if (accel < 0)
155  {
156  if (myspeed > 0)
157  {
158  myspeed = max(0, myspeed - dt * (PHYS_BUGRIGS_FRICTION_FLOOR(this) - PHYS_BUGRIGS_FRICTION_BRAKE(this) * accel));
159  }
160  else
161  {
162  if (!PHYS_BUGRIGS_REVERSE_SPEEDING(this))
163  myspeed = min(0, myspeed + dt * PHYS_BUGRIGS_FRICTION_FLOOR(this));
164  }
165  }
166  else
167  {
168  if (myspeed >= 0)
169  {
170  myspeed = max(0, myspeed - dt * PHYS_BUGRIGS_FRICTION_FLOOR(this));
171  }
172  else
173  {
174  if (PHYS_BUGRIGS_REVERSE_STOPPING(this))
175  myspeed = 0;
176  else
177  myspeed = min(0, myspeed + dt * (PHYS_BUGRIGS_FRICTION_FLOOR(this) + PHYS_BUGRIGS_FRICTION_BRAKE(this) * accel));
178  }
179  }
180  // terminal velocity = velocity at which 50 == accelfactor, that is, 1549 units/sec
181  //MAXIMA: friction(v) := PHYS_BUGRIGS_FRICTION_FLOOR(this);
182 
183  this.angles_y += steer * dt * steerfactor; // apply steering
184  makevectors(this.angles); // new forward direction!
185 
186  myspeed += accel * accelfactor * dt;
187 
188  rigvel = myspeed * v_forward + '0 0 1' * upspeed;
189  }
190  else
191  {
192  float myspeed = vlen(this.velocity);
193 
194  // responsiveness factor for steering and acceleration
195  float f = 1 / (1 + (max(0, myspeed / PHYS_BUGRIGS_SPEED_REF(this)) ** PHYS_BUGRIGS_SPEED_POW(this)));
196  float steerfactor = -myspeed * f;
197  this.angles_y += steer * dt * steerfactor; // apply steering
198 
199  rigvel = this.velocity;
200  makevectors(this.angles); // new forward direction!
201  }
202 
203  rigvel *= max(0, 1 - vlen(rigvel) * PHYS_BUGRIGS_FRICTION_AIR(this) * dt);
204  //MAXIMA: airfriction(v) := v * v * PHYS_BUGRIGS_FRICTION_AIR(this);
205  //MAXIMA: total_acceleration(v) := accel(v) - friction(v) - airfriction(v);
206  //MAXIMA: solve(total_acceleration(v) = 0, v);
207 
208  if (PHYS_BUGRIGS_PLANAR_MOVEMENT(this))
209  {
210  vector rigvel_xy, neworigin, up;
211  float mt;
212 
213  rigvel_z -= dt * PHYS_GRAVITY(this); // 4x gravity plays better
214  rigvel_xy = vec2(rigvel);
215 
216  if (PHYS_BUGRIGS_CAR_JUMPING(this))
217  mt = MOVE_NORMAL;
218  else
219  mt = MOVE_NOMONSTERS;
220 
221  tracebox(this.origin, this.mins, this.maxs, this.origin + '0 0 1024', mt, this);
222  up = trace_endpos - this.origin;
223 
224  // BUG RIGS: align the move to the surface instead of doing collision testing
225  // can we move?
226  tracebox(trace_endpos, this.mins, this.maxs, trace_endpos + rigvel_xy * dt, mt, this);
227 
228  // align to surface
229  tracebox(trace_endpos, this.mins, this.maxs, trace_endpos - up + '0 0 1' * rigvel_z * dt, mt, this);
230 
231  if (trace_fraction < 0.5)
232  {
233  trace_fraction = 1;
234  neworigin = this.origin;
235  }
236  else
237  neworigin = trace_endpos;
238 
239  if (trace_fraction < 1)
240  {
241  // now set angles_x so that the car points parallel to the surface
242  this.angles = vectoangles(
243  '1 0 0' * v_forward.x * trace_plane_normal.z
244  +
245  '0 1 0' * v_forward.y * trace_plane_normal.z
246  +
247  '0 0 1' * -(v_forward.x * trace_plane_normal.x + v_forward.y * trace_plane_normal.y)
248  );
249  SET_ONGROUND(this);
250  }
251  else
252  {
253  // now set angles_x so that the car points forward, but is tilted in velocity direction
254  UNSET_ONGROUND(this);
255  }
256 
257  this.velocity = (neworigin - this.origin) * (1.0 / dt);
259  }
260  else
261  {
262  rigvel_z -= dt * PHYS_GRAVITY(this); // 4x gravity plays better
263  this.velocity = rigvel;
264  set_movetype(this, MOVETYPE_FLY);
265  }
266 
267  trace_fraction = 1;
268  tracebox(this.origin, this.mins, this.maxs, this.origin - '0 0 4', MOVE_NORMAL, this);
269  if (trace_fraction != 1)
270  {
271  this.angles = vectoangles2(
272  '1 0 0' * v_forward.x * trace_plane_normal.z
273  +
274  '0 1 0' * v_forward.y * trace_plane_normal.z
275  +
276  '0 0 1' * -(v_forward.x * trace_plane_normal.x + v_forward.y * trace_plane_normal.y),
278  );
279  }
280  else
281  {
282  vector vel_local;
283 
284  vel_local.x = v_forward * this.velocity;
285  vel_local.y = v_right * this.velocity;
286  vel_local.z = v_up * this.velocity;
287 
288  this.angles_x = racecar_angle(vel_local.x, vel_local.z);
289  this.angles_z = racecar_angle(-vel_local.y, vel_local.z);
290  }
291 
292  // smooth the angles
293  vector vf1, vu1, smoothangles;
294  makevectors(this.angles);
295  float f = bound(0, dt * PHYS_BUGRIGS_ANGLE_SMOOTHING(this), 1);
296  if (f == 0)
297  f = 1;
298  vf1 = v_forward * f;
299  vu1 = v_up * f;
300  makevectors(angles_save);
301  vf1 = vf1 + v_forward * (1 - f);
302  vu1 = vu1 + v_up * (1 - f);
303  smoothangles = vectoangles2(vf1, vu1);
304  this.angles_x = -smoothangles.x;
305  this.angles_z = smoothangles.z;
306 }
307 
308 #ifdef SVQC
309 .vector bugrigs_prevangles;
310 #endif
311 MUTATOR_HOOKFUNCTION(bugrigs, PM_Physics)
312 {
313  entity player = M_ARGV(0, entity);
314  float dt = M_ARGV(2, float);
315 
316  if(!PHYS_BUGRIGS(player) || !IS_PLAYER(player)) { return; }
317 
318 #ifdef SVQC
319  player.angles = player.bugrigs_prevangles;
320 #endif
321 
322  RaceCarPhysics(player, dt);
323  return true;
324 }
325 
326 MUTATOR_HOOKFUNCTION(bugrigs, PlayerPhysics)
327 {
328  if(!PHYS_BUGRIGS(M_ARGV(0, entity))) { return; }
329 #ifdef SVQC
330  entity player = M_ARGV(0, entity);
331  player.bugrigs_prevangles = player.angles;
332 
333  player.disableclientprediction = 2;
334 #endif
335 }
336 
337 #ifdef SVQC
338 
340 {
341  entity player = M_ARGV(0, entity);
342 
343  stuffcmd(player, "cl_cmd settemp chase_active 1\n");
344 }
345 
346 MUTATOR_HOOKFUNCTION(bugrigs, BuildMutatorsString)
347 {
348  M_ARGV(0, string) = strcat(M_ARGV(0, string), ":bugrigs");
349 }
350 
351 MUTATOR_HOOKFUNCTION(bugrigs, BuildMutatorsPrettyString)
352 {
353  M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Bug rigs");
354 }
355 
356 #endif
357 
358 #endif
359 
360 #endif
void ClientConnect(entity this)
ClientConnect
Definition: client.qc:1096
#define REGISTER_MUTATOR(id, dependence)
Definition: base.qh:263
entity() spawn
const float MOVE_NORMAL
Definition: csprogsdefs.qc:252
#define IS_ONGROUND(s)
Definition: movetypes.qh:16
vector maxs
Definition: csprogsdefs.qc:113
origin
Definition: ent_cs.qc:114
#define UNSET_ONGROUND(s)
Definition: movetypes.qh:18
const float MOVE_NOMONSTERS
Definition: csprogsdefs.qc:253
vector mins
Definition: csprogsdefs.qc:113
vector v_up
Definition: csprogsdefs.qc:31
spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 f1 s1 strcat(_("Level %s: "), "^BG%s\3\, _("^BGPress ^F2%s^BG to enter the game"))
vector trace_endpos
Definition: csprogsdefs.qc:37
#define M_ARGV(x, type)
Definition: events.qh:17
vector movement
#define stuffcmd(cl,...)
Definition: progsdefs.qh:23
vector(float skel, float bonenum) _skel_get_boneabs_hidden
float MOVETYPE_NOCLIP
Definition: progsdefs.qc:254
#define SET_ONGROUND(s)
Definition: movetypes.qh:17
vector v_right
Definition: csprogsdefs.qc:31
#define vec2(...)
Definition: vector.qh:90
vector trace_plane_normal
Definition: csprogsdefs.qc:38
vector angles
Definition: csprogsdefs.qc:104
#define MUTATOR_HOOKFUNCTION(...)
Definition: base.qh:310
#define MUTATOR_ONADD
Definition: base.qh:284
vector velocity
Definition: csprogsdefs.qc:103
#define PHYS_MAXSPEED(s)
Definition: player.qh:132
#define makevectors
Definition: post.qh:21
float trace_fraction
Definition: csprogsdefs.qc:36
void set_movetype(entity this, int mt)
float MOVETYPE_FLY
Definition: progsdefs.qc:251
#define IS_PLAYER(v)
Definition: utils.qh:9
vector v_forward
Definition: csprogsdefs.qc:31