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
#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);
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)
{
if (s->waterjumptime <= 0)
{
+ vec_t f;
vec_t vel_straight;
vec_t vel_z;
vec3_t vel_perpend;
VectorMA(s->velocity, -vel_straight, wishdir, vel_perpend);
vel_perpend[2] -= vel_z;
- vec_t f = wishspeed - vel_straight;
+ 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)
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)
s.movevars_airaccel_sideways_friction = cl_movement_airaccel_sideways_friction.value;
}
- cl.movement_predicted = (cl_movement.integer && cls.signon == SIGNONS && cl.stats[STAT_HEALTH] > 0 && !cl.intermission) && ((cls.protocol != PROTOCOL_DARKPLACES6 && cls.protocol != PROTOCOL_DARKPLACES7) || cl.servermovesequence);
+ 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]);
// 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);
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)
extern cvar_t cl_netinputpacketspersecond;
void CL_SendMove(void)
{
- int i;
+ int i, j, packetloss;
int bits;
int impulse;
sizebuf_t buf;
}
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
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];
// 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);
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);