bool CPlayerStateGround::CheckForVaultTrigger(CPlayer & player, float frameTime) { const int enableVaultFromStandingCVar = g_pGameCVars->pl_ledgeClamber.enableVaultFromStanding; const bool doCheck = (enableVaultFromStandingCVar == 3) || ((enableVaultFromStandingCVar > 0) && player.m_jumpButtonIsPressed); if (doCheck) { SLedgeTransitionData ledgeTransition(LedgeId::invalid_id); const float zPos = player.GetEntity()->GetWorldPos().z; const bool ignoreMovement = (enableVaultFromStandingCVar == 2); if (CPlayerStateLedge::TryLedgeGrab(player, zPos, zPos, true, &ledgeTransition, ignoreMovement) && ledgeTransition.m_ledgeTransition != SLedgeTransitionData::eOLT_None) { CRY_ASSERT( LedgeId(ledgeTransition.m_nearestGrabbableLedgeId).IsValid() ); const SLedgeInfo ledgeInfo = g_pGame->GetLedgeManager()->GetLedgeById( LedgeId(ledgeTransition.m_nearestGrabbableLedgeId) ); CRY_ASSERT( ledgeInfo.IsValid() ); if (ledgeInfo.AreAnyFlagsSet(kLedgeFlag_useVault|kLedgeFlag_useHighVault)) { #ifdef STATE_DEBUG if (g_pGameCVars->pl_ledgeClamber.debugDraw) { const char * transitionName = s_ledgeTransitionNames[ledgeTransition.m_ledgeTransition]; IEntity* pEntity = gEnv->pEntitySystem->GetEntity(ledgeInfo.GetEntityId()); CryWatch ("[LEDGEGRAB] $5%s nearest ledge: %s%s%s%s, transition=%s", player.GetEntity()->GetEntityTextDescription(), pEntity ? pEntity->GetEntityTextDescription() : "none", ledgeInfo.AreFlagsSet(kLedgeFlag_isThin) ? " THIN" : "", ledgeInfo.AreFlagsSet(kLedgeFlag_isWindow) ? " WINDOW" : "", ledgeInfo.AreFlagsSet(kLedgeFlag_endCrouched) ? " ENDCROUCHED" : "", transitionName); } #endif if (player.m_jumpButtonIsPressed || enableVaultFromStandingCVar == 3) { ledgeTransition.m_comingFromOnGround=true; ledgeTransition.m_comingFromSprint=player.IsSprinting(); SStateEventLedge ledgeEvent(ledgeTransition); player.StateMachineHandleEventMovement(ledgeEvent); return true; } else { #ifdef STATE_DEBUG if (g_pGameCVars->pl_ledgeClamber.debugDraw) { const char * message = NULL; switch (ledgeTransition.m_ledgeTransition) { case SLedgeTransitionData::eOLT_VaultOnto: message = "CLIMB"; break; case SLedgeTransitionData::eOLT_VaultOver: message = "VAULT"; break; default: CRY_ASSERT_TRACE(0, ("Unexpected ledge transition #%d when trying to display HUD prompt for vault-from-standing!", ledgeTransition.m_ledgeTransition)); break; } if (message) { const float textColor[4] = {1.f, 1.f, 1.f, 1.0f}; const float bracketColor[4] = {0.7f, 0.7f, 0.7f, 1.0f}; const float iconSize = 4.f; const float textSize = 2.f; const float iconColor[4] = {0.3f, 1.f, 0.3f, 1.0f}; const char * iconText = "A"; gEnv->pRenderer->Draw2dLabel((gEnv->pRenderer->GetWidth() * 0.5f), (gEnv->pRenderer->GetHeight() * 0.65f), iconSize, bracketColor, true, "( )"); gEnv->pRenderer->Draw2dLabel((gEnv->pRenderer->GetWidth() * 0.5f), (gEnv->pRenderer->GetHeight() * 0.65f), iconSize, iconColor, true, "%s", iconText); gEnv->pRenderer->Draw2dLabel((gEnv->pRenderer->GetWidth() * 0.5f), (gEnv->pRenderer->GetHeight() * 0.72f), textSize, textColor, true, "%s", message); } } #endif } } } } return false; }
LedgeId CLedgeManager::FindNearestLedge( const Vec3 &referencePosition, const Vec3 &testDirection, float maxDistance /*= 2.0f*/, float angleRange /*= DEG2RAD(35.0f)*/, float extendedAngleRange /*= DEG2RAD(50.0f)*/ ) const { if (m_editorManager.IsInEditorMode()) { return m_editorManager.FindNearestLedge( referencePosition, testDirection, maxDistance, angleRange, extendedAngleRange ); } else { LedgeId bestLedgeId; float closestDistanceSq = maxDistance* maxDistance; const float fCosMaxAngleTable[2] = { cosf(angleRange), cosf(extendedAngleRange) }; const float side[2] = { 1.0f, -1.0f }; SLedgeInfo ledgeInfo; const uint32 ledgeObjectCount = m_levelLedges.m_ledgeCount; for(uint32 objectIdx = 0; objectIdx < ledgeObjectCount; ++objectIdx) { const SLedgeObject& ledgeObject = m_levelLedges.m_pLedgeObjects[objectIdx]; const uint32 startMarkerIdx = ledgeObject.m_markersStartIdx; const uint32 endMarkerIdx = ledgeObject.m_markersStartIdx + ledgeObject.m_markersCount; CRY_ASSERT ( endMarkerIdx <= m_levelLedges.m_markerCount ); const uint32 sideCount = 1 + ((ledgeObject.m_ledgeFlags[LedgeSide_In] & kLedgeFlag_isDoubleSided) != 0); const bool enabled = (ledgeObject.m_ledgeFlags[LedgeSide_In] & kLedgeFlag_enabled) != 0; CRY_ASSERT(sideCount <= 2); uint32 currentSide = 0; do { for (uint32 markerIdx = startMarkerIdx; markerIdx < (endMarkerIdx - 1); ++markerIdx) { ELedgeFlagBitfield flags = kLedgeFlag_none; if (m_levelLedges.m_pMarkers[markerIdx].m_endOrCorner) { flags |= kledgeRunTimeOnlyFlag_p0IsEndOrCorner; } if (m_levelLedges.m_pMarkers[markerIdx+1].m_endOrCorner) { flags |= kledgeRunTimeOnlyFlag_p1IsEndOrCorner; } ledgeInfo = SLedgeInfo( ledgeObject.m_entityId, m_levelLedges.m_pMarkers[markerIdx].m_worldPosition, m_levelLedges.m_pMarkers[markerIdx+1].m_worldPosition, m_levelLedges.m_pMarkers[markerIdx].m_facingDirection * side[currentSide], flags, ledgeObject.m_ledgeCornerEndAdjustAmount ); // Explanation: (Please do not delete this comment) // The item can be skipped if the angle is too big. // Since only the cosine of angles are compared, // bigger angles result in smaller values (hence the less_than comparison) const uint32 thresholdIdx = ((ledgeObject.m_ledgeFlags[currentSide] & (kLedgeFlag_useVault|kLedgeFlag_useHighVault)) != 0); CRY_ASSERT( thresholdIdx < 2 ); const float fCosMaxAngle = fCosMaxAngleTable[thresholdIdx]; const Vec3 vPosToLedge = _FindVectorToClosestPointOnLedge( referencePosition, ledgeInfo ); float distanceSq; if( IsBestLedge( vPosToLedge, testDirection, ledgeInfo, closestDistanceSq, fCosMaxAngle, enabled, distanceSq ) == false ) continue; bestLedgeId = LedgeId( objectIdx, (markerIdx - startMarkerIdx), currentSide ); closestDistanceSq = distanceSq; } currentSide++; } while ( currentSide < sideCount ); } return bestLedgeId; } }