]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/mutators/mutator/bugrigs/bugrigs.qc
Transifex autosync
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / mutators / mutator / bugrigs / bugrigs.qc
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 {
18         MUTATOR_ONADD
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);
258                 set_movetype(this, MOVETYPE_NOCLIP);
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),
277                                 trace_plane_normal
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
339 MUTATOR_HOOKFUNCTION(bugrigs, ClientConnect)
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