X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=cl_input.c;h=a6f447610c8ba75e47ae954f24bd41a25dc364da;hb=10523a94c80615aeccfa84c81bbffe11335ca4a7;hp=402a9ec68c6170ee64d85cac271983df3192a5c4;hpb=e7b5029b4590cf57fdc7a6d7b288b102efb06400;p=xonotic%2Fdarkplaces.git diff --git a/cl_input.c b/cl_input.c index 402a9ec6..a6f44761 100644 --- a/cl_input.c +++ b/cl_input.c @@ -197,6 +197,57 @@ void IN_JumpUp (void) {KeyUp(&in_jump);} void IN_Impulse (void) {in_impulse=atoi(Cmd_Argv(1));} +int in_bestweapon_info[][5] = +{ + {'1', 1, IT_AXE, STAT_SHELLS, 0}, + {'2', 2, IT_SHOTGUN, STAT_SHELLS, 1}, + {'3', 3, IT_SUPER_SHOTGUN, STAT_SHELLS, 1}, + {'4', 4, IT_NAILGUN, STAT_NAILS, 1}, + {'5', 5, IT_SUPER_NAILGUN, STAT_NAILS, 1}, + {'6', 6, IT_GRENADE_LAUNCHER, STAT_ROCKETS, 1}, + {'7', 7, IT_ROCKET_LAUNCHER, STAT_ROCKETS, 1}, + {'8', 8, IT_LIGHTNING, STAT_CELLS, 1}, + {'9', 9, 128, STAT_CELLS, 1}, // generic energy weapon for mods + {'p', 209, 128, STAT_CELLS, 1}, // dpmod plasma gun + {'w', 210, 8388608, STAT_CELLS, 1}, // dpmod plasma wave cannon + {'l', 225, HIT_LASER_CANNON, STAT_CELLS, 1}, // hipnotic laser cannon + {'h', 226, HIT_MJOLNIR, STAT_CELLS, 0}, // hipnotic mjolnir hammer + {-1, 0, 0, 0, 0} +}; +void IN_BestWeapon (void) +{ + int i, n; + const char *s; + if (Cmd_Argc() != 2) + { + Con_Printf("bestweapon requires 1 parameter\n"); + return; + } + s = Cmd_Argv(1); + for (i = 0;s[i];i++) + { + // figure out which weapon this character refers to + for (n = 0;in_bestweapon_info[n][0] >= 0;n++) + { + if (in_bestweapon_info[n][0] == s[i]) + { + // we found out what weapon this character refers to + // check if the inventory contains the weapon and enough ammo + if ((cl.stats[STAT_ITEMS] & in_bestweapon_info[n][2]) && (cl.stats[in_bestweapon_info[n][3]] >= in_bestweapon_info[n][4])) + { + // we found one of the weapons the player wanted + // send an impulse to switch to it + in_impulse = in_bestweapon_info[n][1]; + return; + } + break; + } + } + // if we couldn't identify the weapon we just ignore it and continue checking for other weapons + } + // if we couldn't find any of the weapons, there's nothing more we can do... +} + /* =============== CL_KeyState @@ -274,10 +325,15 @@ cvar_t cl_movement_maxspeed = {0, "cl_movement_maxspeed", "320", "how fast you c cvar_t cl_movement_maxairspeed = {0, "cl_movement_maxairspeed", "30", "how fast you can move while in the air (should match sv_maxairspeed)"}; cvar_t cl_movement_stopspeed = {0, "cl_movement_stopspeed", "100", "speed below which you will be slowed rapidly to a stop rather than sliding endlessly (should match sv_stopspeed)"}; cvar_t cl_movement_friction = {0, "cl_movement_friction", "4", "how fast you slow down (should match sv_friction)"}; +cvar_t cl_movement_waterfriction = {0, "cl_movement_waterfriction", "-1", "how fast you slow down (should match sv_friction), if less than 0 the cl_movement_friction variable is used instead"}; cvar_t cl_movement_edgefriction = {0, "cl_movement_edgefriction", "2", "how much to slow down when you may be about to fall off a ledge (should match edgefriction)"}; cvar_t cl_movement_stepheight = {0, "cl_movement_stepheight", "18", "how tall a step you can step in one instant (should match sv_stepheight)"}; cvar_t cl_movement_accelerate = {0, "cl_movement_accelerate", "10", "how fast you accelerate (should match sv_accelerate)"}; +cvar_t cl_movement_airaccelerate = {0, "cl_movement_airaccelerate", "-1", "how fast you accelerate while in the air (should match sv_airaccelerate), if less than 0 the cl_movement_accelerate variable is used instead"}; +cvar_t cl_movement_wateraccelerate = {0, "cl_movement_wateraccelerate", "-1", "how fast you accelerate while in the air (should match sv_airaccelerate), if less than 0 the cl_movement_accelerate variable is used instead"}; cvar_t cl_movement_jumpvelocity = {0, "cl_movement_jumpvelocity", "270", "how fast you move upward when you begin a jump (should match the quakec code)"}; +cvar_t cl_movement_airaccel_qw = {0, "cl_movement_airaccel_qw", "1", "ratio of QW-style air control as opposed to simple acceleration (should match sv_airaccel_qw)"}; +cvar_t cl_movement_airaccel_sideways_friction = {0, "cl_movement_airaccel_sideways_friction", "0", "anti-sideways movement stabilization (should match sv_airaccel_sideways_friction)"}; cvar_t cl_gravity = {0, "cl_gravity", "800", "how much gravity to apply in client physics (should match sv_gravity)"}; cvar_t cl_slowmo = {0, "cl_slowmo", "1", "speed of game time (should match slowmo)"}; @@ -461,10 +517,9 @@ void CL_Move (void) #include "cl_collision.h" -extern void V_CalcRefdef(void); void CL_UpdatePrydonCursor(void) { - vec3_t temp, scale; + vec3_t temp; if (!cl_prydoncursor.integer) VectorClear(cl.cmd.cursor_screen); @@ -495,21 +550,13 @@ void CL_UpdatePrydonCursor(void) cl.cmd.cursor_screen[1] = bound(-1, cl.cmd.cursor_screen[1], 1); cl.cmd.cursor_screen[2] = 1; - scale[0] = -r_view.frustum_x; - scale[1] = -r_view.frustum_y; - scale[2] = 1; - - // trace distance - VectorScale(scale, 1000000, scale); - // calculate current view matrix - V_CalcRefdef(); - VectorClear(temp); - Matrix4x4_Transform(&r_view.matrix, temp, cl.cmd.cursor_start); - VectorSet(temp, cl.cmd.cursor_screen[2] * scale[2], cl.cmd.cursor_screen[0] * scale[0], cl.cmd.cursor_screen[1] * scale[1]); + Matrix4x4_OriginFromMatrix(&r_view.matrix, cl.cmd.cursor_start); + // calculate direction vector of cursor in viewspace by using frustum slopes + VectorSet(temp, cl.cmd.cursor_screen[2] * 1000000, cl.cmd.cursor_screen[0] * -r_view.frustum_x * 1000000, cl.cmd.cursor_screen[1] * -r_view.frustum_y * 1000000); Matrix4x4_Transform(&r_view.matrix, temp, cl.cmd.cursor_end); // trace from view origin to the cursor - cl.cmd.cursor_fraction = CL_SelectTraceLine(cl.cmd.cursor_start, cl.cmd.cursor_end, cl.cmd.cursor_impact, cl.cmd.cursor_normal, &cl.cmd.cursor_entitynumber, (chase_active.integer || cl.intermission) ? &cl.entities[cl.playerentity].render : NULL, false); + cl.cmd.cursor_fraction = CL_SelectTraceLine(cl.cmd.cursor_start, cl.cmd.cursor_end, cl.cmd.cursor_impact, cl.cmd.cursor_normal, &cl.cmd.cursor_entitynumber, (chase_active.integer || cl.intermission) ? &cl.entities[cl.playerentity].render : NULL); } void CL_ClientMovement_InputQW(qw_usercmd_t *cmd) @@ -524,7 +571,7 @@ void CL_ClientMovement_InputQW(qw_usercmd_t *cmd) if (cl.movement_queue[i].sequence > cls.netcon->qw.incoming_sequence) cl.movement_queue[cl.movement_numqueue++] = cl.movement_queue[i]; else if (i == 0) - cl.movement_replay_canjump = !cl.movement_queue[i].jump; + cl.movement_replay_canjump = !cl.movement_queue[i].jump; // FIXME: this logic is quite broken } // add to input queue if there is room if (cl.movement_numqueue < (int)(sizeof(cl.movement_queue)/sizeof(cl.movement_queue[0]))) @@ -548,7 +595,7 @@ void CL_ClientMovement_Input(qboolean buttonjump, qboolean buttoncrouch) { int i; int n; - double lasttime = cl.movement_numqueue >= 0 ? cl.movement_queue[cl.movement_numqueue - 1].time : 0; + double lasttime = (cls.protocol == PROTOCOL_DARKPLACES6 || cls.protocol == PROTOCOL_DARKPLACES7) ? cl.mtime[1] : (cl.movement_numqueue >= 0 ? cl.movement_queue[cl.movement_numqueue - 1].time : 0); // remove stale queue items n = cl.movement_numqueue; cl.movement_numqueue = 0; @@ -559,7 +606,7 @@ void CL_ClientMovement_Input(qboolean buttonjump, qboolean buttoncrouch) if (cl.movement_queue[i].sequence > cl.servermovesequence) cl.movement_queue[cl.movement_numqueue++] = cl.movement_queue[i]; else if (i == 0) - cl.movement_replay_canjump = !cl.movement_queue[i].jump; + cl.movement_replay_canjump = !cl.movement_queue[i].jump; // FIXME: this logic is quite broken } } else @@ -569,7 +616,7 @@ void CL_ClientMovement_Input(qboolean buttonjump, qboolean buttoncrouch) if (cl.movement_queue[i].time >= cl.mtime[0] - cl_movement_latency.value / 1000.0 && cl.movement_queue[i].time <= cl.mtime[0]) cl.movement_queue[cl.movement_numqueue++] = cl.movement_queue[i]; else if (i == 0) - cl.movement_replay_canjump = !cl.movement_queue[i].jump; + cl.movement_replay_canjump = !cl.movement_queue[i].jump; // FIXME: this logic is quite broken } } // add to input queue if there is room @@ -636,6 +683,8 @@ typedef struct cl_clientmovement_state_s float movevars_edgefriction; float movevars_maxairspeed; float movevars_stepheight; + float movevars_airaccel_qw; + float movevars_airaccel_sideways_friction; // user command client_movementqueue_t q; @@ -922,7 +971,7 @@ void CL_ClientMovement_Physics_Walk(cl_clientmovement_state_t *s) // jump if on ground with jump button pressed but only if it has been // released at least once since the last jump - if (s->q.jump && s->canjump && s->onground) + if (s->q.jump && s->onground)// && s->canjump) // FIXME: canjump doesn't work properly { s->velocity[2] += s->movevars_jumpvelocity; s->onground = false; @@ -986,18 +1035,38 @@ void CL_ClientMovement_Physics_Walk(cl_clientmovement_state_t *s) { if (s->waterjumptime <= 0) { + vec_t f; + vec_t vel_straight; + vec_t vel_z; + vec3_t vel_perpend; + // apply air speed limit wishspeed = min(wishspeed, s->movevars_maxairspeed); - // Nexuiz has no upper bound on air acceleration, but little control - if (gamemode == GAME_NEXUIZ) - addspeed = wishspeed; - else - addspeed = wishspeed - DotProduct(s->velocity, wishdir); + + /* + addspeed = wishspeed - DotProduct(s->velocity, wishdir); if (addspeed > 0) { accelspeed = min(s->movevars_accelerate * s->q.frametime * wishspeed, addspeed); VectorMA(s->velocity, accelspeed, wishdir, s->velocity); } + */ + + vel_straight = DotProduct(s->velocity, wishdir); + vel_z = s->velocity[2]; + VectorMA(s->velocity, -vel_straight, wishdir, vel_perpend); + vel_perpend[2] -= vel_z; + + f = wishspeed - vel_straight; + if(f > 0) + vel_straight += min(f, s->movevars_accelerate * s->q.frametime * wishspeed) * s->movevars_airaccel_qw; + if(wishspeed > 0) + vel_straight += min(wishspeed, s->movevars_accelerate * s->q.frametime * wishspeed) * (1 - s->movevars_airaccel_qw); + + VectorM(1 - (s->q.frametime * (wishspeed / s->movevars_maxairspeed) * s->movevars_airaccel_sideways_friction), vel_perpend, vel_perpend); + + VectorMA(vel_perpend, vel_straight, wishdir, s->velocity); + s->velocity[2] += vel_z; } s->velocity[2] -= cl_gravity.value * s->q.frametime; CL_ClientMovement_Move(s); @@ -1032,6 +1101,7 @@ void CL_ClientMovement_Replay(void) VectorCopy(cl.mvelocity[0], s.velocity); s.crouched = true; // will be updated on first move s.canjump = cl.movement_replay_canjump; + //Con_Printf("movement replay starting org %f %f %f vel %f %f %f\n", s.origin[0], s.origin[1], s.origin[2], s.velocity[0], s.velocity[1], s.velocity[2]); // set up movement variables if (cls.protocol == PROTOCOL_QUAKEWORLD) @@ -1050,6 +1120,8 @@ void CL_ClientMovement_Replay(void) s.movevars_edgefriction = cl_movement_edgefriction.value; s.movevars_maxairspeed = cl_movement_maxairspeed.value; s.movevars_stepheight = cl_movement_stepheight.value; + s.movevars_airaccel_qw = 1.0; + s.movevars_airaccel_sideways_friction = 0.0; } else { @@ -1058,18 +1130,21 @@ void CL_ClientMovement_Replay(void) s.movevars_maxspeed = cl_movement_maxspeed.value; s.movevars_spectatormaxspeed = cl_movement_maxspeed.value; s.movevars_accelerate = cl_movement_accelerate.value; - s.movevars_airaccelerate = cl_movement_accelerate.value; - s.movevars_wateraccelerate = cl_movement_accelerate.value; + s.movevars_airaccelerate = cl_movement_airaccelerate.value < 0 ? cl_movement_accelerate.value : cl_movement_airaccelerate.value; + s.movevars_wateraccelerate = cl_movement_wateraccelerate.value < 0 ? cl_movement_accelerate.value : cl_movement_wateraccelerate.value; s.movevars_friction = cl_movement_friction.value; - s.movevars_waterfriction = cl_movement_friction.value; + s.movevars_waterfriction = cl_movement_waterfriction.value < 0 ? cl_movement_friction.value : cl_movement_waterfriction.value; s.movevars_entgravity = 1; s.movevars_jumpvelocity = cl_movement_jumpvelocity.value; s.movevars_edgefriction = cl_movement_edgefriction.value; s.movevars_maxairspeed = cl_movement_maxairspeed.value; s.movevars_stepheight = cl_movement_stepheight.value; + s.movevars_airaccel_qw = cl_movement_airaccel_qw.value; + s.movevars_airaccel_sideways_friction = cl_movement_airaccel_sideways_friction.value; } - if (cl.movement) + cl.movement_predicted = (cl_movement.integer && !cls.demoplayback && cls.signon == SIGNONS && cl.stats[STAT_HEALTH] > 0 && !cl.intermission) && ((cls.protocol != PROTOCOL_DARKPLACES6 && cls.protocol != PROTOCOL_DARKPLACES7) || cl.servermovesequence); + if (cl.movement_predicted) { //Con_Printf("%f: ", cl.mtime[0]); @@ -1093,9 +1168,9 @@ void CL_ClientMovement_Replay(void) // get the first movement queue entry to know whether to crouch and such s.q = cl.movement_queue[0]; } + // store replay location CL_ClientMovement_UpdateStatus(&s); - cl.onground = s.onground; cl.movement_time[1] = cl.movement_time[0]; cl.movement_time[0] = cl.movement_queue[cl.movement_numqueue-1].time; VectorCopy(cl.movement_origin, cl.movement_oldorigin); @@ -1103,6 +1178,27 @@ void CL_ClientMovement_Replay(void) VectorCopy(s.velocity, cl.movement_velocity); //VectorCopy(s.origin, cl.entities[cl.playerentity].state_current.origin); //VectorSet(cl.entities[cl.playerentity].state_current.angles, 0, cl.viewangles[1], 0); + + // update the onground flag if appropriate + // when not predicted, cl.onground is only cleared by cl_parse.c, but can + // be set forcefully here to hide server inconsistencies in the onground + // flag (such as when stepping up stairs, the onground flag tends to turn + // off briefly due to precision errors, particularly at high framerates), + // such inconsistencies can mess up the gun bobbing and stair smoothing, + // so they must be avoided. + if (cl.movement_predicted) + cl.onground = s.onground; + else if (s.onground) + cl.onground = true; + + // react to onground state changes (for gun bob) + if (cl.onground) + { + if (!cl.oldonground) + cl.hitgroundtime = cl.time; + cl.lastongroundtime = cl.time; + } + cl.oldonground = cl.onground; } void QW_MSG_WriteDeltaUsercmd(sizebuf_t *buf, qw_usercmd_t *from, qw_usercmd_t *to) @@ -1155,7 +1251,7 @@ CL_SendMove extern cvar_t cl_netinputpacketspersecond; void CL_SendMove(void) { - int i; + int i, j, packetloss; int bits; int impulse; sizebuf_t buf; @@ -1179,7 +1275,6 @@ void CL_SendMove(void) accumtotal++; #endif - cl.movement = cl_movement.integer && cls.signon == SIGNONS && cl.stats[STAT_HEALTH] > 0 && !cl.intermission; if (cl_movement.integer && cls.signon == SIGNONS && cls.protocol != PROTOCOL_QUAKEWORLD) { if (!cl.movement_needupdate) @@ -1188,11 +1283,13 @@ void CL_SendMove(void) } else { - if (realtime < lastsendtime + 1.0 / bound(10, cl_netinputpacketspersecond.value, 100)) + double packettime = 1.0 / bound(10, cl_netinputpacketspersecond.value, 100); + // don't send too often or else network connections can get clogged by a high renderer framerate + if (realtime < lastsendtime + packettime) return; // don't let it fall behind if CL_SendMove hasn't been called recently // (such is the case when framerate is too low for instance) - lastsendtime = max(lastsendtime + 1.0 / bound(10, cl_netinputpacketspersecond.value, 100), realtime); + lastsendtime = max(lastsendtime + packettime, realtime); } #if MOVEAVERAGING // average the accumulated changes @@ -1303,8 +1400,9 @@ void CL_SendMove(void) checksumindex = buf.cursize; MSG_WriteByte(&buf, 0); // packet loss percentage - // FIXME: netgraph stuff - MSG_WriteByte(&buf, 0); + for (j = 0, packetloss = 0;j < 100;j++) + packetloss += cls.netcon->packetlost[j]; + MSG_WriteByte(&buf, packetloss); // write most recent 3 moves i = (cls.netcon->qw.outgoing_sequence-2) & QW_UPDATE_MASK; cmd = &cl.qw_moves[i]; @@ -1449,6 +1547,19 @@ void CL_SendMove(void) // PROTOCOL_DARKPLACES7 = 71 bytes per packet } + if (cls.protocol != PROTOCOL_QUAKEWORLD) + { + // acknowledge any recently received data blocks + for (i = 0;i < CL_MAX_DOWNLOADACKS && (cls.dp_downloadack[i].start || cls.dp_downloadack[i].size);i++) + { + MSG_WriteByte(&buf, clc_ackdownloaddata); + MSG_WriteLong(&buf, cls.dp_downloadack[i].start); + MSG_WriteShort(&buf, cls.dp_downloadack[i].size); + cls.dp_downloadack[i].start = 0; + cls.dp_downloadack[i].size = 0; + } + } + // send the reliable message (forwarded commands) if there is one NetConn_SendUnreliableMessage(cls.netcon, &buf, cls.protocol); @@ -1535,6 +1646,9 @@ void CL_InitInput (void) Cmd_AddCommand ("+button16", IN_Button16Down, "activate button16 (behavior depends on mod)"); Cmd_AddCommand ("-button16", IN_Button16Up, "deactivate button16"); + // LordHavoc: added bestweapon command + Cmd_AddCommand ("bestweapon", IN_BestWeapon, "send an impulse number to server to select the first usable weapon out of several (example: 87654321)"); + Cvar_RegisterVariable(&cl_movement); Cvar_RegisterVariable(&cl_movement_latency); Cvar_RegisterVariable(&cl_movement_maxspeed); @@ -1543,8 +1657,11 @@ void CL_InitInput (void) Cvar_RegisterVariable(&cl_movement_friction); Cvar_RegisterVariable(&cl_movement_edgefriction); Cvar_RegisterVariable(&cl_movement_stepheight); + Cvar_RegisterVariable(&cl_movement_airaccelerate); Cvar_RegisterVariable(&cl_movement_accelerate); Cvar_RegisterVariable(&cl_movement_jumpvelocity); + Cvar_RegisterVariable(&cl_movement_airaccel_qw); + Cvar_RegisterVariable(&cl_movement_airaccel_sideways_friction); Cvar_RegisterVariable(&cl_gravity); Cvar_RegisterVariable(&cl_slowmo);