X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fcommon%2Fphysics%2Fplayer.qc;h=34518bda58467bc6f7236a282a952349fa0329af;hb=b9998b31fc75c66b601e66241350b10ca694809f;hp=3b86ebcecacc7433bfc8f86ad594e04d4f17be6c;hpb=47a7d93632e4a6125241310347cad0b0e0e4bf89;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/common/physics/player.qc b/qcsrc/common/physics/player.qc index 3b86ebcec..87d456c01 100644 --- a/qcsrc/common/physics/player.qc +++ b/qcsrc/common/physics/player.qc @@ -1,28 +1,32 @@ #include "player.qh" -#include "../triggers/include.qh" +#include "../mapobjects/_mod.qh" #include "../viewloc.qh" #ifdef SVQC #include -#include "../triggers/trigger/viewloc.qh" +#include "../mapobjects/trigger/viewloc.qh" // client side physics bool Physics_Valid(string thecvar) { - return autocvar_g_physics_clientselect && thecvar != "" && thecvar && thecvar != "default" && strhasword(autocvar_g_physics_clientselect_options, thecvar); + return thecvar != "" && thecvar && thecvar != "default" && strhasword(autocvar_g_physics_clientselect_options, thecvar); } float Physics_ClientOption(entity this, string option, float defaultval) { - if(IS_REAL_CLIENT(this) && Physics_Valid(this.cvar_cl_physics)) + if(!autocvar_g_physics_clientselect) + return defaultval; + + if(IS_REAL_CLIENT(this) && Physics_Valid(CS(this).cvar_cl_physics)) { - string s = strcat("g_physics_", this.cvar_cl_physics, "_", option); + string s = strcat("g_physics_", CS(this).cvar_cl_physics, "_", option); if(cvar_type(s) & CVAR_TYPEFLAG_EXISTS) return cvar(s); } - if(autocvar_g_physics_clientselect && autocvar_g_physics_clientselect_default) + if(autocvar_g_physics_clientselect_default && autocvar_g_physics_clientselect_default != "" && autocvar_g_physics_clientselect_default != "default") { + // NOTE: not using Physics_Valid here, so the default can be forced to something normally unavailable string s = strcat("g_physics_", autocvar_g_physics_clientselect_default, "_", option); if(cvar_type(s) & CVAR_TYPEFLAG_EXISTS) return cvar(s); @@ -30,8 +34,14 @@ float Physics_ClientOption(entity this, string option, float defaultval) return defaultval; } -void Physics_UpdateStats(entity this, float maxspd_mod) +void Physics_UpdateStats(entity this) { + // update this first, as it's used on all stats (wouldn't want to update them all manually from a mutator hook now, would we?) + STAT(MOVEVARS_HIGHSPEED, this) = autocvar_g_movement_highspeed; + + MUTATOR_CALLHOOK(PlayerPhysics_UpdateStats, this); + float maxspd_mod = PHYS_HIGHSPEED(this); + STAT(MOVEVARS_AIRACCEL_QW, this) = AdjustAirAccelQW(Physics_ClientOption(this, "airaccel_qw", autocvar_sv_airaccel_qw), maxspd_mod); STAT(MOVEVARS_AIRSTRAFEACCEL_QW, this) = (Physics_ClientOption(this, "airstrafeaccel_qw", autocvar_sv_airstrafeaccel_qw)) ? AdjustAirAccelQW(Physics_ClientOption(this, "airstrafeaccel_qw", autocvar_sv_airstrafeaccel_qw), maxspd_mod) @@ -39,12 +49,13 @@ void Physics_UpdateStats(entity this, float maxspd_mod) STAT(MOVEVARS_AIRSPEEDLIMIT_NONQW, this) = Physics_ClientOption(this, "airspeedlimit_nonqw", autocvar_sv_airspeedlimit_nonqw) * maxspd_mod; STAT(MOVEVARS_MAXSPEED, this) = Physics_ClientOption(this, "maxspeed", autocvar_sv_maxspeed) * maxspd_mod; // also slow walking - STAT(PL_MIN, this) = autocvar_sv_player_mins; - STAT(PL_MAX, this) = autocvar_sv_player_maxs; - STAT(PL_VIEW_OFS, this) = autocvar_sv_player_viewoffset; - STAT(PL_CROUCH_MIN, this) = autocvar_sv_player_crouch_mins; - STAT(PL_CROUCH_MAX, this) = autocvar_sv_player_crouch_maxs; - STAT(PL_CROUCH_VIEW_OFS, this) = autocvar_sv_player_crouch_viewoffset; + bool vq3compat = autocvar_sv_vq3compat && autocvar_sv_vq3compat_changehitbox; // NOTE: these hitboxes are off by 1 due to engine differences + STAT(PL_MIN, this) = (vq3compat) ? '-15 -15 -24' : autocvar_sv_player_mins; + STAT(PL_MAX, this) = (vq3compat) ? '15 15 32' : autocvar_sv_player_maxs; + STAT(PL_VIEW_OFS, this) = (vq3compat) ? '0 0 26' : autocvar_sv_player_viewoffset; + STAT(PL_CROUCH_MIN, this) = (vq3compat) ? '-15 -15 -24' : autocvar_sv_player_crouch_mins; + STAT(PL_CROUCH_MAX, this) = (vq3compat) ? '15 15 16' : autocvar_sv_player_crouch_maxs; + STAT(PL_CROUCH_VIEW_OFS, this) = (vq3compat) ? '0 0 12' : autocvar_sv_player_crouch_viewoffset; // old stats // fix some new settings @@ -69,7 +80,10 @@ void Physics_UpdateStats(entity this, float maxspd_mod) STAT(MOVEVARS_AIRACCELERATE, this) = Physics_ClientOption(this, "airaccelerate", autocvar_sv_airaccelerate); STAT(MOVEVARS_AIRSTOPACCELERATE, this) = Physics_ClientOption(this, "airstopaccelerate", autocvar_sv_airstopaccelerate); STAT(MOVEVARS_JUMPVELOCITY, this) = Physics_ClientOption(this, "jumpvelocity", autocvar_sv_jumpvelocity); + STAT(MOVEVARS_JUMPVELOCITY_CROUCH, this) = Physics_ClientOption(this, "jumpvelocity_crouch", autocvar_sv_jumpvelocity_crouch); STAT(MOVEVARS_TRACK_CANJUMP, this) = Physics_ClientOption(this, "track_canjump", autocvar_sv_track_canjump); + + MUTATOR_CALLHOOK(PlayerPhysics_PostUpdateStats, this, maxspd_mod); } #endif @@ -91,42 +105,53 @@ float GeomLerp(float a, float _lerp, float b) void PM_ClientMovement_UpdateStatus(entity this) { -#ifdef CSQC if(!IS_PLAYER(this)) return; - // set crouched - bool do_crouch = PHYS_INPUT_BUTTON_CROUCH(this); + bool have_hook = false; for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) { - entity wep = viewmodels[slot]; - if(wep.hook && !wasfreed(wep.hook)) + #if defined(CSQC) + entity wepent = viewmodels[slot]; + #elif defined(SVQC) + .entity weaponentity = weaponentities[slot]; + entity wepent = this.(weaponentity); + #endif + if(wepent.hook && !wasfreed(wepent.hook)) { - do_crouch = false; - break; // don't bother checking the others + have_hook = true; + break; } } - if(this.waterlevel >= WATERLEVEL_SWIMMING) + bool do_crouch = PHYS_INPUT_BUTTON_CROUCH(this); + if(this.viewloc && !(this.viewloc.spawnflags & VIEWLOC_FREEMOVE) && PHYS_CS(this).movement.x < 0) + do_crouch = true; + if (have_hook) { do_crouch = false; - if(hud != HUD_NORMAL) + //} else if (this.waterlevel >= WATERLEVEL_SWIMMING) { + //do_crouch = false; + } else if (PHYS_INVEHICLE(this)) { do_crouch = false; - if(STAT(FROZEN, this)) + } else if (STAT(FROZEN, this)) { do_crouch = false; + } - if (do_crouch) - { - // wants to crouch, this always works - if (!IS_DUCKED(this)) SET_DUCKED(this); - } - else - { - // wants to stand, if currently crouching we need to check for a low ceiling first - if (IS_DUCKED(this)) - { - tracebox(this.origin, STAT(PL_MIN, this), STAT(PL_MAX, this), this.origin, MOVE_NORMAL, this); - if (!trace_startsolid) UNSET_DUCKED(this); + if (do_crouch) { + if (!IS_DUCKED(this)) { + SET_DUCKED(this); + this.view_ofs = STAT(PL_CROUCH_VIEW_OFS, this); + setsize(this, STAT(PL_CROUCH_MIN, this), STAT(PL_CROUCH_MAX, this)); + // setanim(this, this.anim_duck, false, true, true); // this anim is BROKEN anyway } + } else if (IS_DUCKED(this)) { + tracebox(this.origin, STAT(PL_MIN, this), STAT(PL_MAX, this), this.origin, false, this); + if (!trace_startsolid) { + UNSET_DUCKED(this); + this.view_ofs = STAT(PL_VIEW_OFS, this); + setsize(this, STAT(PL_MIN, this), STAT(PL_MAX, this)); + } } +#ifdef CSQC if (IS_ONGROUND(this) || this.velocity.z <= 0 || PHYS_WATERJUMP_TIME(this) <= 0) PHYS_WATERJUMP_TIME(this) = 0; @@ -135,13 +160,13 @@ void PM_ClientMovement_UpdateStatus(entity this) void CPM_PM_Aircontrol(entity this, float dt, vector wishdir, float wishspeed) { - float movity = IsMoveInDirection(this.movement, 0); + float movity = IsMoveInDirection(PHYS_CS(this).movement, 0); if(PHYS_AIRCONTROL_BACKWARDS(this)) - movity += IsMoveInDirection(this.movement, 180); + movity += IsMoveInDirection(PHYS_CS(this).movement, 180); if(PHYS_AIRCONTROL_SIDEWARDS(this)) { - movity += IsMoveInDirection(this.movement, 90); - movity += IsMoveInDirection(this.movement, -90); + movity += IsMoveInDirection(PHYS_CS(this).movement, 90); + movity += IsMoveInDirection(PHYS_CS(this).movement, -90); } float k = 32 * (2 * movity - 1); @@ -297,7 +322,7 @@ bool PlayerJump(entity this) #endif bool doublejump = false; - float mjumpheight = PHYS_JUMPVELOCITY(this); + float mjumpheight = ((PHYS_JUMPVELOCITY_CROUCH(this) && IS_DUCKED(this)) ? PHYS_JUMPVELOCITY_CROUCH(this) : PHYS_JUMPVELOCITY(this)); bool track_jump = PHYS_CL_TRACK_CANJUMP(this); if (MUTATOR_CALLHOOK(PlayerJump, this, mjumpheight, doublejump)) @@ -427,7 +452,7 @@ void CheckWaterJump(entity this) #ifdef SVQC - #define JETPACK_JUMP(s) s.cvar_cl_jetpack_jump + #define JETPACK_JUMP(s) CS(s).cvar_cl_jetpack_jump #elif defined(CSQC) float autocvar_cl_jetpack_jump; #define JETPACK_JUMP(s) autocvar_cl_jetpack_jump @@ -477,31 +502,18 @@ void CheckPlayerJump(entity this) CheckWaterJump(this); } -float racecar_angle(float forward, float down) -{ - if (forward < 0) - { - forward = -forward; - down = -down; - } - - float ret = vectoyaw('0 1 0' * down + '1 0 0' * forward); - - float angle_mult = forward / (800 + forward); - - if (ret > 180) - return ret * angle_mult + 360 * (1 - angle_mult); - else - return ret * angle_mult; -} - #ifdef SVQC string specialcommand = "xwxwxsxsxaxdxaxdx1x "; .float specialcommand_pos; void SpecialCommand(entity this) { - if (!CheatImpulse(this, CHIMPULSE_GIVE_ALL.impulse)) - LOG_INFO("A hollow voice says \"Plugh\".\n"); + if(autocvar_sv_cheats || this.maycheat) + { + if (!CheatImpulse(this, CHIMPULSE_GIVE_ALL.impulse)) + LOG_INFO("A hollow voice says \"Plugh\"."); + } + else + STAT(MOVEVARS_SPECIALCOMMAND, this) = true; } #endif @@ -526,18 +538,18 @@ bool PM_check_specialcommand(entity this, int buttons) else c = "?"; - if (c == substring(specialcommand, this.specialcommand_pos, 1)) + if (c == substring(specialcommand, CS(this).specialcommand_pos, 1)) { - this.specialcommand_pos += 1; - if (this.specialcommand_pos >= strlen(specialcommand)) + CS(this).specialcommand_pos += 1; + if (CS(this).specialcommand_pos >= strlen(specialcommand)) { - this.specialcommand_pos = 0; + CS(this).specialcommand_pos = 0; SpecialCommand(this); return true; } } - else if (this.specialcommand_pos && (c != substring(specialcommand, this.specialcommand_pos - 1, 1))) - this.specialcommand_pos = 0; + else if (CS(this).specialcommand_pos && (c != substring(specialcommand, CS(this).specialcommand_pos - 1, 1))) + CS(this).specialcommand_pos = 0; #endif return false; } @@ -550,7 +562,7 @@ void PM_check_nickspam(entity this) if (this.nickspamcount >= autocvar_g_nick_flood_penalty_yellow) { // slight annoyance for nick change scripts - this.movement = -1 * this.movement; + PHYS_CS(this).movement = -1 * PHYS_CS(this).movement; PHYS_INPUT_BUTTON_ATCK(this) = PHYS_INPUT_BUTTON_JUMP(this) = PHYS_INPUT_BUTTON_ATCK2(this) = PHYS_INPUT_BUTTON_ZOOM(this) = PHYS_INPUT_BUTTON_CROUCH(this) = PHYS_INPUT_BUTTON_HOOK(this) = PHYS_INPUT_BUTTON_USE(this) = false; if (this.nickspamcount >= autocvar_g_nick_flood_penalty_red) // if you are persistent and the slight annoyance above does not stop you, I'll show you! @@ -598,12 +610,12 @@ void PM_check_frozen(entity this) #endif ) { - this.movement_x = bound(-5, this.movement.x, 5); - this.movement_y = bound(-5, this.movement.y, 5); - this.movement_z = bound(-5, this.movement.z, 5); + PHYS_CS(this).movement_x = bound(-5, PHYS_CS(this).movement.x, 5); + PHYS_CS(this).movement_y = bound(-5, PHYS_CS(this).movement.y, 5); + PHYS_CS(this).movement_z = bound(-5, PHYS_CS(this).movement.z, 5); } else - this.movement = '0 0 0'; + PHYS_CS(this).movement = '0 0 0'; vector midpoint = ((this.absmin + this.absmax) * 0.5); if (pointcontents(midpoint) == CONTENT_WATER) @@ -684,7 +696,7 @@ void PM_check_blocked(entity this) #ifdef SVQC if (!this.player_blocked) return; - this.movement = '0 0 0'; + PHYS_CS(this).movement = '0 0 0'; this.disableclientprediction = 1; #endif } @@ -693,8 +705,8 @@ void PM_jetpack(entity this, float maxspd_mod, float dt) { //makevectors(this.v_angle.y * '0 1 0'); makevectors(this.v_angle); - vector wishvel = v_forward * this.movement_x - + v_right * this.movement_y; + vector wishvel = v_forward * PHYS_CS(this).movement_x + + v_right * PHYS_CS(this).movement_y; // add remaining speed as Z component float maxairspd = PHYS_MAXAIRSPEED(this) * max(1, maxspd_mod); // fix speedhacks :P @@ -787,7 +799,7 @@ void PM_jetpack(entity this, float maxspd_mod, float dt) #ifdef SVQC if (!(ITEMS_STAT(this) & IT_UNLIMITED_WEAPON_AMMO)) - this.ammo_fuel -= PHYS_JETPACK_FUEL(this) * dt * fvel * f; + TakeResource(this, RESOURCE_FUEL, PHYS_JETPACK_FUEL(this) * dt * fvel * f); ITEMS_STAT(this) |= IT_USING_JETPACK; @@ -804,7 +816,8 @@ bool IsFlying(entity this) return false; if(this.waterlevel >= WATERLEVEL_SWIMMING) return false; - traceline(this.origin, this.origin - '0 0 48', MOVE_NORMAL, this); + tracebox(this.origin, this.mins, this.maxs, this.origin - '0 0 24', MOVE_NORMAL, this); + //traceline(this.origin, this.origin - '0 0 48', MOVE_NORMAL, this); if(trace_fraction < 1) return false; return true; @@ -818,10 +831,16 @@ void SV_PlayerPhysics(entity this) void CSQC_ClientMovement_PlayerMove_Frame(entity this) #endif { +#ifdef SVQC + // needs to be called before physics are run! + if(IS_REAL_CLIENT(this)) + PM_UpdateButtons(this, CS(this)); +#endif + sys_phys_update(this, PHYS_INPUT_TIMELENGTH); #ifdef SVQC - this.pm_frametime = frametime; + CS(this).pm_frametime = frametime; #elif defined(CSQC) if((ITEMS_STAT(this) & IT_USING_JETPACK) && !IS_DEAD(this) && !intermission) this.csqcmodel_modelflags |= MF_ROCKET;