#ifdef IMPLEMENTATION #ifdef SVQC #include "../../../../server/antilag.qh" #endif #include "../../../physics.qh" #if defined(SVQC) void bugrigs_SetVars(); REGISTER_MUTATOR(bugrigs, cvar("g_bugrigs")) { MUTATOR_ONADD { bugrigs_SetVars(); } return false; } #elif defined(CSQC) REGISTER_MUTATOR(bugrigs, true); #endif #define PHYS_BUGRIGS(s) STAT(BUGRIGS, s) #define PHYS_BUGRIGS_ACCEL(s) STAT(BUGRIGS_ACCEL, s) #define PHYS_BUGRIGS_AIR_STEERING(s) STAT(BUGRIGS_AIR_STEERING, s) #define PHYS_BUGRIGS_ANGLE_SMOOTHING(s) STAT(BUGRIGS_ANGLE_SMOOTHING, s) #define PHYS_BUGRIGS_CAR_JUMPING(s) STAT(BUGRIGS_CAR_JUMPING, s) #define PHYS_BUGRIGS_FRICTION_AIR(s) STAT(BUGRIGS_FRICTION_AIR, s) #define PHYS_BUGRIGS_FRICTION_BRAKE(s) STAT(BUGRIGS_FRICTION_BRAKE, s) #define PHYS_BUGRIGS_FRICTION_FLOOR(s) STAT(BUGRIGS_FRICTION_FLOOR, s) #define PHYS_BUGRIGS_PLANAR_MOVEMENT(s) STAT(BUGRIGS_PLANAR_MOVEMENT, s) #define PHYS_BUGRIGS_REVERSE_SPEEDING(s) STAT(BUGRIGS_REVERSE_SPEEDING, s) #define PHYS_BUGRIGS_REVERSE_SPINNING(s) STAT(BUGRIGS_REVERSE_SPINNING, s) #define PHYS_BUGRIGS_REVERSE_STOPPING(s) STAT(BUGRIGS_REVERSE_STOPPING, s) #define PHYS_BUGRIGS_SPEED_POW(s) STAT(BUGRIGS_SPEED_POW, s) #define PHYS_BUGRIGS_SPEED_REF(s) STAT(BUGRIGS_SPEED_REF, s) #define PHYS_BUGRIGS_STEER(s) STAT(BUGRIGS_STEER, s) #if defined(SVQC) void bugrigs_SetVars() { g_bugrigs = cvar("g_bugrigs"); g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement"); g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping"); g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning"); g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding"); g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping"); g_bugrigs_air_steering = cvar("g_bugrigs_air_steering"); g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing"); g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor"); g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake"); g_bugrigs_friction_air = cvar("g_bugrigs_friction_air"); g_bugrigs_accel = cvar("g_bugrigs_accel"); g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref"); g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow"); g_bugrigs_steer = cvar("g_bugrigs_steer"); } #endif void RaceCarPhysics(entity this) { // using this move type for "big rigs" // the engine does not push the entity! vector rigvel; vector angles_save = this.angles; float accel = bound(-1, this.movement.x / PHYS_MAXSPEED(this), 1); float steer = bound(-1, this.movement.y / PHYS_MAXSPEED(this), 1); if (PHYS_BUGRIGS_REVERSE_SPEEDING(this)) { if (accel < 0) { // back accel is DIGITAL // to prevent speedhack if (accel < -0.5) accel = -1; else accel = 0; } } this.angles_x = 0; this.angles_z = 0; makevectors(this.angles); // new forward direction! if (IS_ONGROUND(this) || PHYS_BUGRIGS_AIR_STEERING(this)) { float myspeed = this.velocity * v_forward; float upspeed = this.velocity * v_up; // responsiveness factor for steering and acceleration float f = 1 / (1 + pow(max(-myspeed, myspeed) / PHYS_BUGRIGS_SPEED_REF(this), PHYS_BUGRIGS_SPEED_POW(this))); //MAXIMA: f(v) := 1 / (1 + (v / PHYS_BUGRIGS_SPEED_REF(this)) ^ PHYS_BUGRIGS_SPEED_POW(this)); float steerfactor; if (myspeed < 0 && PHYS_BUGRIGS_REVERSE_SPINNING(this)) steerfactor = -myspeed * PHYS_BUGRIGS_STEER(this); else steerfactor = -myspeed * f * PHYS_BUGRIGS_STEER(this); float accelfactor; if (myspeed < 0 && PHYS_BUGRIGS_REVERSE_SPEEDING(this)) accelfactor = PHYS_BUGRIGS_ACCEL(this); else accelfactor = f * PHYS_BUGRIGS_ACCEL(this); //MAXIMA: accel(v) := f(v) * PHYS_BUGRIGS_ACCEL(this); if (accel < 0) { if (myspeed > 0) { myspeed = max(0, myspeed - PHYS_INPUT_TIMELENGTH * (PHYS_BUGRIGS_FRICTION_FLOOR(this) - PHYS_BUGRIGS_FRICTION_BRAKE(this) * accel)); } else { if (!PHYS_BUGRIGS_REVERSE_SPEEDING(this)) myspeed = min(0, myspeed + PHYS_INPUT_TIMELENGTH * PHYS_BUGRIGS_FRICTION_FLOOR(this)); } } else { if (myspeed >= 0) { myspeed = max(0, myspeed - PHYS_INPUT_TIMELENGTH * PHYS_BUGRIGS_FRICTION_FLOOR(this)); } else { if (PHYS_BUGRIGS_REVERSE_STOPPING(this)) myspeed = 0; else myspeed = min(0, myspeed + PHYS_INPUT_TIMELENGTH * (PHYS_BUGRIGS_FRICTION_FLOOR(this) + PHYS_BUGRIGS_FRICTION_BRAKE(this) * accel)); } } // terminal velocity = velocity at which 50 == accelfactor, that is, 1549 units/sec //MAXIMA: friction(v) := PHYS_BUGRIGS_FRICTION_FLOOR(this); this.angles_y += steer * PHYS_INPUT_TIMELENGTH * steerfactor; // apply steering makevectors(this.angles); // new forward direction! myspeed += accel * accelfactor * PHYS_INPUT_TIMELENGTH; rigvel = myspeed * v_forward + '0 0 1' * upspeed; } else { float myspeed = vlen(this.velocity); // responsiveness factor for steering and acceleration float f = 1 / (1 + pow(max(0, myspeed / PHYS_BUGRIGS_SPEED_REF(this)), PHYS_BUGRIGS_SPEED_POW(this))); float steerfactor = -myspeed * f; this.angles_y += steer * PHYS_INPUT_TIMELENGTH * steerfactor; // apply steering rigvel = this.velocity; makevectors(this.angles); // new forward direction! } rigvel *= max(0, 1 - vlen(rigvel) * PHYS_BUGRIGS_FRICTION_AIR(this) * PHYS_INPUT_TIMELENGTH); //MAXIMA: airfriction(v) := v * v * PHYS_BUGRIGS_FRICTION_AIR(this); //MAXIMA: total_acceleration(v) := accel(v) - friction(v) - airfriction(v); //MAXIMA: solve(total_acceleration(v) = 0, v); if (PHYS_BUGRIGS_PLANAR_MOVEMENT(this)) { vector rigvel_xy, neworigin, up; float mt; rigvel_z -= PHYS_INPUT_TIMELENGTH * PHYS_GRAVITY(this); // 4x gravity plays better rigvel_xy = vec2(rigvel); if (PHYS_BUGRIGS_CAR_JUMPING(this)) mt = MOVE_NORMAL; else mt = MOVE_NOMONSTERS; tracebox(this.origin, this.mins, this.maxs, this.origin + '0 0 1024', mt, this); up = trace_endpos - this.origin; // BUG RIGS: align the move to the surface instead of doing collision testing // can we move? tracebox(trace_endpos, this.mins, this.maxs, trace_endpos + rigvel_xy * PHYS_INPUT_TIMELENGTH, mt, this); // align to surface tracebox(trace_endpos, this.mins, this.maxs, trace_endpos - up + '0 0 1' * rigvel_z * PHYS_INPUT_TIMELENGTH, mt, this); if (trace_fraction < 0.5) { trace_fraction = 1; neworigin = this.origin; } else neworigin = trace_endpos; if (trace_fraction < 1) { // now set angles_x so that the car points parallel to the surface this.angles = vectoangles( '1 0 0' * v_forward_x * trace_plane_normal_z + '0 1 0' * v_forward_y * trace_plane_normal_z + '0 0 1' * -(v_forward_x * trace_plane_normal_x + v_forward_y * trace_plane_normal_y) ); SET_ONGROUND(this); } else { // now set angles_x so that the car points forward, but is tilted in velocity direction UNSET_ONGROUND(this); } this.velocity = (neworigin - this.origin) * (1.0 / PHYS_INPUT_TIMELENGTH); this.movetype = MOVETYPE_NOCLIP; } else { rigvel_z -= PHYS_INPUT_TIMELENGTH * PHYS_GRAVITY(this); // 4x gravity plays better this.velocity = rigvel; this.movetype = MOVETYPE_FLY; } trace_fraction = 1; tracebox(this.origin, this.mins, this.maxs, this.origin - '0 0 4', MOVE_NORMAL, this); if (trace_fraction != 1) { this.angles = vectoangles2( '1 0 0' * v_forward_x * trace_plane_normal_z + '0 1 0' * v_forward_y * trace_plane_normal_z + '0 0 1' * -(v_forward_x * trace_plane_normal_x + v_forward_y * trace_plane_normal_y), trace_plane_normal ); } else { vector vel_local; vel_local_x = v_forward * this.velocity; vel_local_y = v_right * this.velocity; vel_local_z = v_up * this.velocity; this.angles_x = racecar_angle(vel_local_x, vel_local_z); this.angles_z = racecar_angle(-vel_local_y, vel_local_z); } // smooth the angles vector vf1, vu1, smoothangles; makevectors(this.angles); float f = bound(0, PHYS_INPUT_TIMELENGTH * PHYS_BUGRIGS_ANGLE_SMOOTHING(this), 1); if (f == 0) f = 1; vf1 = v_forward * f; vu1 = v_up * f; makevectors(angles_save); vf1 = vf1 + v_forward * (1 - f); vu1 = vu1 + v_up * (1 - f); smoothangles = vectoangles2(vf1, vu1); this.angles_x = -smoothangles_x; this.angles_z = smoothangles_z; PM_ClientMovement_Move(this); } #ifdef SVQC .vector bugrigs_prevangles; #endif MUTATOR_HOOKFUNCTION(bugrigs, PM_Physics) { if(!PHYS_BUGRIGS(self) || !IS_PLAYER(self)) { return false; } #ifdef SVQC self.angles = self.bugrigs_prevangles; #endif RaceCarPhysics(self); return true; } MUTATOR_HOOKFUNCTION(bugrigs, PlayerPhysics) { if(!PHYS_BUGRIGS(self)) { return false; } #ifdef SVQC self.bugrigs_prevangles = self.angles; #endif return false; } #ifdef SVQC MUTATOR_HOOKFUNCTION(bugrigs, ClientConnect) { stuffcmd(self, "cl_cmd settemp chase_active 1\n"); return false; } MUTATOR_HOOKFUNCTION(bugrigs, BuildMutatorsString) { ret_string = strcat(ret_string, ":bugrigs"); return false; } MUTATOR_HOOKFUNCTION(bugrigs, BuildMutatorsPrettyString) { ret_string = strcat(ret_string, ", Bug rigs"); return false; } #endif #endif