X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=blobdiff_plain;f=qcsrc%2Fcommon%2Fphysics%2Fplayer.qc;fp=qcsrc%2Fcommon%2Fphysics%2Fplayer.qc;h=74a44252fe8bd6d7fc8a11a177ca7ad9c1dfd8ee;hp=1ef5faa59d87554dd9bad0d251e1ce687fa0c205;hb=05ee5b1212a6537e5c5acb76dbc1ef9df40f85c6;hpb=fce7138d4101cf3a8ad1e0400f08cffe21fbecda diff --git a/qcsrc/common/physics/player.qc b/qcsrc/common/physics/player.qc index 1ef5faa59..74a44252f 100644 --- a/qcsrc/common/physics/player.qc +++ b/qcsrc/common/physics/player.qc @@ -154,8 +154,8 @@ void PM_ClientMovement_UpdateStatus(entity this) } } - if (IS_ONGROUND(this) || this.velocity.z <= 0 || pmove_waterjumptime <= 0) - pmove_waterjumptime = 0; + if (IS_ONGROUND(this) || this.velocity.z <= 0 || PHYS_WATERJUMP_TIME(this) <= 0) + PHYS_WATERJUMP_TIME(this) = 0; #endif } @@ -434,7 +434,7 @@ void CheckWaterJump(entity this) #ifdef SVQC PHYS_TELEPORT_TIME(this) = time + 2; // safety net #elif defined(CSQC) - pmove_waterjumptime = 2; + PHYS_WATERJUMP_TIME(this) = 2; #endif } } @@ -681,182 +681,7 @@ void PM_check_blocked(entity this) #endif } -void PM_fly(entity this, float maxspd_mod) -{ - // noclipping or flying - UNSET_ONGROUND(this); - - this.velocity = this.velocity * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION(this)); - makevectors(this.v_angle); - //wishvel = v_forward * this.movement.x + v_right * this.movement.y + v_up * this.movement.z; - vector wishvel = v_forward * this.movement.x - + v_right * this.movement.y - + '0 0 1' * this.movement.z; - // acceleration - vector wishdir = normalize(wishvel); - float wishspeed = min(vlen(wishvel), PHYS_MAXSPEED(this) * maxspd_mod); -#ifdef SVQC - if(time >= PHYS_TELEPORT_TIME(this)) -#elif defined(CSQC) - if(pmove_waterjumptime <= 0) -#endif - PM_Accelerate(this, wishdir, wishspeed, wishspeed, PHYS_ACCELERATE(this) * maxspd_mod, 1, 0, 0, 0); -} - -void PM_swim(entity this, float maxspd_mod) -{ - // swimming - UNSET_ONGROUND(this); - - float jump = PHYS_INPUT_BUTTON_JUMP(this); - // water jump only in certain situations - // this mimics quakeworld code - if (jump && this.waterlevel == WATERLEVEL_SWIMMING && this.velocity_z >= -180 && !this.viewloc) - { - vector yawangles = '0 1 0' * this.v_angle.y; - makevectors(yawangles); - vector forward = v_forward; - vector spot = this.origin + 24 * forward; - spot_z += 8; - traceline(spot, spot, MOVE_NOMONSTERS, this); - if (trace_startsolid) - { - spot_z += 24; - traceline(spot, spot, MOVE_NOMONSTERS, this); - if (!trace_startsolid) - { - this.velocity = forward * 50; - this.velocity_z = 310; - UNSET_ONGROUND(this); - SET_JUMP_HELD(this); - } - } - } - makevectors(this.v_angle); - float wishdown = this.movement.z; - if(PHYS_INPUT_BUTTON_CROUCH(this)) - wishdown = -PHYS_MAXSPEED(this); - //wishvel = v_forward * this.movement.x + v_right * this.movement.y + v_up * this.movement.z; - vector wishvel = v_forward * this.movement.x - + v_right * this.movement.y - + '0 0 1' * wishdown; - if(this.viewloc) - wishvel.z = -160; // drift anyway - else if (wishvel == '0 0 0') - wishvel = '0 0 -60'; // drift towards bottom - - vector wishdir = normalize(wishvel); - float wishspeed = min(vlen(wishvel), PHYS_MAXSPEED(this) * maxspd_mod) * 0.7; - -// if (pmove_waterjumptime <= 0) // TODO: use - { - // water friction - float f = 1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION(this); - f = min(max(0, f), 1); - this.velocity *= f; - - f = wishspeed - this.velocity * wishdir; - if (f > 0) - { - float accelspeed = min(PHYS_ACCELERATE(this) * PHYS_INPUT_TIMELENGTH * wishspeed, f); - this.velocity += accelspeed * wishdir; - } - - // holding jump button swims upward slowly - if (jump && !this.viewloc) - { -#if 0 - if (this.watertype & CONTENT_LAVA) - this.velocity_z = 50; - else if (this.watertype & CONTENT_SLIME) - this.velocity_z = 80; - else - { - if (IS_NEXUIZ_DERIVED(gamemode)) -#endif - if(this.waterlevel >= WATERLEVEL_SUBMERGED) - this.velocity_z = PHYS_MAXSPEED(this); - else - this.velocity_z = 200; -#if 0 - else - this.velocity_z = 100; - } -#endif - } - } - if(this.viewloc) - { - const float addspeed = wishspeed - this.velocity * wishdir; - if (addspeed > 0) - { - const float accelspeed = min(PHYS_ACCELERATE(this) * PHYS_INPUT_TIMELENGTH * wishspeed, addspeed); - this.velocity += accelspeed * wishdir; - } - } - else - { - // water acceleration - PM_Accelerate(this, wishdir, wishspeed, wishspeed, PHYS_ACCELERATE(this) * maxspd_mod, 1, 0, 0, 0); - } -} - .vector oldmovement; -void PM_ladder(entity this, float maxspd_mod) -{ - // on a spawnfunc_func_ladder or swimming in spawnfunc_func_water - UNSET_ONGROUND(this); - - float g; - g = PHYS_GRAVITY(this) * PHYS_INPUT_TIMELENGTH; - if (PHYS_ENTGRAVITY(this)) - g *= PHYS_ENTGRAVITY(this); - if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE) - { - g *= 0.5; - this.velocity_z += g; - } - - this.velocity = this.velocity * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION(this)); - makevectors(this.v_angle); - //wishvel = v_forward * this.movement.x + v_right * this.movement.y + v_up * this.movement.z; - vector wishvel = v_forward * this.movement_x - + v_right * this.movement_y - + '0 0 1' * this.movement_z; - if(this.viewloc) - wishvel.z = this.oldmovement.x; - this.velocity_z += g; - if (this.ladder_entity.classname == "func_water") - { - float f = vlen(wishvel); - if (f > this.ladder_entity.speed) - wishvel *= (this.ladder_entity.speed / f); - - this.watertype = this.ladder_entity.skin; - f = this.ladder_entity.origin_z + this.ladder_entity.maxs_z; - if ((this.origin_z + this.view_ofs_z) < f) - this.waterlevel = WATERLEVEL_SUBMERGED; - else if ((this.origin_z + (this.mins_z + this.maxs_z) * 0.5) < f) - this.waterlevel = WATERLEVEL_SWIMMING; - else if ((this.origin_z + this.mins_z + 1) < f) - this.waterlevel = WATERLEVEL_WETFEET; - else - { - this.waterlevel = WATERLEVEL_NONE; - this.watertype = CONTENT_EMPTY; - } - } - // acceleration - vector wishdir = normalize(wishvel); - float wishspeed = min(vlen(wishvel), PHYS_MAXSPEED(this) * maxspd_mod); -#ifdef SVQC - if(time >= PHYS_TELEPORT_TIME(this)) -#elif defined(CSQC) - if(pmove_waterjumptime <= 0) -#endif - // water acceleration - PM_Accelerate(this, wishdir, wishspeed, wishspeed, PHYS_ACCELERATE(this)*maxspd_mod, 1, 0, 0, 0); -} void PM_jetpack(entity this, float maxspd_mod) { @@ -966,146 +791,6 @@ void PM_jetpack(entity this, float maxspd_mod) } } -void PM_walk(entity this, float maxspd_mod) -{ - if (!WAS_ONGROUND(this)) - { -#ifdef SVQC - if (autocvar_speedmeter) - LOG_TRACE(strcat("landing velocity: ", vtos(this.velocity), " (abs: ", ftos(vlen(this.velocity)), ")\n")); -#endif - if (this.lastground < time - 0.3) - this.velocity *= (1 - PHYS_FRICTION_ONLAND(this)); -#ifdef SVQC - if (this.jumppadcount > 1) - LOG_TRACE(strcat(ftos(this.jumppadcount), "x jumppad combo\n")); - this.jumppadcount = 0; -#endif - } - - // walking - makevectors(this.v_angle.y * '0 1 0'); - const vector wishvel = v_forward * this.movement.x - + v_right * this.movement.y; - // acceleration - const vector wishdir = normalize(wishvel); - float wishspeed = vlen(wishvel); - wishspeed = min(wishspeed, PHYS_MAXSPEED(this) * maxspd_mod); - if (IS_DUCKED(this)) wishspeed *= 0.5; - - // apply edge friction - const float f2 = vlen2(vec2(this.velocity)); - if (f2 > 0) - { - trace_dphitq3surfaceflags = 0; - tracebox(this.origin, this.mins, this.maxs, this.origin - '0 0 1', MOVE_NOMONSTERS, this); - // TODO: apply edge friction - // apply ground friction - const int realfriction = (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK) - ? PHYS_FRICTION_SLICK(this) - : PHYS_FRICTION(this); - - float f = sqrt(f2); - f = 1 - PHYS_INPUT_TIMELENGTH * realfriction * ((f < PHYS_STOPSPEED(this)) ? (PHYS_STOPSPEED(this) / f) : 1); - f = max(0, f); - this.velocity *= f; - /* - Mathematical analysis time! - - Our goal is to invert this mess. - - For the two cases we get: - v = v0 * (1 - PHYS_INPUT_TIMELENGTH * (PHYS_STOPSPEED(this) / v0) * PHYS_FRICTION(this)) - = v0 - PHYS_INPUT_TIMELENGTH * PHYS_STOPSPEED(this) * PHYS_FRICTION(this) - v0 = v + PHYS_INPUT_TIMELENGTH * PHYS_STOPSPEED(this) * PHYS_FRICTION(this) - and - v = v0 * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION(this)) - v0 = v / (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION(this)) - - These cases would be chosen ONLY if: - v0 < PHYS_STOPSPEED(this) - v + PHYS_INPUT_TIMELENGTH * PHYS_STOPSPEED(this) * PHYS_FRICTION(this) < PHYS_STOPSPEED(this) - v < PHYS_STOPSPEED(this) * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION(this)) - and, respectively: - v0 >= PHYS_STOPSPEED(this) - v / (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION(this)) >= PHYS_STOPSPEED(this) - v >= PHYS_STOPSPEED(this) * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION(this)) - */ - } - const float addspeed = wishspeed - this.velocity * wishdir; - if (addspeed > 0) - { - const float accelspeed = min(PHYS_ACCELERATE(this) * PHYS_INPUT_TIMELENGTH * wishspeed, addspeed); - this.velocity += accelspeed * wishdir; - } -} - -void PM_air(entity this, float buttons_prev, float maxspd_mod) -{ - makevectors(this.v_angle.y * '0 1 0'); - vector wishvel = v_forward * this.movement.x - + v_right * this.movement.y; - // acceleration - vector wishdir = normalize(wishvel); - float wishspeed = vlen(wishvel); - -#ifdef SVQC - if(time >= PHYS_TELEPORT_TIME(this)) -#elif defined(CSQC) - if(pmove_waterjumptime <= 0) -#endif - { - float maxairspd = PHYS_MAXAIRSPEED(this) * min(maxspd_mod, 1); - - // apply air speed limit - float airaccelqw = PHYS_AIRACCEL_QW(this); - float wishspeed0 = wishspeed; - wishspeed = min(wishspeed, maxairspd); - if (IS_DUCKED(this)) - wishspeed *= 0.5; - float airaccel = PHYS_AIRACCELERATE(this) * min(maxspd_mod, 1); - - float accelerating = (this.velocity * wishdir > 0); - float wishspeed2 = wishspeed; - - // CPM: air control - if (PHYS_AIRSTOPACCELERATE(this)) - { - vector curdir = normalize(vec2(this.velocity)); - airaccel += (PHYS_AIRSTOPACCELERATE(this)*maxspd_mod - airaccel) * max(0, -(curdir * wishdir)); - } - // note that for straight forward jumping: - // step = accel * PHYS_INPUT_TIMELENGTH * wishspeed0; - // accel = bound(0, wishspeed - vel_xy_current, step) * accelqw + step * (1 - accelqw); - // --> - // dv/dt = accel * maxspeed (when slow) - // dv/dt = accel * maxspeed * (1 - accelqw) (when fast) - // log dv/dt = logaccel + logmaxspeed (when slow) - // log dv/dt = logaccel + logmaxspeed + log(1 - accelqw) (when fast) - float strafity = IsMoveInDirection(this.movement, -90) + IsMoveInDirection(this.movement, +90); // if one is nonzero, other is always zero - if (PHYS_MAXAIRSTRAFESPEED(this)) - wishspeed = min(wishspeed, GeomLerp(PHYS_MAXAIRSPEED(this)*maxspd_mod, strafity, PHYS_MAXAIRSTRAFESPEED(this)*maxspd_mod)); - if (PHYS_AIRSTRAFEACCELERATE(this)) - airaccel = GeomLerp(airaccel, strafity, PHYS_AIRSTRAFEACCELERATE(this)*maxspd_mod); - if (PHYS_AIRSTRAFEACCEL_QW(this)) - airaccelqw = - (((strafity > 0.5 ? PHYS_AIRSTRAFEACCEL_QW(this) : PHYS_AIRACCEL_QW(this)) >= 0) ? +1 : -1) - * - (1 - GeomLerp(1 - fabs(PHYS_AIRACCEL_QW(this)), strafity, 1 - fabs(PHYS_AIRSTRAFEACCEL_QW(this)))); - // !CPM - - if (PHYS_WARSOWBUNNY_TURNACCEL(this) && accelerating && this.movement.y == 0 && this.movement.x != 0) - PM_AirAccelerate(this, wishdir, wishspeed2); - else { - float sidefric = maxairspd ? (PHYS_AIRACCEL_SIDEWAYS_FRICTION(this) / maxairspd) : 0; - PM_Accelerate(this, wishdir, wishspeed, wishspeed0, airaccel, airaccelqw, PHYS_AIRACCEL_QW_STRETCHFACTOR(this), sidefric, PHYS_AIRSPEEDLIMIT_NONQW(this)); - } - - if (PHYS_AIRCONTROL(this)) - CPM_PM_Aircontrol(this, wishdir, wishspeed2); - } -} - // used for calculating airshots bool IsFlying(entity this) { @@ -1119,267 +804,15 @@ bool IsFlying(entity this) return true; } -void PM_Main(entity this) -{ - int buttons = PHYS_INPUT_BUTTON_MASK(this); -#ifdef CSQC - this.items = STAT(ITEMS); - - this.movement = PHYS_INPUT_MOVEVALUES(this); - - this.spectatorspeed = STAT(SPECTATORSPEED); - - this.team = myteam + 1; // is this correct? - if (!(PHYS_INPUT_BUTTON_JUMP(this))) // !jump - UNSET_JUMP_HELD(this); // canjump = true - pmove_waterjumptime -= PHYS_INPUT_TIMELENGTH; - - PM_ClientMovement_UpdateStatus(this); -#endif - - this.oldmovement = this.movement; - - -#ifdef SVQC - WarpZone_PlayerPhysics_FixVAngle(this); -#endif - float maxspeed_mod = 1; - maxspeed_mod *= PHYS_HIGHSPEED(this); - -#ifdef SVQC - Physics_UpdateStats(this, maxspeed_mod); - - if (this.PlayerPhysplug) - if (this.PlayerPhysplug(this)) - return; -#elif defined(CSQC) - if(hud != HUD_NORMAL) - return; // no vehicle prediction (yet) -#endif - -#ifdef SVQC - anticheat_physics(this); -#endif - - if (PM_check_specialcommand(this, buttons)) - return; -#ifdef SVQC - if (sv_maxidle > 0) - { - if (buttons != this.buttons_old || this.movement != this.movement_old || this.v_angle != this.v_angle_old) - this.parm_idlesince = time; - } -#endif - int buttons_prev = this.buttons_old; - this.buttons_old = buttons; - this.movement_old = this.movement; - this.v_angle_old = this.v_angle; - - PM_check_nickspam(this); - - PM_check_punch(this); -#ifdef SVQC - if (IS_BOT_CLIENT(this)) - { - if (playerdemo_read(this)) - return; - bot_think(this); - } -#endif - -#ifdef SVQC - if (IS_PLAYER(this)) - { - const bool allowed_to_move = (time >= game_starttime); - if (!allowed_to_move) - { - this.velocity = '0 0 0'; - set_movetype(this, MOVETYPE_NONE); - this.disableclientprediction = 2; - } - else if (this.disableclientprediction == 2) - { - if (this.move_movetype == MOVETYPE_NONE) - set_movetype(this, MOVETYPE_WALK); - this.disableclientprediction = 0; - } - } -#endif - -#ifdef SVQC - if (this.move_movetype == MOVETYPE_NONE) - return; - - // when we get here, disableclientprediction cannot be 2 - this.disableclientprediction = (this.move_qcphysics) ? -1 : 0; -#endif - - viewloc_PlayerPhysics(this); - - PM_check_frozen(this); - - PM_check_blocked(this); - - maxspeed_mod = 1; - - if (this.in_swamp) - maxspeed_mod *= this.swamp_slowdown; //cvar("g_balance_swamp_moverate"); - - // conveyors: first fix velocity - if (this.conveyor.state) - this.velocity -= this.conveyor.movedir; - - MUTATOR_CALLHOOK(PlayerPhysics, this); - - if (!IS_PLAYER(this)) - { -#ifdef SVQC - maxspeed_mod = autocvar_sv_spectator_speed_multiplier; - if (!this.spectatorspeed) - this.spectatorspeed = maxspeed_mod; - if (this.impulse && this.impulse <= 19 || (this.impulse >= 200 && this.impulse <= 209) || (this.impulse >= 220 && this.impulse <= 229)) - { - if (this.lastclassname != STR_PLAYER) - { - if (this.impulse == 10 || this.impulse == 15 || this.impulse == 18 || (this.impulse >= 200 && this.impulse <= 209)) - this.spectatorspeed = bound(1, this.spectatorspeed + 0.5, 5); - else if (this.impulse == 11) - this.spectatorspeed = maxspeed_mod; - else if (this.impulse == 12 || this.impulse == 16 || this.impulse == 19 || (this.impulse >= 220 && this.impulse <= 229)) - this.spectatorspeed = bound(1, this.spectatorspeed - 0.5, 5); - else if (this.impulse >= 1 && this.impulse <= 9) - this.spectatorspeed = 1 + 0.5 * (this.impulse - 1); - } // otherwise just clear - this.impulse = 0; - } -#endif - maxspeed_mod = this.spectatorspeed; - } -#ifdef SVQC - - float spd = max(PHYS_MAXSPEED(this), PHYS_MAXAIRSPEED(this)) * maxspeed_mod; - if(this.speed != spd) - { - this.speed = spd; - string temps = ftos(spd); - stuffcmd(this, strcat("cl_forwardspeed ", temps, "\n")); - stuffcmd(this, strcat("cl_backspeed ", temps, "\n")); - stuffcmd(this, strcat("cl_sidespeed ", temps, "\n")); - stuffcmd(this, strcat("cl_upspeed ", temps, "\n")); - } - - if(this.jumpspeedcap_min != autocvar_sv_jumpspeedcap_min) - { - this.jumpspeedcap_min = autocvar_sv_jumpspeedcap_min; - stuffcmd(this, sprintf("\ncl_jumpspeedcap_min \"%s\"\n", autocvar_sv_jumpspeedcap_min)); - } - if(this.jumpspeedcap_max != autocvar_sv_jumpspeedcap_max) - { - this.jumpspeedcap_max = autocvar_sv_jumpspeedcap_max; - stuffcmd(this, sprintf("\ncl_jumpspeedcap_max \"%s\"\n", autocvar_sv_jumpspeedcap_max)); - } -#endif - - if(IS_DEAD(this)) - { - // handle water here - vector midpoint = ((this.absmin + this.absmax) * 0.5); - if(pointcontents(midpoint) == CONTENT_WATER) - { - this.velocity = this.velocity * 0.5; - - // do we want this? - //if(pointcontents(midpoint + '0 0 2') == CONTENT_WATER) - //{ this.velocity_z = 70; } - } - goto end; - } - -#ifdef SVQC - if (!this.fixangle) - this.angles = '0 1 0' * this.v_angle.y; -#endif - - if (IS_PLAYER(this) && IS_ONGROUND(this)) - { - PM_check_hitground(this); - PM_Footsteps(this); - } - -#ifdef SVQC - if(IsFlying(this)) - this.wasFlying = 1; -#endif - - if (IS_PLAYER(this)) - CheckPlayerJump(this); - - if (this.flags & FL_WATERJUMP) - { - this.velocity_x = this.movedir.x; - this.velocity_y = this.movedir.y; - if (this.waterlevel == WATERLEVEL_NONE - #ifdef CSQC - || pmove_waterjumptime <= 0 - #elif defined(SVQC) - || time > PHYS_TELEPORT_TIME(this) - #endif - ) - { - this.flags &= ~FL_WATERJUMP; - #ifdef CSQC - pmove_waterjumptime = 0; - #elif defined(CSQC) - PHYS_TELEPORT_TIME(this) = 0; - #endif - } - } - - else if (MUTATOR_CALLHOOK(PM_Physics, this, maxspeed_mod)) - { } - -#ifdef SVQC - else if (this.move_movetype == MOVETYPE_NOCLIP || this.move_movetype == MOVETYPE_FLY || this.move_movetype == MOVETYPE_FLY_WORLDONLY || MUTATOR_CALLHOOK(IsFlying, this)) -#elif defined(CSQC) - else if (this.move_movetype == MOVETYPE_NOCLIP || this.move_movetype == MOVETYPE_FLY || this.move_movetype == MOVETYPE_FLY_WORLDONLY || MUTATOR_CALLHOOK(IsFlying, this)) -#endif - PM_fly(this, maxspeed_mod); - - else if (this.waterlevel >= WATERLEVEL_SWIMMING) - PM_swim(this, maxspeed_mod); - - else if (time < this.ladder_time) - PM_ladder(this, maxspeed_mod); - - else if (ITEMS_STAT(this) & IT_USING_JETPACK) - PM_jetpack(this, maxspeed_mod); - - else if (IS_ONGROUND(this)) - PM_walk(this, maxspeed_mod); - - else - PM_air(this, buttons_prev, maxspeed_mod); - -LABEL(end) - if (IS_ONGROUND(this)) - this.lastground = time; - - // conveyors: then break velocity again - if(this.conveyor.state) - this.velocity += this.conveyor.movedir; - - this.lastflags = this.flags; - - this.lastclassname = this.classname; -} +void sys_phys_update(entity this, float dt); #if defined(SVQC) void SV_PlayerPhysics(entity this) #elif defined(CSQC) void CSQC_ClientMovement_PlayerMove_Frame(entity this) #endif { - PM_Main(this); + sys_phys_update(this, PHYS_INPUT_TIMELENGTH); #ifdef SVQC this.pm_frametime = frametime;