]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/mutators/mutator/bugrigs/bugrigs.qc
Merged master.
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / mutators / mutator / bugrigs / bugrigs.qc
1 #include "bugrigs.qh"
2
3 #ifdef GAMEQC
4
5 #ifdef SVQC
6         #include <server/antilag.qh>
7 #endif
8 #include <common/physics/player.qh>
9
10
11 #if defined(SVQC)
12 void bugrigs_SetVars();
13
14 REGISTER_MUTATOR(bugrigs, cvar("g_bugrigs"))
15 {
16         MUTATOR_ONADD
17         {
18                 bugrigs_SetVars();
19         }
20         return false;
21 }
22 #elif defined(CSQC)
23 REGISTER_MUTATOR(bugrigs, true);
24 #endif
25
26
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)
42
43 #if defined(SVQC)
44
45 void bugrigs_SetVars()
46 {
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");
62 }
63
64 #endif
65
66 float racecar_angle(float forward, float down)
67 {
68         if (forward < 0)
69         {
70                 forward = -forward;
71                 down = -down;
72         }
73
74         float ret = vectoyaw('0 1 0' * down + '1 0 0' * forward);
75
76         float angle_mult = forward / (800 + forward);
77
78         if (ret > 180)
79                 return ret * angle_mult + 360 * (1 - angle_mult);
80         else
81                 return ret * angle_mult;
82 }
83
84 void RaceCarPhysics(entity this, float dt)
85 {
86         // using this move type for "big rigs"
87         // the engine does not push the entity!
88
89         vector rigvel;
90
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);
94
95         if (PHYS_BUGRIGS_REVERSE_SPEEDING(this))
96         {
97                 if (accel < 0)
98                 {
99                         // back accel is DIGITAL
100                         // to prevent speedhack
101                         if (accel < -0.5)
102                                 accel = -1;
103                         else
104                                 accel = 0;
105                 }
106         }
107
108         this.angles_x = 0;
109         this.angles_z = 0;
110         makevectors(this.angles); // new forward direction!
111
112         if (IS_ONGROUND(this) || PHYS_BUGRIGS_AIR_STEERING(this))
113         {
114                 float myspeed = this.velocity * v_forward;
115                 float upspeed = this.velocity * v_up;
116
117                 // responsiveness factor for steering and acceleration
118                 float f = 1 / (1 + ((max(-myspeed, myspeed) / PHYS_BUGRIGS_SPEED_REF(this)) ** PHYS_BUGRIGS_SPEED_POW(this)));
119                 //MAXIMA: f(v) := 1 / (1 + (v / PHYS_BUGRIGS_SPEED_REF(this)) ^ PHYS_BUGRIGS_SPEED_POW(this));
120
121                 float steerfactor;
122                 if (myspeed < 0 && PHYS_BUGRIGS_REVERSE_SPINNING(this))
123                         steerfactor = -myspeed * PHYS_BUGRIGS_STEER(this);
124                 else
125                         steerfactor = -myspeed * f * PHYS_BUGRIGS_STEER(this);
126
127                 float accelfactor;
128                 if (myspeed < 0 && PHYS_BUGRIGS_REVERSE_SPEEDING(this))
129                         accelfactor = PHYS_BUGRIGS_ACCEL(this);
130                 else
131                         accelfactor = f * PHYS_BUGRIGS_ACCEL(this);
132                 //MAXIMA: accel(v) := f(v) * PHYS_BUGRIGS_ACCEL(this);
133
134                 if (accel < 0)
135                 {
136                         if (myspeed > 0)
137                         {
138                                 myspeed = max(0, myspeed - dt * (PHYS_BUGRIGS_FRICTION_FLOOR(this) - PHYS_BUGRIGS_FRICTION_BRAKE(this) * accel));
139                         }
140                         else
141                         {
142                                 if (!PHYS_BUGRIGS_REVERSE_SPEEDING(this))
143                                         myspeed = min(0, myspeed + dt * PHYS_BUGRIGS_FRICTION_FLOOR(this));
144                         }
145                 }
146                 else
147                 {
148                         if (myspeed >= 0)
149                         {
150                                 myspeed = max(0, myspeed - dt * PHYS_BUGRIGS_FRICTION_FLOOR(this));
151                         }
152                         else
153                         {
154                                 if (PHYS_BUGRIGS_REVERSE_STOPPING(this))
155                                         myspeed = 0;
156                                 else
157                                         myspeed = min(0, myspeed + dt * (PHYS_BUGRIGS_FRICTION_FLOOR(this) + PHYS_BUGRIGS_FRICTION_BRAKE(this) * accel));
158                         }
159                 }
160                 // terminal velocity = velocity at which 50 == accelfactor, that is, 1549 units/sec
161                 //MAXIMA: friction(v) := PHYS_BUGRIGS_FRICTION_FLOOR(this);
162
163                 this.angles_y += steer * dt * steerfactor; // apply steering
164                 makevectors(this.angles); // new forward direction!
165
166                 myspeed += accel * accelfactor * dt;
167
168                 rigvel = myspeed * v_forward + '0 0 1' * upspeed;
169         }
170         else
171         {
172                 float myspeed = vlen(this.velocity);
173
174                 // responsiveness factor for steering and acceleration
175                 float f = 1 / (1 + (max(0, myspeed / PHYS_BUGRIGS_SPEED_REF(this)) ** PHYS_BUGRIGS_SPEED_POW(this)));
176                 float steerfactor = -myspeed * f;
177                 this.angles_y += steer * dt * steerfactor; // apply steering
178
179                 rigvel = this.velocity;
180                 makevectors(this.angles); // new forward direction!
181         }
182
183         rigvel *= max(0, 1 - vlen(rigvel) * PHYS_BUGRIGS_FRICTION_AIR(this) * dt);
184         //MAXIMA: airfriction(v) := v * v * PHYS_BUGRIGS_FRICTION_AIR(this);
185         //MAXIMA: total_acceleration(v) := accel(v) - friction(v) - airfriction(v);
186         //MAXIMA: solve(total_acceleration(v) = 0, v);
187
188         if (PHYS_BUGRIGS_PLANAR_MOVEMENT(this))
189         {
190                 vector rigvel_xy, neworigin, up;
191                 float mt;
192
193                 rigvel_z -= dt * PHYS_GRAVITY(this); // 4x gravity plays better
194                 rigvel_xy = vec2(rigvel);
195
196                 if (PHYS_BUGRIGS_CAR_JUMPING(this))
197                         mt = MOVE_NORMAL;
198                 else
199                         mt = MOVE_NOMONSTERS;
200
201                 tracebox(this.origin, this.mins, this.maxs, this.origin + '0 0 1024', mt, this);
202                 up = trace_endpos - this.origin;
203
204                 // BUG RIGS: align the move to the surface instead of doing collision testing
205                 // can we move?
206                 tracebox(trace_endpos, this.mins, this.maxs, trace_endpos + rigvel_xy * dt, mt, this);
207
208                 // align to surface
209                 tracebox(trace_endpos, this.mins, this.maxs, trace_endpos - up + '0 0 1' * rigvel_z * dt, mt, this);
210
211                 if (trace_fraction < 0.5)
212                 {
213                         trace_fraction = 1;
214                         neworigin = this.origin;
215                 }
216                 else
217                         neworigin = trace_endpos;
218
219                 if (trace_fraction < 1)
220                 {
221                         // now set angles_x so that the car points parallel to the surface
222                         this.angles = vectoangles(
223                                         '1 0 0' * v_forward.x * trace_plane_normal.z
224                                         +
225                                         '0 1 0' * v_forward.y * trace_plane_normal.z
226                                         +
227                                         '0 0 1' * -(v_forward.x * trace_plane_normal.x + v_forward.y * trace_plane_normal.y)
228                                         );
229                         SET_ONGROUND(this);
230                 }
231                 else
232                 {
233                         // now set angles_x so that the car points forward, but is tilted in velocity direction
234                         UNSET_ONGROUND(this);
235                 }
236
237                 this.velocity = (neworigin - this.origin) * (1.0 / dt);
238                 set_movetype(this, MOVETYPE_NOCLIP);
239         }
240         else
241         {
242                 rigvel_z -= dt * PHYS_GRAVITY(this); // 4x gravity plays better
243                 this.velocity = rigvel;
244                 set_movetype(this, MOVETYPE_FLY);
245         }
246
247         trace_fraction = 1;
248         tracebox(this.origin, this.mins, this.maxs, this.origin - '0 0 4', MOVE_NORMAL, this);
249         if (trace_fraction != 1)
250         {
251                 this.angles = vectoangles2(
252                                 '1 0 0' * v_forward.x * trace_plane_normal.z
253                                 +
254                                 '0 1 0' * v_forward.y * trace_plane_normal.z
255                                 +
256                                 '0 0 1' * -(v_forward.x * trace_plane_normal.x + v_forward.y * trace_plane_normal.y),
257                                 trace_plane_normal
258                                 );
259         }
260         else
261         {
262                 vector vel_local;
263
264                 vel_local.x = v_forward * this.velocity;
265                 vel_local.y = v_right * this.velocity;
266                 vel_local.z = v_up * this.velocity;
267
268                 this.angles_x = racecar_angle(vel_local.x, vel_local.z);
269                 this.angles_z = racecar_angle(-vel_local.y, vel_local.z);
270         }
271
272         // smooth the angles
273         vector vf1, vu1, smoothangles;
274         makevectors(this.angles);
275         float f = bound(0, dt * PHYS_BUGRIGS_ANGLE_SMOOTHING(this), 1);
276         if (f == 0)
277                 f = 1;
278         vf1 = v_forward * f;
279         vu1 = v_up * f;
280         makevectors(angles_save);
281         vf1 = vf1 + v_forward * (1 - f);
282         vu1 = vu1 + v_up * (1 - f);
283         smoothangles = vectoangles2(vf1, vu1);
284         this.angles_x = -smoothangles.x;
285         this.angles_z =  smoothangles.z;
286 }
287
288 #ifdef SVQC
289 .vector bugrigs_prevangles;
290 #endif
291 MUTATOR_HOOKFUNCTION(bugrigs, PM_Physics)
292 {
293     entity player = M_ARGV(0, entity);
294     float dt = M_ARGV(2, float);
295
296         if(!PHYS_BUGRIGS(player) || !IS_PLAYER(player)) { return; }
297
298 #ifdef SVQC
299         player.angles = player.bugrigs_prevangles;
300 #endif
301
302         RaceCarPhysics(player, dt);
303         return true;
304 }
305
306 MUTATOR_HOOKFUNCTION(bugrigs, PlayerPhysics)
307 {
308         if(!PHYS_BUGRIGS(M_ARGV(0, entity))) { return; }
309 #ifdef SVQC
310         entity player = M_ARGV(0, entity);
311         player.bugrigs_prevangles = player.angles;
312 #endif
313 }
314
315 #ifdef SVQC
316
317 MUTATOR_HOOKFUNCTION(bugrigs, ClientConnect)
318 {
319     entity player = M_ARGV(0, entity);
320
321         stuffcmd(player, "cl_cmd settemp chase_active 1\n");
322 }
323
324 MUTATOR_HOOKFUNCTION(bugrigs, BuildMutatorsString)
325 {
326         M_ARGV(0, string) = strcat(M_ARGV(0, string), ":bugrigs");
327 }
328
329 MUTATOR_HOOKFUNCTION(bugrigs, BuildMutatorsPrettyString)
330 {
331         M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Bug rigs");
332 }
333
334 #endif
335
336 #endif