// TODO: Migrate this into seperate class accessible to climbingMotor and HangingMotor /// <summary> /// See if the player can pass a climbing skill check /// </summary> /// <returns>true if player passed climbing skill check</returns> public bool ClimbingSkillCheck(int basePercentSuccess) { player.TallySkill(DFCareer.Skills.Climbing, 1); if (overrideSkillCheck) { return(true); } int percentSuccess = FormulaHelper.CalculateClimbingChance(player, basePercentSuccess); if (Dice100.FailedRoll(percentSuccess)) { // Don't allow skill check to break climbing while swimming // Water makes it easier to climb var playerPos = controller.transform.position.y + (76 * MeshReader.GlobalScale) - 0.95f; var playerFootPos = playerPos - (controller.height / 2) - 1.20f; // to prevent player from failing to climb out of water var waterPos = playerEnterExit.blockWaterLevel * -1 * MeshReader.GlobalScale; if (playerFootPos >= waterPos) // prevent fail underwater { return(false); } } return(true); }
private void ClimbMovement() { controller.Move(Vector3.up * Time.deltaTime); if (climbingContinueTimer <= (playerMotor.systemTimerUpdatesPerSecond * 15)) { climbingContinueTimer += Time.deltaTime; } else { climbingContinueTimer = 0; Entity.PlayerEntity player = GameManager.Instance.PlayerEntity; player.TallySkill(DFCareer.Skills.Climbing, 1); int skill = player.Skills.GetLiveSkillValue(DFCareer.Skills.Climbing); if (player.Race == Entity.Races.Khajiit) { skill += 30; } Mathf.Clamp(skill, 5, 95); if ((UnityEngine.Random.Range(1, 101) > 90) || (UnityEngine.Random.Range(1, 101) > skill)) { isClimbing = false; } } }
/// <summary> /// See if the player can pass a climbing skill check /// </summary> /// <returns>true if player passed climbing skill check</returns> private bool SkillCheck(int basePercentSuccess) { player.TallySkill(DFCareer.Skills.Climbing, 1); if (overrideSkillCheck) { return(true); } int skill = player.Skills.GetLiveSkillValue(DFCareer.Skills.Climbing); int luck = player.Stats.GetLiveStatValue(DFCareer.Stats.Luck); if (player.Race == Entity.Races.Khajiit) { skill += 30; } // Climbing effect states "target can climb twice as well" - doubling effective skill after racial applied if (player.IsEnhancedClimbing) { skill *= 2; } // Clamp skill range skill = Mathf.Clamp(skill, 5, 95); float luckFactor = Mathf.Lerp(0, 10, luck * 0.01f); // Skill Check float percentRolled = Mathf.Lerp(basePercentSuccess, 100, skill * .01f) + luckFactor; if (percentRolled < UnityEngine.Random.Range(1, 101)) // Failed Check? { // Don't allow skill check to break climbing while swimming // Water makes it easier to climb var playerPos = controller.transform.position.y + (76 * MeshReader.GlobalScale) - 0.95f; var playerFootPos = playerPos - (controller.height / 2) - 1.20f; // to prevent player from failing to climb out of water var waterPos = playerEnterExit.blockWaterLevel * -1 * MeshReader.GlobalScale; if (playerFootPos >= waterPos) // prevent fail underwater { return(false); } } return(true); }
public bool StealthCheck() { if (distanceToPlayer > 1024 * MeshReader.GlobalScale) { return(false); } uint gameMinutes = DaggerfallUnity.Instance.WorldTime.DaggerfallDateTime.ToClassicDaggerfallTime(); if (gameMinutes == timeOfLastStealthCheck) { return(detectedPlayer); } PlayerMotor playerMotor = GameManager.Instance.PlayerMotor; if (playerMotor.IsMovingLessThanHalfSpeed) { if ((gameMinutes & 1) == 1) { return(detectedPlayer); } } else if (hasEncounteredPlayer) { return(true); } Entity.PlayerEntity player = GameManager.Instance.PlayerEntity; if (player.TimeOfLastStealthCheck != gameMinutes) { player.TallySkill(DaggerfallConnect.DFCareer.Skills.Stealth, 1); player.TimeOfLastStealthCheck = gameMinutes; } timeOfLastStealthCheck = gameMinutes; int stealthRoll = 2 * ((int)(distanceToPlayer / MeshReader.GlobalScale) * player.Skills.GetLiveSkillValue(DaggerfallConnect.DFCareer.Skills.Stealth) >> 10); return(Random.Range(1, 101) > stealthRoll); }
/// <summary> /// See if the player can pass a climbing skill check /// </summary> /// <returns>true if player passed climbing skill check</returns> private bool SkillCheck(int basePercentSuccess) { player.TallySkill(DFCareer.Skills.Climbing, 1); int skill = player.Skills.GetLiveSkillValue(DFCareer.Skills.Climbing); if (player.Race == Entity.Races.Khajiit) { skill += 30; } // Climbing effect states "target can climb twice as well" - doubling effective skill after racial applied if (player.IsEnhancedClimbing) { skill *= 2; } // Clamp skill range skill = Mathf.Clamp(skill, 5, 95); // Skill Check float percentRolled = Mathf.Lerp(basePercentSuccess, 100, skill * .01f); if (percentRolled < UnityEngine.Random.Range(1, 101)) // Failed Check? { // Don't allow skill check to break climbing while swimming // This is another reason player can't climb out of water - any slip in climb will throw them back into swim mode // For now just pretend water is supporting player while they climb // It's not enough to check if they are swimming, need to check if their feet are above water. - MeteoricDragon var playerPos = controller.transform.position.y + (76 * MeshReader.GlobalScale) - 0.95f; var playerFootPos = playerPos - (controller.height / 2) - 1.20f; // to prevent player from failing to climb out of water var waterPos = playerEnterExit.blockWaterLevel * -1 * MeshReader.GlobalScale; if (playerFootPos >= waterPos) // prevent fail underwater { return(false); } } return(true); }
/// <summary> /// Check if should do rappel, and do rappel and attach to wall. /// </summary> public void RappelChecks() { if (rappelStage == RappelStage.Inactive) { measure = null; } else { // Player can become grounded with a partial rappel state based on object height // If player is grounded then reset back to inactive state if (GameManager.Instance.PlayerMotor.IsGrounded) { ResetRappelState(); return; } } InitialSetRappelType(); bool inputBackward = InputManager.Instance.HasAction(InputManager.Actions.MoveBackwards); Vector3 origin = Vector3.zero; Vector3 direction = -controller.transform.forward; #region Scan For AdjacentSurface if (inputBackward) { // check from different origins to find different surfaces if (!climbingMotor.IsClimbing) { origin = controller.transform.position + Vector3.down * (0.25f * controller.height) + controller.transform.forward * (0.8f * controller.radius); } else { origin = controller.transform.position + Vector3.up * (0.25f * controller.height) + controller.transform.forward * (0.8f * controller.radius); } playerScanner.FindAdjacentSurface(origin, direction, PlayerMoveScanner.RotationDirection.YZCounterClockwise); } #endregion // the only time Ground closeness can cancel the start of the rappel is when we are // going to rappel down and behind to a wall if (InitialTooCloseToGround(rappelDirection)) { IsRappelling = false; return; } if (rappelStage == RappelStage.Activated) { DaggerfallUI.AddHUDText(UserInterfaceWindows.HardStrings.rappelMode); rappelStage = RappelStage.Swooping; InitialSetGrappleDirection(); swoopBasePosition = controller.transform.position; rappelTimer = 0f; measure = null; } // Rappel swooping if (rappelStage == RappelStage.Swooping) { player.TallySkill(DFCareer.Skills.Climbing, 1); Vector3 swoopDirection = grappleDirection; // if we are rappelling under to ceiling, grappledirection is different so use adjacentSurfaceRay // direction to get right direction to go under the ceiling. if (rappelDirection == RappelDirection.DownUnder || rappelDirection == RappelDirection.FrontUp) { swoopDirection = playerScanner.WallDetachedVector; } rappelTimer += Time.deltaTime; switch (rappelDirection) { case RappelDirection.DownBehind: CurlDown(swoopBasePosition, swoopDirection); break; case RappelDirection.UpBehind: CurlOver(swoopBasePosition, swoopDirection); break; //case RappelDirection.DownUnder: // CurlUnder(swoopBasePosition, swoopDirection); // break; case RappelDirection.FrontUp: if (updateSwoopBasePosition) { // enables player to bottom out on DownUnder and continue FrontUp swoopBasePosition = controller.transform.position; updateSwoopBasePosition = false; rappelTimer = 0; } CurlUpHalf(swoopBasePosition, swoopDirection); break; default: break; } controller.transform.position = rappelPosition; } if (rappelStage == RappelStage.Grappling) // perform horizontal measurement-based Wall-grapple direction or vertical for ceiling { // if measurement hasn't started, start measuring grapple-to-surface movement if (measure == null) { measure = new VectorMeasurement(controller.transform.position); } if (!(/*hangingMotor.IsHanging ||*/ climbingMotor.IsClimbing) && measure.Distance(controller.transform.position) < 1f) { // Auto move toward surface to grab float speed = speedChanger.GetBaseSpeed(); grappleDirection = grappleDirection.normalized * speed * 1.15f; groundMotor.MoveWithMovingPlatform(grappleDirection); } else // if we've moved past the distance limit { ResetRappelState(); } } }
public void ClimbingCheck(ref CollisionFlags collisionFlags) { // Get pre-movement position for climbing check lastHorizontalPosition = new Vector2(controller.transform.position.x, controller.transform.position.z); if (isClimbing) { collisionFlags = CollisionFlags.Sides; } // Get collision flags for swimming as well, so it's possible to climb out of water TODO: Collision flags from swimming aren't working else if (levitateMotor.IsSwimming) { collisionFlags = levitateMotor.CollisionFlags; } // Climbing uint gameMinutes = DaggerfallUnity.Instance.WorldTime.DaggerfallDateTime.ToClassicDaggerfallTime(); if (!InputManager.Instance.HasAction(InputManager.Actions.MoveForwards) || (collisionFlags & CollisionFlags.Sides) == 0 || failedClimbingCheck || levitateMotor.IsLevitating || playerMotor.IsRiding || Vector2.Distance(lastHorizontalPosition, new Vector2(controller.transform.position.x, controller.transform.position.z)) >= (0.003f)) // Approximation based on observing classic in-game { isClimbing = false; showClimbingModeMessage = true; climbingStartTimer = 0; timeOfLastClimbingCheck = gameMinutes; } else { if (climbingStartTimer <= (playerMotor.systemTimerUpdatesPerSecond * 14)) { climbingStartTimer += Time.deltaTime; } else { if (!isClimbing) { if (showClimbingModeMessage) { DaggerfallUI.AddHUDText(UserInterfaceWindows.HardStrings.climbingMode); } // Disable further showing of climbing mode message until current climb attempt is stopped // to keep it from filling message log showClimbingModeMessage = false; isClimbing = true; } // Initial check to start climbing if ((gameMinutes - timeOfLastClimbingCheck) > 18) { Entity.PlayerEntity player = GameManager.Instance.PlayerEntity; player.TallySkill(DFCareer.Skills.Climbing, 1); timeOfLastClimbingCheck = gameMinutes; if (UnityEngine.Random.Range(1, 101) > 95) { if (UnityEngine.Random.Range(1, 101) > player.Skills.GetLiveSkillValue(DFCareer.Skills.Climbing)) { isClimbing = false; failedClimbingCheck = true; } } } } } if (isClimbing) { ClimbMovement(); } }
void FixedUpdate() { // Clear movement if (cancelMovement) { moveDirection = Vector3.zero; cancelMovement = false; ClearActivePlatform(); ClearFallingDamage(); return; } // Handle freeze movement if (freezeMotor > 0) { freezeMotor -= Time.deltaTime; if (freezeMotor <= 0) { freezeMotor = 0; CancelMovement = true; } return; } if (isClimbing) { collisionFlags = CollisionFlags.Sides; } // Get collision flags for swimming as well, so it's possible to climb out of water TODO: Collision flags from swimming aren't working else if (fakeLevitate.IsSwimming) { collisionFlags = fakeLevitate.CollisionFlags; } // Climbing uint gameMinutes = DaggerfallUnity.Instance.WorldTime.DaggerfallDateTime.ToClassicDaggerfallTime(); if (!InputManager.Instance.HasAction(InputManager.Actions.MoveForwards) || (collisionFlags & CollisionFlags.Sides) == 0 || failedClimbingCheck || fakeLevitate.IsLevitating || isRiding || Vector2.Distance(lastHorizontalPosition, new Vector2(controller.transform.position.x, controller.transform.position.z)) >= (0.003f)) // Approximation based on observing classic in-game { isClimbing = false; showClimbingModeMessage = true; climbingStartTimer = 0; timeOfLastClimbingCheck = gameMinutes; } else { if (climbingStartTimer <= (systemTimerUpdatesPerSecond * 14)) { climbingStartTimer += Time.deltaTime; } else { if (!isClimbing) { if (showClimbingModeMessage) { DaggerfallUI.AddHUDText(UserInterfaceWindows.HardStrings.climbingMode); } // Disable further showing of climbing mode message until current climb attempt is stopped // to keep it from filling message log showClimbingModeMessage = false; isClimbing = true; } // Initial check to start climbing if ((gameMinutes - timeOfLastClimbingCheck) > 18) { Entity.PlayerEntity player = GameManager.Instance.PlayerEntity; player.TallySkill(DFCareer.Skills.Climbing, 1); timeOfLastClimbingCheck = gameMinutes; if (UnityEngine.Random.Range(1, 101) > 95) { if (UnityEngine.Random.Range(1, 101) > player.Skills.GetLiveSkillValue(DFCareer.Skills.Climbing)) { isClimbing = false; failedClimbingCheck = true; } } } } } if (isClimbing) { falling = false; ClimbMovement(); } // Do nothing if player fake levitating/swimming or climbing - replacement motor will take over movement for levitating/swimming if (fakeLevitate && (fakeLevitate.IsLevitating || fakeLevitate.IsSwimming) || isClimbing) { return; } //float inputX = Input.GetAxis("Horizontal"); //float inputY = Input.GetAxis("Vertical"); float inputX = InputManager.Instance.Horizontal; float inputY = InputManager.Instance.Vertical; // If both horizontal and vertical are used simultaneously, limit speed (if allowed), so the total doesn't exceed normal move speed float inputModifyFactor = (inputX != 0.0f && inputY != 0.0f && limitDiagonalSpeed) ? .7071f : 1.0f; // Player assumed to be in movement for now standingStill = false; if (grounded) { // Set standing still while grounded flag // Casting moveDirection to a Vector2 so constant downward force of gravity not included in magnitude standingStill = (new Vector2(moveDirection.x, moveDirection.z).magnitude == 0); if (jumping) { jumping = false; } bool sliding = false; // See if surface immediately below should be slid down. We use this normally rather than a ControllerColliderHit point, // because that interferes with step climbing amongst other annoyances if (Physics.Raycast(myTransform.position, -Vector3.up, out hit, rayDistance)) { if (Vector3.Angle(hit.normal, Vector3.up) > slideLimit) { sliding = true; } } // However, just raycasting straight down from the center can fail when on steep slopes // So if the above raycast didn't catch anything, raycast down from the stored ControllerColliderHit point instead else { Physics.Raycast(contactPoint + Vector3.up, -Vector3.up, out hit); if (Vector3.Angle(hit.normal, Vector3.up) > slideLimit) { sliding = true; } } // If we were falling, and we fell a vertical distance greater than the threshold, run a falling damage routine if (falling) { falling = false; float fallDistance = fallStartLevel - myTransform.position.y; if (fallDistance > fallingDamageThreshold) { FallingDamageAlert(fallDistance); } else if (fallDistance > fallingDamageThreshold / 2f) { BadFallDetected(fallDistance); } //if (myTransform.position.y < fallStartLevel - fallingDamageThreshold) // FallingDamageAlert(fallDistance); } // Get walking/crouching/riding speed speed = GetBaseSpeed(); if (!riding) { if (!isCrouching) { controller.height = standingHeight; } try { // If running isn't on a toggle, then use the appropriate speed depending on whether the run button is down if (!toggleRun && InputManager.Instance.HasAction(InputManager.Actions.Run)) { speed = GetRunSpeed(speed); } } catch { speed = GetRunSpeed(speed); } } // Handle sneak key. Reduces movement speed to half, then subtracts 1 in classic speed units if (InputManager.Instance.HasAction(InputManager.Actions.Sneak)) { speed /= 2; speed -= (1 / classicToUnitySpeedUnitRatio); } // If sliding (and it's allowed), or if we're on an object tagged "Slide", get a vector pointing down the slope we're on if ((sliding && slideWhenOverSlopeLimit) || (slideOnTaggedObjects && hit.collider.tag == "Slide")) { Vector3 hitNormal = hit.normal; moveDirection = new Vector3(hitNormal.x, -hitNormal.y, hitNormal.z); Vector3.OrthoNormalize(ref hitNormal, ref moveDirection); moveDirection *= slideSpeed; playerControl = false; } // Otherwise recalculate moveDirection directly from axes, adding a bit of -y to avoid bumping down inclines else { moveDirection = new Vector3(inputX * inputModifyFactor, -antiBumpFactor, inputY * inputModifyFactor); moveDirection = myTransform.TransformDirection(moveDirection) * speed; playerControl = true; } try { // Jump! But only if the jump button has been released and player has been grounded for a given number of frames if (!InputManager.Instance.HasAction(InputManager.Actions.Jump)) { jumpTimer++; } //if (!Input.GetButton("Jump")) // jumpTimer++; else if (jumpTimer >= antiBunnyHopFactor) { moveDirection.y = jumpSpeed; jumpTimer = 0; jumping = true; // Modify crouching jump speed if (isCrouching) { moveDirection.y *= crouchingJumpDelta; } } else { jumping = false; } } catch { } } else { // If we stepped over a cliff or something, set the height at which we started falling if (!falling) { falling = true; fallStartLevel = myTransform.position.y; } // If air control is allowed, check movement but don't touch the y component if (airControl && playerControl) { moveDirection.x = inputX * speed * inputModifyFactor; moveDirection.z = inputY * speed * inputModifyFactor; moveDirection = myTransform.TransformDirection(moveDirection); } } // Apply gravity moveDirection.y -= gravity * Time.deltaTime; // If we hit something above us AND we are moving up, reverse vertical movement if ((controller.collisionFlags & CollisionFlags.Above) != 0) { if (moveDirection.y > 0) { moveDirection.y = -moveDirection.y; } } // Moving platform support if (activePlatform != null) { var newGlobalPlatformPoint = activePlatform.TransformPoint(activeLocalPlatformPoint); var moveDistance = (newGlobalPlatformPoint - activeGlobalPlatformPoint); if (moveDistance != Vector3.zero) { controller.Move(moveDistance); } //lastPlatformVelocity = (newGlobalPlatformPoint - activeGlobalPlatformPoint) / Time.deltaTime; // If you want to support moving platform rotation as well: var newGlobalPlatformRotation = activePlatform.rotation * activeLocalPlatformRotation; var rotationDiff = newGlobalPlatformRotation * Quaternion.Inverse(activeGlobalPlatformRotation); // Prevent rotation of the local up vector rotationDiff = Quaternion.FromToRotation(rotationDiff * transform.up, transform.up) * rotationDiff; transform.rotation = rotationDiff * transform.rotation; } //else //{ // lastPlatformVelocity = Vector3.zero; //} activePlatform = null; // Move the controller, and set grounded true or false depending on whether we're standing on something collisionFlags = controller.Move(moveDirection * Time.deltaTime); // Get pre-movement position for climbing check lastHorizontalPosition = new Vector2(controller.transform.position.x, controller.transform.position.z); grounded = (collisionFlags & CollisionFlags.Below) != 0; // Moving platforms support if (activePlatform != null) { activeGlobalPlatformPoint = transform.position; activeLocalPlatformPoint = activePlatform.InverseTransformPoint(transform.position); // If you want to support moving platform rotation as well: activeGlobalPlatformRotation = transform.rotation; activeLocalPlatformRotation = Quaternion.Inverse(activePlatform.rotation) * transform.rotation; } }