DayZ 1.27
DayZ Explorer by KGB
 
Загрузка...
Поиск...
Не найдено

◆ LiftWeaponCheck()

bool Weapon::LiftWeaponCheck ( PlayerBase player)
inlineprotected

См. определение в файле Weapon_Base.c строка 1334

1335 {
1336 int idx;
1337 float distance;
1338 float hit_fraction;
1339 vector start, end;
1340 vector direction;
1341 vector hit_pos, hit_normal;
1342 Object obj;
1343
1344 bool wasLift = m_LiftWeapon;
1345 vector lastLiftPosition = m_LastLiftPosition;
1346
1347 m_LiftWeapon = false;
1348 // not a gun, no weap.raise for now
1349 if ( HasSelection("Usti hlavne") )
1350 return false;
1351
1352 if (!player)
1353 {
1354 Print("Error: No weapon owner, returning");
1355 return false;
1356 }
1357
1358 // weapon not raised
1359 HumanMovementState movementState = new HumanMovementState();
1360 player.GetMovementState(movementState);
1361 if (!movementState.IsRaised())
1362 return false;
1363
1364 // suppress raising of weapon during melee attack preventing state inconsistency
1365 if (movementState.m_CommandTypeId == DayZPlayerConstants.COMMANDID_MELEE || movementState.m_CommandTypeId == DayZPlayerConstants.COMMANDID_MELEE2)
1366 {
1367 return false;
1368 }
1369
1370
1371 // If possible use aiming angles instead as these will work consistently
1372 // and independently of any cameras, etc.
1373 HumanCommandWeapons hcw = player.GetCommandModifier_Weapons();
1374 if (hcw)
1375 {
1376 vector yawPitchRoll = Vector(
1377 hcw.GetBaseAimingAngleLR() + player.GetOrientation()[0],
1379 0.0);
1380
1381 float xAimHandsOffset = hcw.GetAimingHandsOffsetLR();
1382 float yAimHandsOffset = hcw.GetAimingHandsOffsetUD();
1383
1384 yawPitchRoll[0] = yawPitchRoll[0] + xAimHandsOffset;
1385 yawPitchRoll[1] = Math.Clamp( yawPitchRoll[1] + yAimHandsOffset, DayZPlayerCamera1stPerson.CONST_UD_MIN, DayZPlayerCamera1stPerson.CONST_UD_MAX );
1386
1387 direction = yawPitchRoll.AnglesToVector();
1388 }
1389 else // Fallback to previously implemented logic
1390 {
1391 // freelook raycast
1392 if (player.GetInputController().CameraIsFreeLook())
1393 {
1394 if (player.m_DirectionToCursor != vector.Zero)
1395 {
1396 direction = player.m_DirectionToCursor;
1397 }
1398 // if player raises weapon in freelook
1399 else
1400 {
1401 direction = MiscGameplayFunctions.GetHeadingVector(player);
1402 }
1403 }
1404 else
1405 {
1406 direction = GetGame().GetCurrentCameraDirection(); // exception for freelook. Much better this way!
1407 }
1408 }
1409
1410 idx = player.GetBoneIndexByName("Neck"); //RightHandIndex1
1411 if ( idx == -1 )
1412 { start = player.GetPosition()[1] + 1.5; }
1413 else
1414 { start = player.GetBonePositionWS(idx); }
1415
1416
1417 // Updated weapon lift detection code prototype
1418 {
1419 // 0: construct stable trasformation matrix that
1420 // approximately aligns with the weapon transform
1421 // without actually using the weapon as reference
1422 // (as the weapon can be moved unpredictably by anims)
1423 vector resTM[4];
1424 resTM[0] = Vector(direction[0], 0, direction[2]).Normalized();
1425 resTM[0] = vector.RotateAroundZeroDeg(resTM[0], vector.Up, 90);
1426 resTM[2] = direction;
1427 resTM[1] = resTM[2] * resTM[0];
1428 resTM[3] = start;
1429
1430 // Approximate the roll of leaning
1431 HumanMovementState hms = new HumanMovementState();
1432 player.GetMovementState(hms);
1433 float leanAngle = hms.m_fLeaning * 35;
1434 vector rotTM[3];
1435 Math3D.YawPitchRollMatrix( Vector(xAimHandsOffset , yAimHandsOffset, leanAngle), rotTM );
1436 Math3D.MatrixMultiply3(resTM, rotTM, resTM);
1437
1438 // Draw relative TM diagnostic
1439 #ifdef DIAG_DEVELOPER
1440 if (DiagMenu.GetValue(DiagMenuIDs.WEAPON_LIFT_DEBUG))
1441 {
1442 Shape.CreateArrow(resTM[3], resTM[3] + resTM[0], 0.05, COLOR_RED, ShapeFlags.ONCE);
1443 Shape.CreateArrow(resTM[3], resTM[3] + resTM[1], 0.05, COLOR_GREEN, ShapeFlags.ONCE);
1444 Shape.CreateArrow(resTM[3], resTM[3] + resTM[2], 0.05, COLOR_BLUE, ShapeFlags.ONCE);
1445 }
1446 #endif
1447
1448 // 1: pick from predefined offset relative to
1449 // the previously constructed transform
1450 float udAngle = Math.Asin(direction[1]) * Math.RAD2DEG;
1451
1452 // offsets are [right, up, forward]
1453 // values are based on what felt right after iterating
1454 vector offsets[] =
1455 {
1456 "0.11 0.17 0.0", // offset while aiming down
1457 "0.12 0.05 0.0", // offset while aiming forward
1458 "0.112 0.03 0.0" // offset while aiming up
1459 };
1460 const int lastIndex = 2; // length of offsets - 1
1461
1462 // <0,1> range of aiming
1463 float a = Math.Clamp(Math.InverseLerp(DayZPlayerCamera1stPerson.CONST_UD_MIN, DayZPlayerCamera1stPerson.CONST_UD_MAX, udAngle), 0, 0.9999);
1464 int lo = a * lastIndex;
1465 int hi = Math.Clamp(lo+1, 0, lastIndex);
1466
1467 // remap to current lo-hi range
1468 float t = Math.Clamp(a * lastIndex - lo, 0, 1);
1469 vector offset = vector.Lerp(offsets[lo], offsets[hi], t);
1470
1471 // offsets are [right, up forward]
1472 // additional offsets added to previous offsets per stance
1473 vector stanceOffsets[] =
1474 {
1475 "0 -0.015 0", // erect
1476 "0 0.03 0", // crouch
1477 "0 -0.04 0",// prone
1478 };
1479
1480 // 2. pick from predefined offsets based on stance,
1481 // allows to even further approximate the alignment
1482 int stanceOffsetIndex = hms.m_iStanceIdx;
1483 if (stanceOffsetIndex >= DayZPlayerConstants.STANCEIDX_PRONE)
1484 stanceOffsetIndex -= DayZPlayerConstants.STANCEIDX_RAISED;
1485
1486 stanceOffsetIndex -= DayZPlayerConstants.STANCEIDX_ERECT;
1487 offset += stanceOffsets[stanceOffsetIndex];
1488
1489 // if any additional height offset is defined, apply it
1491 {
1492 offset[1] = offset[1] + m_WeaponLiftCheckVerticalOffset;
1493 }
1494
1495 //
1496 offset = offset.InvMultiply3(rotTM);
1497
1498 // 3. use the offset as the start position.
1499 // it will not be perfect, but it should reflect
1500 // the actual weapon transform more accurately
1501 start = offset.Multiply4(resTM);
1502 }
1503
1504
1506
1507 vector weaponStart = start + (m_ShoulderDistance * direction);
1508 vector weaponEnd = weaponStart + (distance * direction);
1509
1510 // Draw diagnostics: Script -> Weapon -> Weapon Lift
1511 #ifdef DIAG_DEVELOPER
1512 if (DiagMenu.GetValue(DiagMenuIDs.WEAPON_LIFT_DEBUG))
1513 {
1514 vector diagNoAttachEnd = weaponStart + (m_WeaponLength * direction);
1515 int diagPtsShpFlgs = ShapeFlags.ONCE | ShapeFlags.NOOUTLINE;
1516 float diagPtsRadius = 0.025;
1517 Shape.CreateSphere(COLOR_GREEN, diagPtsShpFlgs, weaponStart, diagPtsRadius);
1518 Shape.CreateSphere(COLOR_YELLOW, diagPtsShpFlgs, diagNoAttachEnd, diagPtsRadius);
1519 Shape.CreateSphere(COLOR_BLUE, diagPtsShpFlgs, weaponEnd, diagPtsRadius);
1520 }
1521 #endif
1522
1523 // For the physical cast, extend the distance by x%
1524 // to allow for smoother transition handling in some cases
1525 end = weaponEnd + ((0.1 * distance) * direction);
1526
1527 // Prepare raycast params and perform the cast in fire geo
1528 RaycastRVParams rayParm = new RaycastRVParams(start, end, player, 0.02);
1529 rayParm.flags = CollisionFlags.ALLOBJECTS;
1530 rayParm.type = ObjIntersect.Fire;
1531
1532 #ifdef DIAG_DEVELOPER
1533 DbgUI.BeginCleanupScope();
1534 #endif
1535 array<ref RaycastRVResult> results = {};
1536 if (!DayZPhysics.RaycastRVProxy(rayParm, results) || results.Count() == 0)
1537 {
1538 hit_pos = vector.Zero;
1539 hit_fraction = 0;
1540 }
1541 else
1542 {
1543 RaycastRVResult res = results[0];
1544
1545 #ifdef DIAG_DEVELOPER // isect diag
1546 if (DiagMenu.GetValue(DiagMenuIDs.WEAPON_LIFT_DEBUG) == 2)
1547 {
1548 DbgUI.Begin("Weapon Lift Diag");
1549 {
1550 if (res.surface)
1551 {
1552 DbgUI.Text("Intersection data:");
1553 DbgUI.Text(" Name: " + res.surface.GetName());
1554 DbgUI.Text(" EntryName: " + res.surface.GetEntryName());
1555 DbgUI.Text(" SurfaceType: " + res.surface.GetSurfaceType());
1556
1557 DbgUI.Text(" IsPassThrough: " + res.surface.IsPassthrough());
1558 DbgUI.Text(" IsSolid: " + res.surface.IsSolid());
1559 }
1560 else
1561 {
1562 DbgUI.Text("Intersection with no surface");
1563 }
1564 }
1565 DbgUI.End();
1566 }
1567 #endif // !isect diag
1568
1570 {
1571 hit_pos = res.pos;
1572 float len0 = (hit_pos - start).Length();
1573 float len1 = (end - start).Length();
1574 if (len0 <= 0 || len1 <= 0)
1575 {
1576 hit_fraction = 1;
1577 }
1578 else
1579 {
1580 hit_fraction = len0 / len1;
1581 }
1582 }
1583 else
1584 {
1585 hit_pos = vector.Zero;
1586 hit_fraction = 0;
1587 }
1588 }
1589 #ifdef DIAG_DEVELOPER
1590 DbgUI.EndCleanupScope();
1591 #endif
1592
1593 // Draw diagnostics: Script -> Weapon -> Weapon Lift
1594 #ifdef DIAG_DEVELOPER
1595 if (DiagMenu.GetValue(DiagMenuIDs.WEAPON_LIFT_DEBUG))
1596 {
1597 const vector epsilon = "0 0.0002 0"; // to overcome excessive z-fighting for diag
1598 if (lastLiftPosition!=vector.Zero)
1599 {
1600 Shape.CreateArrow(start-epsilon, lastLiftPosition-epsilon, 0.05, COLOR_YELLOW, ShapeFlags.ONCE);
1601 }
1602
1603 Shape.CreateArrow(start, weaponEnd, 0.05, COLOR_WHITE, ShapeFlags.ONCE | ShapeFlags.NOZBUFFER );
1604
1605 if (hit_fraction != 0)
1606 {
1607 Shape.CreateArrow(start+epsilon, hit_pos+epsilon, 0.05, COLOR_RED, ShapeFlags.ONCE);
1608 }
1609 }
1610 #endif
1611
1612 // Start by assuming that we want to retain state
1613 bool wantsLift = wasLift;
1614
1615 // Sq. distance of weapon movement required to trigger lift (in)
1616 const float inThreshold = 0.002;
1617 // Sq. distance of weapon movement required to trigger lift (out)
1618 const float outThreshold = 0.003;
1619 const float noIsctOutThreshold = 0.01;
1620 // Max num of ticks with no hit for which hysteresis will persist
1621 // value chosen by iteration, should be approx 0.333s
1622 const int maxNumMissedTicks = 10;
1623
1624 // Min angle in degrees change from last lift to stop lifting
1625 // Base threshold of 0.75 degrees + 0.6 degrees per meter of weapon length
1626 float angleThreshold = 0.75 + Math.Clamp( m_WeaponLength * 0.6, 0, 1.5 );
1627
1628 // Update state when a hit is registered
1629 if (hit_fraction != 0)
1630 {
1631 vector v1 = hit_pos - weaponEnd;
1632 vector v2 = hit_pos - end;
1633 float d = vector.Dot(v1, v2);
1634 // But leave some threshold where previous state is kept
1635 // to prevent excessive switches from occuring
1636 if (!wasLift && d > inThreshold)
1637 {
1638 wantsLift = true;
1639 }
1640 else if (wasLift && d < -outThreshold)
1641 {
1642 wantsLift = false;
1643 }
1644
1645 m_LastLiftPosition = hit_pos;
1646 m_LastLiftHit = player.GetSimulationTimeStamp();
1647 }
1648 else
1649 {
1650 // With no hit and no previous lift
1651 if (lastLiftPosition == vector.Zero)
1652 {
1653 wantsLift = false;
1654 m_LastLiftPosition = vector.Zero;
1655 }
1656 // See if previous hit wasn't very close to our current position,
1657 // in which case simply don't lift the weapon
1658 else
1659 {
1660 vector v3 = (lastLiftPosition - start).Normalized();
1661 vector v4 = (end-start).Normalized();
1662 float d2 = vector.Dot(v3, v4);
1663 // no isect, angle delta check
1664 if (Math.Acos(d2) > (angleThreshold * Math.DEG2RAD)) // if relative angle is > x degree, stop lifting
1665 {
1666 wantsLift = false;
1667 m_LastLiftPosition = vector.Zero;
1668 }
1669 // no isect, distance check
1670 else
1671 {
1672 float d3 = vector.Dot( lastLiftPosition - weaponEnd, (start-end).Normalized() );
1673 if (d3 < -noIsctOutThreshold)
1674 {
1675 wantsLift = false;
1676 m_LastLiftPosition = vector.Zero;
1677 }
1678
1679 // fallback in case offending object disappears or moves
1680 int timeSinceHit = player.GetSimulationTimeStamp() - m_LastLiftHit;
1681 if (timeSinceHit > maxNumMissedTicks)
1682 {
1683 wantsLift = false;
1684 m_LastLiftPosition = vector.Zero;
1685 }
1686 }
1687 }
1688 }
1689
1690 // lift is desired
1691 if (wantsLift)
1692 {
1693 //Print(distance);
1694 m_LiftWeapon = true;
1695 return true;
1696 }
1697 return false;
1698 }
void DayZPlayerCamera1stPerson(DayZPlayer pPlayer, HumanInputController pInput)
Определения DayZPlayerCamera1stPerson.c:112
DiagMenuIDs
Определения EDiagMenuIDs.c:2
proto native vector GetCurrentCameraDirection()
proto native float GetAimingHandsOffsetUD()
returns aiming hands up/down (y) offset angle
proto native float GetBaseAimingAngleLR()
returns base aiming angle LR - without sway/offsets/...
proto native float GetAimingHandsOffsetLR()
returns aiming hands left/right (x) offset angle
proto native float GetBaseAimingAngleUD()
returns base aiming angle UD - without sway/offsets/...
int m_iStanceIdx
current command's id
Определения human.c:1141
int m_CommandTypeId
Определения human.c:1140
float m_fLeaning
current movement (0 idle, 1 walk, 2-run, 3-sprint), only if the command has a movement
Определения human.c:1143
bool IsRaised()
Определения human.c:1148
SurfaceInfo surface
surface material info handle
Определения DayZPhysics.c:109
vector pos
position of collision (in world coord)
Определения DayZPhysics.c:103
proto string GetName()
proto bool IsSolid()
proto string GetSurfaceType()
proto bool IsPassthrough()
proto string GetEntryName()
int m_LastLiftHit
Определения Weapon_Base.c:68
float m_WeaponLiftCheckVerticalOffset
Определения Weapon_Base.c:65
float GetEffectiveAttachmentLength()
Returns effective length of attachments that influence total weapon length.
Определения Weapon_Base.c:1707
float m_ShoulderDistance
Определения Weapon_Base.c:66
vector m_LastLiftPosition
Определения Weapon_Base.c:67
bool LiftWeaponRaycastResultCheck(notnull RaycastRVResult res)
Return whether provided material triggers weapon lift (true) or not (false).
Определения Weapon_Base.c:1701
bool m_LiftWeapon
Определения Weapon_Base.c:51
float m_WeaponLength
Определения Weapon_Base.c:64
proto vector Normalized()
return normalized vector (keeps orginal vector untouched)
proto vector Multiply4(vector mat[4])
Transforms position.
static vector RotateAroundZeroDeg(vector vec, vector axis, float angle)
Rotate a vector around 0,0,0 by an angle in degrees.
Определения EnConvert.c:450
static float Dot(vector v1, vector v2)
Returns Dot product of vector v1 and vector v2.
Определения EnConvert.c:271
static const vector Zero
Определения EnConvert.c:110
proto vector InvMultiply3(vector mat[3])
Invert-transforms vector.
proto vector AnglesToVector()
Converts spherical coordinates (yaw, pitch, roll in degrees) to unit length vector.
DayZPlayerConstants
defined in C++
Определения dayzplayer.c:602
class LOD Object
proto native CGame GetGame()
const int COLOR_BLUE
Определения constants.c:66
const int COLOR_RED
Определения constants.c:64
const int COLOR_GREEN
Определения constants.c:65
const int COLOR_WHITE
Определения constants.c:63
const int COLOR_YELLOW
Определения constants.c:67
proto void Print(void var)
Prints content of variable to console/log.
CollisionFlags
Определения EnDebug.c:141
ShapeFlags
Определения EnDebug.c:126
class DiagMenu Shape
don't call destructor directly. Use Destroy() instead
proto native vector Vector(float x, float y, float z)
Vector constructor from components.
void HumanCommandWeapons()
Определения human.c:1113

Перекрестные ссылки Math::Acos(), vector::AnglesToVector(), Math::Asin(), DbgUI::Begin(), DbgUI::BeginCleanupScope(), Math::Clamp(), COLOR_BLUE, COLOR_GREEN, COLOR_RED, COLOR_WHITE, COLOR_YELLOW, Math::DEG2RAD, vector::Dot(), DbgUI::End(), DbgUI::EndCleanupScope(), HumanCommandWeapons::GetAimingHandsOffsetLR(), HumanCommandWeapons::GetAimingHandsOffsetUD(), HumanCommandWeapons::GetBaseAimingAngleLR(), HumanCommandWeapons::GetBaseAimingAngleUD(), CGame::GetCurrentCameraDirection(), GetEffectiveAttachmentLength(), SurfaceInfo::GetEntryName(), GetGame(), SurfaceInfo::GetName(), SurfaceInfo::GetSurfaceType(), DiagMenu::GetValue(), Math::InverseLerp(), vector::InvMultiply3(), SurfaceInfo::IsPassthrough(), HumanMovementState::IsRaised(), SurfaceInfo::IsSolid(), vector::Lerp(), LiftWeaponRaycastResultCheck(), HumanMovementState::m_CommandTypeId, HumanMovementState::m_fLeaning, HumanMovementState::m_iStanceIdx, m_LastLiftHit, m_LastLiftPosition, m_LiftWeapon, m_ShoulderDistance, m_WeaponLength, m_WeaponLiftCheckVerticalOffset, Math3D::MatrixMultiply3(), vector::Multiply4(), vector::Normalized(), RaycastRVResult::pos, Print(), Math::RAD2DEG, DayZPhysics::RaycastRVProxy(), vector::RotateAroundZeroDeg(), Shape, RaycastRVResult::surface, DbgUI::Text(), vector::Up, Vector(), Math3D::YawPitchRollMatrix() и vector::Zero.