Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
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
11
12
13#if defined(SVQC)
14void bugrigs_SetVars();
15
16REGISTER_MUTATOR(bugrigs, cvar("g_bugrigs"))
17{
19 {
21 }
22 return false;
23}
24#elif defined(CSQC)
25REGISTER_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
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
86float 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
104void 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
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 {
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 {
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
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 +
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;
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
310#endif
311MUTATOR_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
326MUTATOR_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
346MUTATOR_HOOKFUNCTION(bugrigs, BuildMutatorsString)
347{
348 M_ARGV(0, string) = strcat(M_ARGV(0, string), ":bugrigs");
349}
350
351MUTATOR_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
#define MUTATOR_ONADD
Definition base.qh:309
#define REGISTER_MUTATOR(...)
Definition base.qh:295
#define MUTATOR_HOOKFUNCTION(...)
Definition base.qh:335
#define PHYS_BUGRIGS_REVERSE_SPINNING(s)
Definition bugrigs.qc:56
#define PHYS_BUGRIGS_FRICTION_FLOOR(s)
Definition bugrigs.qc:53
#define PHYS_BUGRIGS_SPEED_POW(s)
Definition bugrigs.qc:58
#define PHYS_BUGRIGS_STEER(s)
Definition bugrigs.qc:60
#define PHYS_BUGRIGS_REVERSE_SPEEDING(s)
Definition bugrigs.qc:55
void RaceCarPhysics(entity this, float dt)
Definition bugrigs.qc:104
float racecar_angle(float forward, float down)
Definition bugrigs.qc:86
#define PHYS_BUGRIGS_FRICTION_BRAKE(s)
Definition bugrigs.qc:52
#define PHYS_BUGRIGS_FRICTION_AIR(s)
Definition bugrigs.qc:51
#define PHYS_BUGRIGS_ACCEL(s)
Definition bugrigs.qc:47
#define PHYS_BUGRIGS_CAR_JUMPING(s)
Definition bugrigs.qc:50
vector bugrigs_prevangles
Definition bugrigs.qc:309
#define PHYS_BUGRIGS_SPEED_REF(s)
Definition bugrigs.qc:59
#define PHYS_BUGRIGS_REVERSE_STOPPING(s)
Definition bugrigs.qc:57
#define PHYS_BUGRIGS_ANGLE_SMOOTHING(s)
Definition bugrigs.qc:49
#define PHYS_BUGRIGS(s)
Definition bugrigs.qc:46
#define PHYS_BUGRIGS_AIR_STEERING(s)
Definition bugrigs.qc:48
#define PHYS_BUGRIGS_PLANAR_MOVEMENT(s)
Definition bugrigs.qc:54
void bugrigs_SetVars()
Definition bugrigs.qc:65
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
#define M_ARGV(x, type)
Definition events.qh:17
vector movement
Definition player.qh:229
#define PHYS_CS(s)
Definition player.qh:258
#define PHYS_MAXSPEED(s)
Definition player.qh:136
#define IS_PLAYER(s)
Definition player.qh:243
float g_bugrigs_accel
Definition stats.qh:182
float g_bugrigs_angle_smoothing
Definition stats.qh:178
float g_bugrigs_reverse_speeding
Definition stats.qh:175
float g_bugrigs_reverse_spinning
Definition stats.qh:174
float g_bugrigs_reverse_stopping
Definition stats.qh:176
float g_bugrigs_friction_air
Definition stats.qh:181
float g_bugrigs_friction_floor
Definition stats.qh:179
float g_bugrigs_air_steering
Definition stats.qh:177
bool g_bugrigs
Definition stats.qh:171
bool g_bugrigs_planar_movement
Definition stats.qh:172
float g_bugrigs_speed_ref
Definition stats.qh:183
float g_bugrigs_steer
Definition stats.qh:185
float g_bugrigs_friction_brake
Definition stats.qh:180
bool g_bugrigs_planar_movement_car_jumping
Definition stats.qh:173
float g_bugrigs_speed_pow
Definition stats.qh:184
vector v_up
const float MOVE_NOMONSTERS
const float MOVE_NORMAL
vector mins
vector velocity
vector v_right
vector trace_endpos
vector maxs
vector v_forward
vector origin
float trace_fraction
vector trace_plane_normal
ent angles
Definition ent_cs.qc:121
angles_y
Definition ent_cs.qc:119
#define ClientConnect
Definition _all.inc:238
float bound(float min, float value, float max)
float cvar(string name)
float vectoyaw(vector v)
float vlen(vector v)
vector vectoangles(vector v)
float min(float f,...)
float max(float f,...)
void set_movetype(entity this, int mt)
Definition movetypes.qc:4
#define PHYS_GRAVITY(s)
Definition movetypes.qh:53
#define SET_ONGROUND(s)
Definition movetypes.qh:17
#define UNSET_ONGROUND(s)
Definition movetypes.qh:18
const int MOVETYPE_NOCLIP
Definition movetypes.qh:137
const int MOVETYPE_FLY
Definition movetypes.qh:134
#define IS_ONGROUND(s)
Definition movetypes.qh:16
strcat(_("^F4Countdown stopped!"), "\n^BG", _("Teams are too unbalanced."))
#define makevectors
Definition post.qh:21
#define stuffcmd(cl,...)
Definition progsdefs.qh:23
vector
Definition self.qh:92
#define vec2(...)
Definition vector.qh:90