float lastclientthink, sv_maxspeed, sv_friction, sv_accelerate, sv_stopspeed; float sv_edgefriction, cl_rollangle, cl_divspeed; .vector movement; // LordHavoc: // Highly optimized port of SV_ClientThink from engine code to QuakeC. // No behavior changes! This code is much shorter and probably faster than // the engine code :) // note that darkplaces engine will call this function if it finds it, // so modify for your own mods and enjoy... // note also, this code uses some builtin functions from dpextensions.qc // (included with darkplaces engine releases) // P.S. if you find something weird in this code, it's just mimicing weird // stuff in the original quake engine code (which was so unreadable it was // hard to even identify what it was doing) void() SV_PlayerPhysics = { local vector wishvel, wishdir, v; local float wishspeed, f, limit; if (self.movetype == MOVETYPE_NONE) return; if (self.punchangle != '0 0 0') { f = vlen(self.punchangle) - 10 * frametime; if (f > 0) self.punchangle = normalize(self.punchangle) * f; else self.punchangle = '0 0 0'; } // if dead, behave differently if (self.health <= 0) return; if (time != lastclientthink) { lastclientthink = time; sv_maxspeed = cvar("sv_maxspeed"); sv_friction = cvar("sv_friction"); sv_accelerate = cvar("sv_accelerate"); sv_stopspeed = cvar("sv_stopspeed"); sv_edgefriction = cvar("edgefriction"); // LordHavoc: this * 4 is an optimization cl_rollangle = cvar("cl_rollangle") * 4; // LordHavoc: this 1 / is an optimization cl_divspeed = 1 / cvar("cl_rollspeed"); } // show 1/3 the pitch angle and all the roll angle f = (self.velocity * v_right) * cl_divspeed; if (f < -1) f = -1; if (f > 1) f = 1; self.angles_z = f * cl_rollangle; if (!self.fixangle) { self.angles_x = (self.v_angle_x + self.punchangle_x) * -0.333; self.angles_y = self.v_angle_y + self.punchangle_y; } if (self.flags & FL_WATERJUMP ) { self.velocity_x = self.movedir_x; self.velocity_y = self.movedir_y; if (time > self.teleport_time || self.waterlevel == 0) { self.flags = self.flags - (self.flags & FL_WATERJUMP); self.teleport_time = 0; } return; } // swim if (self.waterlevel >= 2) if (self.movetype != MOVETYPE_NOCLIP) { makevectors(self.v_angle); if (self.movement == '0 0 0') wishvel = '0 0 -60'; // drift towards bottom else wishvel = v_forward * self.movement_x + v_right * self.movement_y + '0 0 1' * self.movement_z; wishspeed = vlen(wishvel); if (wishspeed > sv_maxspeed) wishspeed = sv_maxspeed * 0.7; else wishspeed = wishspeed * 0.7; // water friction if (self.velocity != '0 0 0') { f = vlen(self.velocity) * (1 - frametime * sv_friction); if (f > 0) self.velocity = normalize(self.velocity) * f; else self.velocity = '0 0 0'; } else f = 0; // water acceleration if (wishspeed <= f) return; limit = sv_accelerate * wishspeed * frametime; f = wishspeed - f; if (f > limit) self.velocity = self.velocity + normalize(wishvel) * limit; else self.velocity = self.velocity + normalize(wishvel) * f; return; } if (self.movetype == MOVETYPE_FLY) makevectors(self.v_angle); else makevectors(self.v_angle_y * '0 1 0'); // hack to not let you back into teleporter wishvel = v_right * self.movement_y; if (time >= self.teleport_time || self.movement_x > 0) wishvel = wishvel + v_forward * self.movement_x; if (self.movetype != MOVETYPE_WALK) wishvel_z = wishvel_z + self.movement_z; wishdir = normalize(wishvel); wishspeed = vlen(wishvel); if (wishspeed > sv_maxspeed) wishspeed = sv_maxspeed; if (self.movetype == MOVETYPE_NOCLIP || self.movetype == MOVETYPE_FLY) { self.velocity = wishdir * wishspeed; return; } if (self.flags & FL_ONGROUND) // walking { // friction if (self.velocity_x || self.velocity_y) { v = self.velocity; v_z = 0; f = vlen(v); // if the leading edge is over a dropoff, increase friction v = self.origin + normalize(v) * 16 + '0 0 1' * self.mins_z; traceline(v, v + '0 0 -34', TRUE, self); // apply friction if (trace_fraction == 1.0) { if (f < sv_stopspeed) f = 1 - frametime * (sv_stopspeed / f) * sv_friction * sv_edgefriction; else f = 1 - frametime * sv_friction * sv_edgefriction; } else { if (f < sv_stopspeed) f = 1 - frametime * (sv_stopspeed / f) * sv_friction; else f = 1 - frametime * sv_friction; } if (f < 0) self.velocity = '0 0 0'; else self.velocity = self.velocity * f; } } else // airborn if (wishspeed > 30) wishspeed = 30; // acceleration f = wishspeed - (self.velocity * wishdir); if (f > 0) { limit = sv_accelerate * frametime * wishspeed; if (f > limit) f = limit; self.velocity = self.velocity + wishdir * f; } }