/* * @brief Sets the kick value based on recent events such as falling. Firing of * weapons may also set the kick value, and we factor that in here as well. */ static void G_ClientKickAngles(g_edict_t *ent) { int16_t *kick_angles = ent->client->ps.pm_state.kick_angles; vec3_t kick; UnpackAngles(kick_angles, kick); // add in any event-based feedback switch (ent->s.event) { case EV_CLIENT_LAND: kick[PITCH] += 2.5; break; case EV_CLIENT_FALL: kick[PITCH] += 5.0; break; case EV_CLIENT_FALL_FAR: kick[PITCH] += 10.0; break; default: break; } // and any velocity-based feedback vec_t forward = DotProduct(ent->locals.velocity, ent->client->locals.forward); kick[PITCH] += forward / 450.0; vec_t right = DotProduct(ent->locals.velocity, ent->client->locals.right); kick[ROLL] += right / 350.0; // now interpolate the kick angles towards neutral over time vec_t delta = VectorLength(kick); if (!delta) // no kick, we're done return; // we recover from kick at a rate based on the kick itself delta = 0.5 + delta * delta * gi.frame_seconds; int32_t i; for (i = 0; i < 3; i++) { // clear angles smaller than our delta to avoid oscillations if (fabs(kick[i]) <= delta) { kick[i] = 0.0; } else if (kick[i] > 0.0) { kick[i] -= delta; } else { kick[i] += delta; } } PackAngles(kick, kick_angles); }
/* * @brief Adds view kick in the specified direction to the specified client. */ void G_ClientDamageKick(g_entity_t *ent, const vec3_t dir, const vec_t kick) { vec3_t old_kick_angles, kick_angles; UnpackAngles(ent->client->ps.pm_state.kick_angles, old_kick_angles); VectorClear(kick_angles); kick_angles[PITCH] = DotProduct(dir, ent->client->locals.forward) * kick * KICK_SCALE; kick_angles[ROLL] = DotProduct(dir, ent->client->locals.right) * kick * KICK_SCALE; //gi.Print("kicked %s from %s at %1.2f\n", vtos(kick_angles), vtos(dir), kick); VectorAdd(old_kick_angles, kick_angles, kick_angles); PackAngles(kick_angles, ent->client->ps.pm_state.kick_angles); }
/* * @brief Accumulate this frame's movement-related inputs and assemble a movement * command to send to the server. This may be called several times for each * command that is transmitted if the client is running asynchronously. */ void Cl_Move(pm_cmd_t *cmd) { if (cmd->msec < 1) // save key states for next move return; // keyboard move forward / back cmd->forward += cl_forward_speed->value * cmd->msec * Cl_KeyState(&in_forward, cmd->msec); cmd->forward -= cl_forward_speed->value * cmd->msec * Cl_KeyState(&in_back, cmd->msec); // keyboard strafe left / right cmd->right += cl_right_speed->value * cmd->msec * Cl_KeyState(&in_move_right, cmd->msec); cmd->right -= cl_right_speed->value * cmd->msec * Cl_KeyState(&in_move_left, cmd->msec); // keyboard jump / crouch cmd->up += cl_up_speed->value * cmd->msec * Cl_KeyState(&in_up, cmd->msec); cmd->up -= cl_up_speed->value * cmd->msec * Cl_KeyState(&in_down, cmd->msec); // keyboard turn left / right cl.angles[YAW] -= cl_yaw_speed->value * cmd->msec * Cl_KeyState(&in_right, cmd->msec); cl.angles[YAW] += cl_yaw_speed->value * cmd->msec * Cl_KeyState(&in_left, cmd->msec); // keyboard look up / down cl.angles[PITCH] -= cl_pitch_speed->value * cmd->msec * Cl_KeyState(&in_look_up, cmd->msec); cl.angles[PITCH] += cl_pitch_speed->value * cmd->msec * Cl_KeyState(&in_look_down, cmd->msec); Cl_ClampPitch(); // clamp, accounting for frame delta angles // pack the angles into the command PackAngles(cl.angles, cmd->angles); // set any button hits that occurred since last frame if (in_attack.state & 3) cmd->buttons |= BUTTON_ATTACK; in_attack.state &= ~2; if (cl_run->value) { // run by default, walk on speed toggle if (in_speed.state & 1) cmd->buttons |= BUTTON_WALK; } else { // walk by default, run on speed toggle if (!(in_speed.state & 1)) cmd->buttons |= BUTTON_WALK; } }
/* * @brief Sets the kick value based on recent events such as falling. Firing of * weapons may also set the kick value, and we factor that in here as well. */ static void G_ClientKickAngles(g_entity_t *ent) { uint16_t *kick_angles = ent->client->ps.pm_state.kick_angles; // spectators and dead clients receive no kick angles if (ent->client->ps.pm_state.type != PM_NORMAL) { VectorClear(kick_angles); return; } vec3_t kick; UnpackAngles(kick_angles, kick); // un-clamp them so that we can work with small signed values near zero for (int32_t i = 0; i < 3; i++) { if (kick[i] > 180.0) kick[i] -= 360.0; } // add in any event-based feedback switch (ent->s.event) { case EV_CLIENT_LAND: kick[PITCH] += 2.5; break; case EV_CLIENT_FALL: kick[PITCH] += 5.0; break; case EV_CLIENT_FALL_FAR: kick[PITCH] += 10.0; break; default: break; } // and any velocity-based feedback vec_t forward = DotProduct(ent->locals.velocity, ent->client->locals.forward); kick[PITCH] += forward / 450.0; vec_t right = DotProduct(ent->locals.velocity, ent->client->locals.right); kick[ROLL] += right / 400.0; // now interpolate the kick angles towards neutral over time vec_t delta = VectorLength(kick); if (!delta) // no kick, we're done return; // we recover from kick at a rate based on the kick itself delta = 0.5 + delta * delta * gi.frame_seconds; for (int32_t i = 0; i < 3; i++) { // clear angles smaller than our delta to avoid oscillations if (fabs(kick[i]) <= delta) { kick[i] = 0.0; } else if (kick[i] > 0.0) { kick[i] -= delta; } else { kick[i] += delta; } } PackAngles(kick, kick_angles); }