Motion controlled Force Push/Pull

This commit is contained in:
Simon 2022-11-07 23:57:10 +00:00
parent 62f1924dff
commit 0d70fae512
7 changed files with 536 additions and 460 deletions

View file

@ -1308,8 +1308,10 @@ void JKVR_Init()
vr_immersive_cinematics = Cvar_Get("vr_immersive_cinematics", "1", CVAR_ARCHIVE); vr_immersive_cinematics = Cvar_Get("vr_immersive_cinematics", "1", CVAR_ARCHIVE);
vr_screen_dist = Cvar_Get( "vr_screen_dist", "2.5", CVAR_ARCHIVE); vr_screen_dist = Cvar_Get( "vr_screen_dist", "2.5", CVAR_ARCHIVE);
vr_weapon_velocity_trigger = Cvar_Get( "vr_weapon_velocity_trigger", "2.3", CVAR_ARCHIVE); vr_weapon_velocity_trigger = Cvar_Get( "vr_weapon_velocity_trigger", "2.0", CVAR_ARCHIVE);
vr_force_velocity_trigger = Cvar_Get( "vr_force_velocity_trigger", "2.0", CVAR_ARCHIVE);
vr_two_handed_weapons = Cvar_Get ("vr_two_handed_weapons", "1", CVAR_ARCHIVE); vr_two_handed_weapons = Cvar_Get ("vr_two_handed_weapons", "1", CVAR_ARCHIVE);
vr_force_motion_controlled = Cvar_Get ("vr_force_motion_controlled", "1", CVAR_ARCHIVE);
cvar_t *expanded_menu_enabled = Cvar_Get ("expanded_menu_enabled", "0", CVAR_ARCHIVE); cvar_t *expanded_menu_enabled = Cvar_Get ("expanded_menu_enabled", "0", CVAR_ARCHIVE);
if (FS_FileExists("expanded_menu.pk3")) { if (FS_FileExists("expanded_menu.pk3")) {

View file

@ -61,6 +61,7 @@ typedef struct {
bool primaryVelocityTriggeredAttack; bool primaryVelocityTriggeredAttack;
float secondaryswingvelocity; float secondaryswingvelocity;
bool secondaryVelocityTriggeredAttack; bool secondaryVelocityTriggeredAttack;
vec3_t secondaryVelocityTriggerLocation;
vec3_t offhandangles; vec3_t offhandangles;
vec3_t offhandangles_last; // Don't use this, it is just for calculating delta! vec3_t offhandangles_last; // Don't use this, it is just for calculating delta!

View file

@ -10,5 +10,7 @@ extern cvar_t *vr_switch_sticks;
extern cvar_t *vr_immersive_cinematics; extern cvar_t *vr_immersive_cinematics;
extern cvar_t *vr_screen_dist; extern cvar_t *vr_screen_dist;
extern cvar_t *vr_weapon_velocity_trigger; extern cvar_t *vr_weapon_velocity_trigger;
extern cvar_t *vr_force_velocity_trigger;
extern cvar_t *vr_two_handed_weapons; extern cvar_t *vr_two_handed_weapons;
extern cvar_t *vr_force_motion_controlled;

View file

@ -30,7 +30,9 @@ cvar_t *vr_switch_sticks;
cvar_t *vr_immersive_cinematics; cvar_t *vr_immersive_cinematics;
cvar_t *vr_screen_dist; cvar_t *vr_screen_dist;
cvar_t *vr_weapon_velocity_trigger; cvar_t *vr_weapon_velocity_trigger;
cvar_t *vr_force_velocity_trigger;
cvar_t *vr_two_handed_weapons; cvar_t *vr_two_handed_weapons;
cvar_t *vr_force_motion_controlled;
ovrInputStateTrackedRemote leftTrackedRemoteState_old; ovrInputStateTrackedRemote leftTrackedRemoteState_old;
ovrInputStateTrackedRemote leftTrackedRemoteState_new; ovrInputStateTrackedRemote leftTrackedRemoteState_new;

View file

@ -264,485 +264,515 @@ void HandleInput_Default( ovrInputStateGamepad *pFootTrackingNew, ovrInputStateG
} }
} }
//if (!vr.item_selector) //Engage scope / virtual stock if conditions are right
bool scopeready = vr.weapon_stabilised && (distanceToHMD < SCOPE_ENGAGE_DISTANCE);
static bool lastScopeReady = qfalse;
if (scopeready != lastScopeReady) {
if (vr.scopedweapon && !vr.scopedetached) {
if (!vr.scopeengaged && scopeready) {
ALOGV("**WEAPON EVENT** trigger scope mode");
sendButtonActionSimple("weapalt");
} else if (vr.scopeengaged && !scopeready) {
ALOGV("**WEAPON EVENT** disable scope mode");
sendButtonActionSimple("weapalt");
}
lastScopeReady = scopeready;
}
}
//Engage scope / virtual stock (iron sight lock) if conditions are right
static bool scopeEngaged = qfalse;
if (scopeEngaged != vr.scopeengaged) {
scopeEngaged = vr.scopeengaged;
}
//dominant hand stuff first
{ {
//Engage scope / virtual stock if conditions are right //Record recent weapon position for trajectory based stuff
bool scopeready = vr.weapon_stabilised && (distanceToHMD < SCOPE_ENGAGE_DISTANCE); for (int i = (NUM_WEAPON_SAMPLES - 1); i != 0; --i) {
static bool lastScopeReady = qfalse; VectorCopy(vr.weaponoffset_history[i - 1], vr.weaponoffset_history[i]);
if (scopeready != lastScopeReady) { vr.weaponoffset_history_timestamp[i] = vr.weaponoffset_history_timestamp[i - 1];
if (vr.scopedweapon && !vr.scopedetached) {
if (!vr.scopeengaged && scopeready) {
ALOGV("**WEAPON EVENT** trigger scope mode");
sendButtonActionSimple("weapalt");
} else if (vr.scopeengaged && !scopeready) {
ALOGV("**WEAPON EVENT** disable scope mode");
sendButtonActionSimple("weapalt");
}
lastScopeReady = scopeready;
}
} }
VectorCopy(vr.weaponoffset, vr.weaponoffset_history[0]);
vr.weaponoffset_history_timestamp[0] = vr.weaponoffset_timestamp;
//Engage scope / virtual stock (iron sight lock) if conditions are right VectorSet(vr.weaponposition, pWeapon->HeadPose.Pose.Position.x,
static bool scopeEngaged = qfalse; pWeapon->HeadPose.Pose.Position.y, pWeapon->HeadPose.Pose.Position.z);
if (scopeEngaged != vr.scopeengaged) {
scopeEngaged = vr.scopeengaged;
}
//dominant hand stuff first ///Weapon location relative to view
{ VectorSet(vr.weaponoffset, pWeapon->HeadPose.Pose.Position.x,
//Record recent weapon position for trajectory based stuff pWeapon->HeadPose.Pose.Position.y, pWeapon->HeadPose.Pose.Position.z);
for (int i = (NUM_WEAPON_SAMPLES - 1); i != 0; --i) { VectorSubtract(vr.weaponoffset, vr.hmdposition, vr.weaponoffset);
VectorCopy(vr.weaponoffset_history[i - 1], vr.weaponoffset_history[i]); vr.weaponoffset_timestamp = Sys_Milliseconds();
vr.weaponoffset_history_timestamp[i] = vr.weaponoffset_history_timestamp[i - 1];
}
VectorCopy(vr.weaponoffset, vr.weaponoffset_history[0]);
vr.weaponoffset_history_timestamp[0] = vr.weaponoffset_timestamp;
VectorSet(vr.weaponposition, pWeapon->HeadPose.Pose.Position.x, vec3_t velocity;
pWeapon->HeadPose.Pose.Position.y, pWeapon->HeadPose.Pose.Position.z); VectorSet(velocity, pWeapon->HeadPose.LinearVelocity.x,
pWeapon->HeadPose.LinearVelocity.y, pWeapon->HeadPose.LinearVelocity.z);
vr.primaryswingvelocity = VectorLength(velocity);
///Weapon location relative to view VectorSet(velocity, pOff->HeadPose.LinearVelocity.x,
VectorSet(vr.weaponoffset, pWeapon->HeadPose.Pose.Position.x, pOff->HeadPose.LinearVelocity.y, pOff->HeadPose.LinearVelocity.z);
pWeapon->HeadPose.Pose.Position.y, pWeapon->HeadPose.Pose.Position.z); vr.secondaryswingvelocity = VectorLength(velocity);
VectorSubtract(vr.weaponoffset, vr.hmdposition, vr.weaponoffset);
vr.weaponoffset_timestamp = Sys_Milliseconds();
vec3_t velocity;
VectorSet(velocity, pWeapon->HeadPose.LinearVelocity.x,
pWeapon->HeadPose.LinearVelocity.y, pWeapon->HeadPose.LinearVelocity.z);
vr.primaryswingvelocity = VectorLength(velocity);
VectorSet(velocity, pOff->HeadPose.LinearVelocity.x,
pOff->HeadPose.LinearVelocity.y, pOff->HeadPose.LinearVelocity.z);
vr.secondaryswingvelocity = VectorLength(velocity);
//For melee right hand is alt attack and left hand is attack //For melee right hand is alt attack and left hand is attack
if (vr.weaponid == WP_MELEE) { if (vr.weaponid == WP_MELEE) {
//Does weapon velocity trigger attack (melee) and is it fast enough //Does weapon velocity trigger attack (melee) and is it fast enough
if (vr.velocitytriggered) { if (vr.velocitytriggered) {
static bool fired = false; static bool fired = false;
vr.primaryVelocityTriggeredAttack = (vr.primaryswingvelocity > vr.primaryVelocityTriggeredAttack = (vr.primaryswingvelocity >
vr_weapon_velocity_trigger->value); vr_weapon_velocity_trigger->value);
if (fired != vr.primaryVelocityTriggeredAttack) { if (fired != vr.primaryVelocityTriggeredAttack) {
ALOGV("**WEAPON EVENT** veocity triggered %s", ALOGV("**WEAPON EVENT** veocity triggered %s",
vr.primaryVelocityTriggeredAttack ? "+altattack" : "-altattack"); vr.primaryVelocityTriggeredAttack ? "+altattack" : "-altattack");
//normal attack is a punch with the left hand //normal attack is a punch with the left hand
sendButtonAction("+altattack", vr.primaryVelocityTriggeredAttack);
fired = vr.primaryVelocityTriggeredAttack;
}
} else if (vr.primaryVelocityTriggeredAttack) {
//send a stop attack as we have an unfinished velocity attack
vr.primaryVelocityTriggeredAttack = false;
ALOGV("**WEAPON EVENT** veocity triggered -altattack");
sendButtonAction("+altattack", vr.primaryVelocityTriggeredAttack); sendButtonAction("+altattack", vr.primaryVelocityTriggeredAttack);
fired = vr.primaryVelocityTriggeredAttack;
} }
} else if (vr.primaryVelocityTriggeredAttack) {
//send a stop attack as we have an unfinished velocity attack
vr.primaryVelocityTriggeredAttack = false;
ALOGV("**WEAPON EVENT** veocity triggered -altattack");
sendButtonAction("+altattack", vr.primaryVelocityTriggeredAttack);
}
if (vr.velocitytriggered) { if (vr.velocitytriggered) {
static bool fired = false; static bool fired = false;
vr.secondaryVelocityTriggeredAttack = (vr.secondaryswingvelocity > vr.secondaryVelocityTriggeredAttack = (vr.secondaryswingvelocity >
vr_weapon_velocity_trigger->value); vr_weapon_velocity_trigger->value);
if (fired != vr.secondaryVelocityTriggeredAttack) { if (fired != vr.secondaryVelocityTriggeredAttack) {
ALOGV("**WEAPON EVENT** veocity triggered %s", ALOGV("**WEAPON EVENT** veocity triggered %s",
vr.secondaryVelocityTriggeredAttack ? "+attack" : "-attack"); vr.secondaryVelocityTriggeredAttack ? "+attack" : "-attack");
//normal attack is a punch with the left hand //normal attack is a punch with the left hand
sendButtonAction("+attack", vr.secondaryVelocityTriggeredAttack);
fired = vr.secondaryVelocityTriggeredAttack;
}
} else if (vr.secondaryVelocityTriggeredAttack) {
//send a stop attack as we have an unfinished velocity attack
vr.secondaryVelocityTriggeredAttack = qfalse;
ALOGV("**WEAPON EVENT** veocity triggered -attack");
sendButtonAction("+attack", vr.secondaryVelocityTriggeredAttack); sendButtonAction("+attack", vr.secondaryVelocityTriggeredAttack);
fired = vr.secondaryVelocityTriggeredAttack;
} }
} else if (vr.weaponid == WP_SABER) { } else if (vr.secondaryVelocityTriggeredAttack) {
//Does weapon velocity trigger attack //send a stop attack as we have an unfinished velocity attack
if (vr.velocitytriggered) { vr.secondaryVelocityTriggeredAttack = qfalse;
static bool fired = false; ALOGV("**WEAPON EVENT** veocity triggered -attack");
vr.primaryVelocityTriggeredAttack = (vr.primaryswingvelocity > sendButtonAction("+attack", vr.secondaryVelocityTriggeredAttack);
vr_weapon_velocity_trigger->value); }
} else if (vr.weaponid == WP_SABER) {
//Does weapon velocity trigger attack
if (vr.velocitytriggered) {
static bool fired = false;
vr.primaryVelocityTriggeredAttack = (vr.primaryswingvelocity >
vr_weapon_velocity_trigger->value);
if (fired != vr.primaryVelocityTriggeredAttack) { if (fired != vr.primaryVelocityTriggeredAttack) {
ALOGV("**WEAPON EVENT** veocity triggered %s", ALOGV("**WEAPON EVENT** veocity triggered %s",
vr.primaryVelocityTriggeredAttack ? "+attack" : "-attack"); vr.primaryVelocityTriggeredAttack ? "+attack" : "-attack");
//normal attack is a punch with the left hand //normal attack is a punch with the left hand
sendButtonAction("+attack", vr.primaryVelocityTriggeredAttack);
fired = vr.primaryVelocityTriggeredAttack;
}
} else if (vr.primaryVelocityTriggeredAttack) {
//send a stop attack as we have an unfinished velocity attack
vr.primaryVelocityTriggeredAttack = false;
ALOGV("**WEAPON EVENT** veocity triggered -attack");
sendButtonAction("+attack", vr.primaryVelocityTriggeredAttack); sendButtonAction("+attack", vr.primaryVelocityTriggeredAttack);
fired = vr.primaryVelocityTriggeredAttack;
} }
} } else if (vr.primaryVelocityTriggeredAttack) {
//send a stop attack as we have an unfinished velocity attack
if (vr.weapon_stabilised) { vr.primaryVelocityTriggeredAttack = false;
if (vr.scopeengaged || vr_virtual_stock->integer == 1) { ALOGV("**WEAPON EVENT** veocity triggered -attack");
//offset to the appropriate eye a little bit sendButtonAction("+attack", vr.primaryVelocityTriggeredAttack);
vec2_t xy;
rotateAboutOrigin(Cvar_VariableValue("cg_stereoSeparation") / 2.0f, 0.0f,
-vr.hmdorientation[YAW], xy);
float x = pOff->HeadPose.Pose.Position.x - (vr.hmdposition[0] + xy[0]);
float y = pOff->HeadPose.Pose.Position.y -
(vr.hmdposition[1] - 0.1f); // Use a point lower
float z = pOff->HeadPose.Pose.Position.z - (vr.hmdposition[2] + xy[1]);
float zxDist = length(x, z);
if (zxDist != 0.0f && z != 0.0f) {
VectorSet(vr.weaponangles, -degrees(atanf(y / zxDist)),
-degrees(atan2f(x, -z)), 0);
}
} else {
float x =
pOff->HeadPose.Pose.Position.x - pWeapon->HeadPose.Pose.Position.x;
float y =
pOff->HeadPose.Pose.Position.y - pWeapon->HeadPose.Pose.Position.y;
float z =
pOff->HeadPose.Pose.Position.z - pWeapon->HeadPose.Pose.Position.z;
float zxDist = length(x, z);
if (zxDist != 0.0f && z != 0.0f) {
VectorSet(vr.weaponangles, -degrees(atanf(y / zxDist)),
-degrees(atan2f(x, -z)), vr.weaponangles[ROLL] /
2.0f); //Dampen roll on stabilised weapon
}
}
}
// Calculate if player tries to reach backpack
bool handInBackpack = false;
bool bpDistToHMDOk = false, bpWeaponHeightOk = false, bpWeaponAngleOk = false, bpHmdToWeaponAngleOk = false;
vec3_t hmdForwardXY = {}, weaponForwardXY = {};
float weaponToDownAngle = 0, hmdToWeaponDotProduct = 0;
static vec3_t downVector = {0.0, 0.0, -1.0};
bool bpTrackOk = pOffTracking->Status &
VRAPI_TRACKING_STATUS_POSITION_TRACKED; // 1) Position must be tracked
if (bpTrackOk && (bpDistToHMDOk = distanceToHMD >= 0.2 && distanceToHMD <=
0.35) // 2) Weapon-to-HMD distance must be within <0.2-0.35> range
&& (bpWeaponHeightOk = vr.weaponoffset[1] >= -0.10 && vr.weaponoffset[1] <=
0.10)) // 3) Weapon height in relation to HMD must be within <-0.10, 0.10> range
{
AngleVectors(vr.hmdorientation, hmdForwardXY, NULL, NULL);
AngleVectors(vr.weaponangles, weaponForwardXY, NULL, NULL);
float weaponToDownAngle = AngleBetweenVectors(downVector, weaponForwardXY);
// 4) Angle between weapon forward vector and a down vector must be within 80-140 degrees
if (bpWeaponAngleOk = weaponToDownAngle >= 80.0 && weaponToDownAngle <= 140.0) {
hmdForwardXY[2] = 0;
VectorNormalize(hmdForwardXY);
weaponForwardXY[2] = 0;
VectorNormalize(weaponForwardXY);
hmdToWeaponDotProduct = DotProduct(hmdForwardXY, weaponForwardXY);
// 5) HMD and weapon forward on XY plane must go in opposite directions (i.e. dot product < 0)
handInBackpack = bpHmdToWeaponAngleOk = hmdToWeaponDotProduct < 0;
}
}
//off-hand stuff (done here as I reference it in the save state thing
{
vr.offhandposition[0] = pOff->HeadPose.Pose.Position.x;
vr.offhandposition[1] = pOff->HeadPose.Pose.Position.y;
vr.offhandposition[2] = pOff->HeadPose.Pose.Position.z;
vr.offhandoffset[0] = pOff->HeadPose.Pose.Position.x - vr.hmdposition[0];
vr.offhandoffset[1] = pOff->HeadPose.Pose.Position.y - vr.hmdposition[1];
vr.offhandoffset[2] = pOff->HeadPose.Pose.Position.z - vr.hmdposition[2];
vec3_t rotation = {0};
QuatToYawPitchRoll(pOff->HeadPose.Pose.Orientation, rotation, vr.offhandangles);
if (vr_walkdirection->value == 0) {
controllerYawHeading = vr.offhandangles[YAW] - vr.hmdorientation[YAW];
} else {
controllerYawHeading = 0.0f;
}
}
// Use off hand as well to trigger save condition
canUseQuickSave = false;
bool bpOffhandDistToHMDOk = false, bpOffhandHeightOk = false, bpOffhandAngleOk = false, bpHmdToOffhandAngleOk = false;
vec3_t offhandForwardXY = {};
float hmdToOffhandDotProduct = 0;
float offhandToDownAngle = 0;
if (bpTrackOk && (bpOffhandDistToHMDOk = distanceToHMDOff >= 0.2 &&
distanceToHMDOff <=
0.35) // 2) Off-to-HMD distance must be within <0.2-0.35> range
&& (bpOffhandHeightOk = vr.offhandoffset[1] >= -0.10 && vr.offhandoffset[1] <=
0.10)) // 3) Offhand height in relation to HMD must be within <-0.10, 0.10> range
{
//Need to do this again as might not have done it above and cant be bothered to refactor
AngleVectors(vr.hmdorientation, hmdForwardXY, NULL, NULL);
AngleVectors(vr.offhandangles, offhandForwardXY, NULL, NULL);
offhandToDownAngle = AngleBetweenVectors(downVector, offhandForwardXY);
// 4) Angle between weapon forward vector and a down vector must be within 80-140 degrees
if (bpOffhandAngleOk =
offhandToDownAngle >= 80.0 && offhandToDownAngle <= 140.0) {
hmdForwardXY[2] = 0;
VectorNormalize(hmdForwardXY);
offhandForwardXY[2] = 0;
VectorNormalize(offhandForwardXY);
hmdToOffhandDotProduct = DotProduct(hmdForwardXY, offhandForwardXY);
// 5) HMD and weapon forward on XY plane must go in opposite directions (i.e. dot product < 0)
canUseQuickSave = bpHmdToOffhandAngleOk = hmdToOffhandDotProduct < 0;
}
}
// Uncomment to debug offhand reaching
/* ALOGV("Quick Save> Dist: %f | OffHandToDownAngle: %f | HandOffs: %f %f %f\nHmdHandDot: %f | HmdFwdXY: %f %f | WpnFwdXY: %f %f\nTrackOk: %i, DistOk: %i, HeightOk: %i, HnadAngleOk: %i, HmdHandDotOk: %i",
distanceToHMDOff, offhandToDownAngle, vr.offhandoffset[0],
vr.offhandoffset[1], vr.offhandoffset[2],
hmdToOffhandDotProduct, hmdForwardXY[0], hmdForwardXY[1], offhandForwardXY[0],
offhandForwardXY[1],
bpTrackOk, bpOffhandDistToHMDOk, bpOffhandHeightOk, bpOffhandAngleOk,
bpHmdToOffhandAngleOk);
*/
// Check quicksave
if (canUseQuickSave) {
int channel = (vr_control_scheme->integer >= 10) ? 1 : 0;
JKVR_Vibrate(40, channel, 0.5); // vibrate to let user know they can switch
if (((pOffTrackedRemoteNew->Buttons & offButton1) !=
(pOffTrackedRemoteOld->Buttons & offButton1)) &&
(pOffTrackedRemoteNew->Buttons & offButton1)) {
sendButtonActionSimple("savegame quicksave");
}
if (((pOffTrackedRemoteNew->Buttons & offButton2) !=
(pOffTrackedRemoteOld->Buttons & offButton2)) &&
(pOffTrackedRemoteNew->Buttons & offButton2)) {
sendButtonActionSimple("loadgame quicksave");
}
} }
} }
//Right-hand specific stuff if (vr.weapon_stabilised) {
{ if (vr.scopeengaged || vr_virtual_stock->integer == 1) {
//This section corrects for the fact that the controller actually controls direction of movement, but we want to move relative to the direction the //offset to the appropriate eye a little bit
//player is facing for positional tracking vec2_t xy;
rotateAboutOrigin(Cvar_VariableValue("cg_stereoSeparation") / 2.0f, 0.0f,
-vr.hmdorientation[YAW], xy);
float x = pOff->HeadPose.Pose.Position.x - (vr.hmdposition[0] + xy[0]);
float y = pOff->HeadPose.Pose.Position.y -
(vr.hmdposition[1] - 0.1f); // Use a point lower
float z = pOff->HeadPose.Pose.Position.z - (vr.hmdposition[2] + xy[1]);
float zxDist = length(x, z);
//Positional movement speed correction for when we are not hitting target framerate if (zxDist != 0.0f && z != 0.0f) {
static double lastframetime = 0; VectorSet(vr.weaponangles, -degrees(atanf(y / zxDist)),
int refresh = GetRefresh(); -degrees(atan2f(x, -z)), 0);
double newframetime = GetTimeInMilliSeconds();
float multiplier = (float) ((1000.0 / refresh) / (newframetime - lastframetime));
lastframetime = newframetime;
vec2_t v;
float factor = (refresh / 72.0F) *
vr_positional_factor->value; // adjust positional factor based on refresh rate
rotateAboutOrigin(-vr.hmdposition_delta[0] * factor * multiplier,
vr.hmdposition_delta[2] * factor * multiplier,
-vr.hmdorientation[YAW], v);
positional_movementSideways = v[0];
positional_movementForward = v[1];
ALOGV(" positional_movementSideways: %f, positional_movementForward: %f",
positional_movementSideways,
positional_movementForward);
//Jump (A Button)
if ((primaryButtonsNew & primaryButton1) != (primaryButtonsOld & primaryButton1)) {
sendButtonAction("+moveup", (primaryButtonsNew & primaryButton1));
}
//Alt Fire (B Button)
if ((primaryButtonsNew & primaryButton2) != (primaryButtonsOld & primaryButton2)) {
if (vr.cgzoommode > 0)
{
sendButtonActionSimple("invuse");
}
else if (vr.weaponid == WP_SABER && vr.velocitytriggered)
{
//B button toggles saber on/off in first person
if (primaryButtonsNew & primaryButton2) {
sendButtonActionSimple("togglesaber");
}
}
else
{
sendButtonAction("+altattack", (primaryButtonsNew & primaryButton2));
}
}
static bool firing = false;
static bool throwing = false;
int thirdPerson = Cvar_VariableIntegerValue("cg_thirdPerson");
if (vr.weaponid == WP_SABER && !thirdPerson && vr.cgzoommode == 0)
{
static bool previous_throwing = false;
previous_throwing = throwing;
if (!throwing &&
vr.primaryVelocityTriggeredAttack &&
(pDominantTrackedRemoteNew->Buttons & ovrButton_Trigger))
{
throwing = true;
}
else if (throwing && !(pDominantTrackedRemoteNew->Buttons & ovrButton_Trigger))
{
throwing = false;
}
if (previous_throwing != throwing) {
sendButtonAction("+altattack", throwing);
}
}
else if (!vr.velocitytriggered) // Don't fire velocity triggered weapons
{
//Fire Primary - Doesn't trigger the saber
if ((pDominantTrackedRemoteNew->Buttons & ovrButton_Trigger) !=
(pDominantTrackedRemoteOld->Buttons & ovrButton_Trigger)) {
ALOGV("**WEAPON EVENT** Not Grip Pushed %sattack",
(pDominantTrackedRemoteNew->Buttons & ovrButton_Trigger) ? "+" : "-");
firing = (pDominantTrackedRemoteNew->Buttons & ovrButton_Trigger);
sendButtonAction("+attack", firing);
}
if (throwing)
{
//if throwing is still activated here, just disable
throwing = false;
sendButtonAction("+altattack", throwing);
}
}
//Duck - off hand joystick
if ((secondaryButtonsNew & secondaryThumb) !=
(secondaryButtonsOld & secondaryThumb)) {
sendButtonAction("+movedown", (secondaryButtonsNew & secondaryThumb));
}
//Use
if ((pDominantTrackedRemoteNew->Buttons & primaryThumb) !=
(pDominantTrackedRemoteOld->Buttons & primaryThumb)) {
sendButtonAction("+use", (pDominantTrackedRemoteNew->Buttons & primaryThumb));
}
}
{
//Apply a filter and quadratic scaler so small movements are easier to make
float dist = length(pSecondaryJoystick->x, pSecondaryJoystick->y);
float nlf = nonLinearFilter(dist);
float x = (nlf * pSecondaryJoystick->x) + pFootTrackingNew->LeftJoystick.x;
float y = (nlf * pSecondaryJoystick->y) - pFootTrackingNew->LeftJoystick.y;
vr.player_moving = (fabs(x) + fabs(y)) > 0.05f;
//Adjust to be off-hand controller oriented
vec2_t v;
rotateAboutOrigin(x, y, controllerYawHeading, v);
//Move a lot slower if scope is engaged
remote_movementSideways =
v[0] * (vr.scopeengaged ? 0.3f : 1.0f) * vr_movement_multiplier->value;
remote_movementForward =
v[1] * (vr.scopeengaged ? 0.3f : 1.0f) * vr_movement_multiplier->value;
ALOGV(" remote_movementSideways: %f, remote_movementForward: %f",
remote_movementSideways,
remote_movementForward);
if (!canUseQuickSave) {
if ((secondaryButtonsNew & secondaryButton1) !=
(secondaryButtonsOld & secondaryButton1)) {
//Toggle walk/run somehow?!
}
}
//Open the datapad
if (!canUseQuickSave) {
if (((secondaryButtonsNew & secondaryButton2) !=
(secondaryButtonsOld & secondaryButton2)) &&
(secondaryButtonsNew & secondaryButton2)) {
Sys_QueEvent(0, SE_KEY, A_TAB, true, 0, NULL);
}
}
//Use Force - off hand trigger
{
if ((pOffTrackedRemoteNew->Buttons & ovrButton_Trigger) !=
(pOffTrackedRemoteOld->Buttons & ovrButton_Trigger))
{
sendButtonAction("+useforce", (pOffTrackedRemoteNew->Buttons & ovrButton_Trigger));
}
}
//Use smooth in 3rd person
bool usingSnapTurn = vr_turn_mode->integer == 0 ||
(!vr.third_person && vr_turn_mode->integer == 1);
static int increaseSnap = true;
if (!vr.item_selector && !vr.scopeengaged) {
if (usingSnapTurn) {
if (primaryJoystickX > 0.7f) {
if (increaseSnap) {
vr.snapTurn -= vr_turn_angle->value;
increaseSnap = false;
if (vr.snapTurn < -180.0f) {
vr.snapTurn += 360.f;
}
}
} else if (primaryJoystickX < 0.3f) {
increaseSnap = true;
}
}
static int decreaseSnap = true;
if (usingSnapTurn) {
if (primaryJoystickX < -0.7f) {
if (decreaseSnap) {
vr.snapTurn += vr_turn_angle->value;
decreaseSnap = false;
if (vr.snapTurn > 180.0f) {
vr.snapTurn -= 360.f;
}
}
} else if (primaryJoystickX > -0.3f) {
decreaseSnap = true;
}
}
if (!usingSnapTurn && fabs(primaryJoystickX) > 0.1f) //smooth turn
{
vr.snapTurn -= ((vr_turn_angle->value / 10.0f) *
primaryJoystickX);
if (vr.snapTurn > 180.0f) {
vr.snapTurn -= 360.f;
}
} }
} else { } else {
if (fabs(primaryJoystickX) > 0.5f) { float x =
increaseSnap = false; pOff->HeadPose.Pose.Position.x - pWeapon->HeadPose.Pose.Position.x;
} else { float y =
pOff->HeadPose.Pose.Position.y - pWeapon->HeadPose.Pose.Position.y;
float z =
pOff->HeadPose.Pose.Position.z - pWeapon->HeadPose.Pose.Position.z;
float zxDist = length(x, z);
if (zxDist != 0.0f && z != 0.0f) {
VectorSet(vr.weaponangles, -degrees(atanf(y / zxDist)),
-degrees(atan2f(x, -z)), vr.weaponangles[ROLL] /
2.0f); //Dampen roll on stabilised weapon
}
}
}
// Calculate if player tries to reach backpack
bool handInBackpack = false;
bool bpDistToHMDOk = false, bpWeaponHeightOk = false, bpWeaponAngleOk = false, bpHmdToWeaponAngleOk = false;
vec3_t hmdForwardXY = {}, weaponForwardXY = {};
float weaponToDownAngle = 0, hmdToWeaponDotProduct = 0;
static vec3_t downVector = {0.0, 0.0, -1.0};
bool bpTrackOk = pOffTracking->Status &
VRAPI_TRACKING_STATUS_POSITION_TRACKED; // 1) Position must be tracked
if (bpTrackOk && (bpDistToHMDOk = distanceToHMD >= 0.2 && distanceToHMD <=
0.35) // 2) Weapon-to-HMD distance must be within <0.2-0.35> range
&& (bpWeaponHeightOk = vr.weaponoffset[1] >= -0.10 && vr.weaponoffset[1] <=
0.10)) // 3) Weapon height in relation to HMD must be within <-0.10, 0.10> range
{
AngleVectors(vr.hmdorientation, hmdForwardXY, NULL, NULL);
AngleVectors(vr.weaponangles, weaponForwardXY, NULL, NULL);
float weaponToDownAngle = AngleBetweenVectors(downVector, weaponForwardXY);
// 4) Angle between weapon forward vector and a down vector must be within 80-140 degrees
if (bpWeaponAngleOk = weaponToDownAngle >= 80.0 && weaponToDownAngle <= 140.0) {
hmdForwardXY[2] = 0;
VectorNormalize(hmdForwardXY);
weaponForwardXY[2] = 0;
VectorNormalize(weaponForwardXY);
hmdToWeaponDotProduct = DotProduct(hmdForwardXY, weaponForwardXY);
// 5) HMD and weapon forward on XY plane must go in opposite directions (i.e. dot product < 0)
handInBackpack = bpHmdToWeaponAngleOk = hmdToWeaponDotProduct < 0;
}
}
//off-hand stuff (done here as I reference it in the save state thing
{
vr.offhandposition[0] = pOff->HeadPose.Pose.Position.x;
vr.offhandposition[1] = pOff->HeadPose.Pose.Position.y;
vr.offhandposition[2] = pOff->HeadPose.Pose.Position.z;
vr.offhandoffset[0] = pOff->HeadPose.Pose.Position.x - vr.hmdposition[0];
vr.offhandoffset[1] = pOff->HeadPose.Pose.Position.y - vr.hmdposition[1];
vr.offhandoffset[2] = pOff->HeadPose.Pose.Position.z - vr.hmdposition[2];
vec3_t rotation = {0};
QuatToYawPitchRoll(pOff->HeadPose.Pose.Orientation, rotation, vr.offhandangles);
if (vr_walkdirection->value == 0) {
controllerYawHeading = vr.offhandangles[YAW] - vr.hmdorientation[YAW];
} else {
controllerYawHeading = 0.0f;
}
}
// Use off hand as well to trigger save condition
canUseQuickSave = false;
bool bpOffhandDistToHMDOk = false, bpOffhandHeightOk = false, bpOffhandAngleOk = false, bpHmdToOffhandAngleOk = false;
vec3_t offhandForwardXY = {};
float hmdToOffhandDotProduct = 0;
float offhandToDownAngle = 0;
if (bpTrackOk && (bpOffhandDistToHMDOk = distanceToHMDOff >= 0.2 &&
distanceToHMDOff <=
0.35) // 2) Off-to-HMD distance must be within <0.2-0.35> range
&& (bpOffhandHeightOk = vr.offhandoffset[1] >= -0.10 && vr.offhandoffset[1] <=
0.10)) // 3) Offhand height in relation to HMD must be within <-0.10, 0.10> range
{
//Need to do this again as might not have done it above and cant be bothered to refactor
AngleVectors(vr.hmdorientation, hmdForwardXY, NULL, NULL);
AngleVectors(vr.offhandangles, offhandForwardXY, NULL, NULL);
offhandToDownAngle = AngleBetweenVectors(downVector, offhandForwardXY);
// 4) Angle between weapon forward vector and a down vector must be within 80-140 degrees
if (bpOffhandAngleOk =
offhandToDownAngle >= 80.0 && offhandToDownAngle <= 140.0) {
hmdForwardXY[2] = 0;
VectorNormalize(hmdForwardXY);
offhandForwardXY[2] = 0;
VectorNormalize(offhandForwardXY);
hmdToOffhandDotProduct = DotProduct(hmdForwardXY, offhandForwardXY);
// 5) HMD and weapon forward on XY plane must go in opposite directions (i.e. dot product < 0)
canUseQuickSave = bpHmdToOffhandAngleOk = hmdToOffhandDotProduct < 0;
}
}
// Uncomment to debug offhand reaching
/* ALOGV("Quick Save> Dist: %f | OffHandToDownAngle: %f | HandOffs: %f %f %f\nHmdHandDot: %f | HmdFwdXY: %f %f | WpnFwdXY: %f %f\nTrackOk: %i, DistOk: %i, HeightOk: %i, HnadAngleOk: %i, HmdHandDotOk: %i",
distanceToHMDOff, offhandToDownAngle, vr.offhandoffset[0],
vr.offhandoffset[1], vr.offhandoffset[2],
hmdToOffhandDotProduct, hmdForwardXY[0], hmdForwardXY[1], offhandForwardXY[0],
offhandForwardXY[1],
bpTrackOk, bpOffhandDistToHMDOk, bpOffhandHeightOk, bpOffhandAngleOk,
bpHmdToOffhandAngleOk);
*/
// Check quicksave
if (canUseQuickSave) {
int channel = (vr_control_scheme->integer >= 10) ? 1 : 0;
JKVR_Vibrate(40, channel, 0.5); // vibrate to let user know they can switch
if (((pOffTrackedRemoteNew->Buttons & offButton1) !=
(pOffTrackedRemoteOld->Buttons & offButton1)) &&
(pOffTrackedRemoteNew->Buttons & offButton1)) {
sendButtonActionSimple("savegame quicksave");
}
if (((pOffTrackedRemoteNew->Buttons & offButton2) !=
(pOffTrackedRemoteOld->Buttons & offButton2)) &&
(pOffTrackedRemoteNew->Buttons & offButton2)) {
sendButtonActionSimple("loadgame quicksave");
}
}
}
//Right-hand specific stuff
{
//This section corrects for the fact that the controller actually controls direction of movement, but we want to move relative to the direction the
//player is facing for positional tracking
//Positional movement speed correction for when we are not hitting target framerate
static double lastframetime = 0;
int refresh = GetRefresh();
double newframetime = GetTimeInMilliSeconds();
float multiplier = (float) ((1000.0 / refresh) / (newframetime - lastframetime));
lastframetime = newframetime;
vec2_t v;
float factor = (refresh / 72.0F) *
vr_positional_factor->value; // adjust positional factor based on refresh rate
rotateAboutOrigin(-vr.hmdposition_delta[0] * factor * multiplier,
vr.hmdposition_delta[2] * factor * multiplier,
-vr.hmdorientation[YAW], v);
positional_movementSideways = v[0];
positional_movementForward = v[1];
ALOGV(" positional_movementSideways: %f, positional_movementForward: %f",
positional_movementSideways,
positional_movementForward);
//Jump (A Button)
if ((primaryButtonsNew & primaryButton1) != (primaryButtonsOld & primaryButton1)) {
sendButtonAction("+moveup", (primaryButtonsNew & primaryButton1));
}
//Alt Fire (B Button)
if ((primaryButtonsNew & primaryButton2) != (primaryButtonsOld & primaryButton2)) {
if (vr.cgzoommode > 0)
{
sendButtonActionSimple("invuse");
}
else if (vr.weaponid == WP_SABER && vr.velocitytriggered)
{
//B button toggles saber on/off in first person
if (primaryButtonsNew & primaryButton2) {
sendButtonActionSimple("togglesaber");
}
}
else
{
sendButtonAction("+altattack", (primaryButtonsNew & primaryButton2));
}
}
static bool firing = false;
static bool throwing = false;
int thirdPerson = Cvar_VariableIntegerValue("cg_thirdPerson");
if (vr.weaponid == WP_SABER && !thirdPerson && vr.cgzoommode == 0)
{
static bool previous_throwing = false;
previous_throwing = throwing;
if (!throwing &&
vr.primaryVelocityTriggeredAttack &&
(pDominantTrackedRemoteNew->Buttons & ovrButton_Trigger))
{
throwing = true;
}
else if (throwing && !(pDominantTrackedRemoteNew->Buttons & ovrButton_Trigger))
{
throwing = false;
}
if (previous_throwing != throwing) {
sendButtonAction("+altattack", throwing);
}
}
else if (!vr.velocitytriggered) // Don't fire velocity triggered weapons
{
//Fire Primary - Doesn't trigger the saber
if ((pDominantTrackedRemoteNew->Buttons & ovrButton_Trigger) !=
(pDominantTrackedRemoteOld->Buttons & ovrButton_Trigger)) {
ALOGV("**WEAPON EVENT** Not Grip Pushed %sattack",
(pDominantTrackedRemoteNew->Buttons & ovrButton_Trigger) ? "+" : "-");
firing = (pDominantTrackedRemoteNew->Buttons & ovrButton_Trigger);
sendButtonAction("+attack", firing);
}
if (throwing)
{
//if throwing is still activated here, just disable
throwing = false;
sendButtonAction("+altattack", throwing);
}
}
//Duck - off hand joystick
if ((secondaryButtonsNew & secondaryThumb) !=
(secondaryButtonsOld & secondaryThumb)) {
sendButtonAction("+movedown", (secondaryButtonsNew & secondaryThumb));
}
//Use
if ((pDominantTrackedRemoteNew->Buttons & primaryThumb) !=
(pDominantTrackedRemoteOld->Buttons & primaryThumb)) {
sendButtonAction("+use", (pDominantTrackedRemoteNew->Buttons & primaryThumb));
}
}
{
//Apply a filter and quadratic scaler so small movements are easier to make
float dist = length(pSecondaryJoystick->x, pSecondaryJoystick->y);
float nlf = nonLinearFilter(dist);
float x = (nlf * pSecondaryJoystick->x) + pFootTrackingNew->LeftJoystick.x;
float y = (nlf * pSecondaryJoystick->y) - pFootTrackingNew->LeftJoystick.y;
vr.player_moving = (fabs(x) + fabs(y)) > 0.05f;
//Adjust to be off-hand controller oriented
vec2_t v;
rotateAboutOrigin(x, y, controllerYawHeading, v);
//Move a lot slower if scope is engaged
remote_movementSideways =
v[0] * (vr.scopeengaged ? 0.3f : 1.0f) * vr_movement_multiplier->value;
remote_movementForward =
v[1] * (vr.scopeengaged ? 0.3f : 1.0f) * vr_movement_multiplier->value;
ALOGV(" remote_movementSideways: %f, remote_movementForward: %f",
remote_movementSideways,
remote_movementForward);
if (!canUseQuickSave) {
if ((secondaryButtonsNew & secondaryButton1) !=
(secondaryButtonsOld & secondaryButton1)) {
//Toggle walk/run somehow?!
}
}
//Open the datapad
if (!canUseQuickSave) {
if (((secondaryButtonsNew & secondaryButton2) !=
(secondaryButtonsOld & secondaryButton2)) &&
(secondaryButtonsNew & secondaryButton2)) {
Sys_QueEvent(0, SE_KEY, A_TAB, true, 0, NULL);
}
}
//Use Force - off hand trigger
{
if ((pOffTrackedRemoteNew->Buttons & ovrButton_Trigger) !=
(pOffTrackedRemoteOld->Buttons & ovrButton_Trigger))
{
sendButtonAction("+useforce", (pOffTrackedRemoteNew->Buttons & ovrButton_Trigger));
}
}
//Use smooth in 3rd person
bool usingSnapTurn = vr_turn_mode->integer == 0 ||
(!vr.third_person && vr_turn_mode->integer == 1);
static int increaseSnap = true;
if (!vr.item_selector && !vr.scopeengaged) {
if (usingSnapTurn) {
if (primaryJoystickX > 0.7f) {
if (increaseSnap) {
vr.snapTurn -= vr_turn_angle->value;
increaseSnap = false;
if (vr.snapTurn < -180.0f) {
vr.snapTurn += 360.f;
}
}
} else if (primaryJoystickX < 0.3f) {
increaseSnap = true; increaseSnap = true;
} }
} }
}
updateScopeAngles(); static int decreaseSnap = true;
if (usingSnapTurn) {
if (primaryJoystickX < -0.7f) {
if (decreaseSnap) {
vr.snapTurn += vr_turn_angle->value;
decreaseSnap = false;
if (vr.snapTurn > 180.0f) {
vr.snapTurn -= 360.f;
}
}
} else if (primaryJoystickX > -0.3f) {
decreaseSnap = true;
}
}
if (!usingSnapTurn && fabs(primaryJoystickX) > 0.1f) //smooth turn
{
vr.snapTurn -= ((vr_turn_angle->value / 10.0f) *
primaryJoystickX);
if (vr.snapTurn > 180.0f) {
vr.snapTurn -= 360.f;
}
}
} else {
if (fabs(primaryJoystickX) > 0.5f) {
increaseSnap = false;
} else {
increaseSnap = true;
}
}
} }
//process force motion controls here
if (vr_force_motion_controlled->integer)
{
if (vr.secondaryswingvelocity > vr_force_velocity_trigger->value)
{
if (!vr.secondaryVelocityTriggeredAttack)
{
VectorCopy(vr.offhandposition, vr.secondaryVelocityTriggerLocation);
vr.secondaryVelocityTriggeredAttack = true;
}
}
else
{
if (vr.secondaryVelocityTriggeredAttack)
{
vec3_t delta1, delta2;
VectorSubtract(vr.offhandposition, vr.hmdposition, delta1);
VectorSubtract(vr.secondaryVelocityTriggerLocation, vr.hmdposition, delta2);
if (VectorLength(delta1) > VectorLength(delta2))
{
sendButtonActionSimple("useGivenForce 3"); // PULL
}
else
{
sendButtonActionSimple("useGivenForce 4"); // PUSH
}
vr.secondaryVelocityTriggeredAttack = false;
}
}
}
updateScopeAngles();
} }
//Save state //Save state
rightTrackedRemoteState_old = rightTrackedRemoteState_new; rightTrackedRemoteState_old = rightTrackedRemoteState_new;
leftTrackedRemoteState_old = leftTrackedRemoteState_new; leftTrackedRemoteState_old = leftTrackedRemoteState_new;

View file

@ -1980,6 +1980,40 @@ usually be a couple times for each server frame on fast clients.
*/ */
extern int G_FindLocalInterestPoint( gentity_t *self ); extern int G_FindLocalInterestPoint( gentity_t *self );
extern void ForceGrip(gentity_t *ent);
extern void ForceLightning(gentity_t *ent);
extern void ForceTelepathy(gentity_t *ent);
extern void ForceHeal(gentity_t *ent);
extern void ForceThrowEx( gentity_t *self, qboolean pull, qboolean aimByViewAngles );
static void ProcessGenericCmd(gentity_t *ent, byte cmd)
{
switch(cmd) {
default:
break;
case GENCMD_FORCE_HEAL:
ForceHeal( ent );
break;
case GENCMD_FORCE_SPEED:
ForceSpeed( ent );
break;
case GENCMD_FORCE_THROW:
ForceThrowEx(ent, qfalse, qtrue);
break;
case GENCMD_FORCE_PULL:
ForceThrowEx(ent, qtrue, qtrue);
break;
case GENCMD_FORCE_DISTRACT:
ForceTelepathy(ent);
break;
case GENCMD_FORCE_GRIP:
ForceGrip(ent);
break;
case GENCMD_FORCE_LIGHTNING:
ForceLightning(ent);
break;
}
}
void ClientThink_real( gentity_t *ent, usercmd_t *ucmd ) void ClientThink_real( gentity_t *ent, usercmd_t *ucmd )
{ {
gclient_t *client; gclient_t *client;
@ -2768,6 +2802,8 @@ extern cvar_t *g_skippingcin;
// perform a pmove // perform a pmove
Pmove( &pm ); Pmove( &pm );
ProcessGenericCmd(ent, pm.cmd.generic_cmd);
// save results of pmove // save results of pmove
if ( ent->client->ps.eventSequence != oldEventSequence ) if ( ent->client->ps.eventSequence != oldEventSequence )
{ {

View file

@ -5599,7 +5599,13 @@ void WP_ForceKnockdown( gentity_t *self, gentity_t *pusher, qboolean pull, qbool
self->forcePushTime = level.time + 600; // let the push effect last for 600 ms self->forcePushTime = level.time + 600; // let the push effect last for 600 ms
} }
void ForceThrowEx( gentity_t *self, qboolean pull, qboolean aimByViewAngles );
void ForceThrow( gentity_t *self, qboolean pull ) void ForceThrow( gentity_t *self, qboolean pull )
{
ForceThrowEx(self, pull, qfalse);
}
void ForceThrowEx( gentity_t *self, qboolean pull, qboolean aimByViewAngles )
{//FIXME: pass in a target ent so we (an NPC) can push/pull just one targeted ent. {//FIXME: pass in a target ent so we (an NPC) can push/pull just one targeted ent.
//shove things in front of you away //shove things in front of you away
float dist; float dist;
@ -5721,10 +5727,11 @@ void ForceThrow( gentity_t *self, qboolean pull )
G_Sound( self, soundIndex ); G_Sound( self, soundIndex );
vec3_t origin, angles; vec3_t origin, angles;
if (self->client->ps.clientNum == 0 && !cg.renderingThirdPerson) if (self->client->ps.clientNum == 0 && !cg.renderingThirdPerson && !aimByViewAngles)
{ {
BG_CalculateVROffHandPosition(origin, fwdangles); BG_CalculateVROffHandPosition(origin, fwdangles);
AngleVectors( fwdangles, forward, right, NULL );
VectorCopy( origin, center );
} }
else else
{ {
@ -8178,9 +8185,7 @@ static void WP_ForcePowerRun( gentity_t *self, forcePowers_t forcePower, usercmd
self->client->ps.forceGripEntityInitialDist == ENTITYNUM_NONE) self->client->ps.forceGripEntityInitialDist == ENTITYNUM_NONE)
{ {
vec3_t diff; vec3_t diff;
diff[2] = 0; VectorSubtract(vr->offhandposition, vr->hmdposition, diff);
VectorSubtract2(self->client->renderInfo.handLPoint,
self->client->renderInfo.eyePoint, diff);
self->client->ps.forceGripEntityInitialDist = VectorLength(diff); self->client->ps.forceGripEntityInitialDist = VectorLength(diff);
} }
@ -8199,13 +8204,11 @@ static void WP_ForcePowerRun( gentity_t *self, forcePowers_t forcePower, usercmd
{//carry {//carry
if (isFirstPersonPlayer) { if (isFirstPersonPlayer) {
vec3_t diff; vec3_t diff;
diff[2] = 0; VectorSubtract(vr->offhandposition, vr->hmdposition, diff);
VectorSubtract2(self->client->renderInfo.handLPoint,
self->client->renderInfo.eyePoint, diff);
float length = VectorLength(diff); float length = VectorLength(diff);
if (fabs(length - self->client->ps.forceGripEntityInitialDist) > 1.0f) { float movedLength = (length - self->client->ps.forceGripEntityInitialDist) * cg_worldScale.value;
dist += (length - self->client->ps.forceGripEntityInitialDist) * if (fabs(movedLength) > 1.0f) {
5.0f; dist += movedLength * 5.0f;
} }
if (dist > 384) { if (dist > 384) {
dist = 384; dist = 384;