private void StaggerAttacker(Character self, Animator m_animator, Character _dealerChar) { String m_nameLocKey = (String)At.GetValue(typeof(Character), self, "m_nameLocKey"); String m_name = (String)At.GetValue(typeof(Character), self, "m_name"); // Debug.Log(self.Name + " blocked the attack. Shield stability: " + m_shieldStability); At.SetValue(Character.HurtType.NONE, typeof(Character), self, "m_hurtType"); if (self.InLocomotion) { m_animator.SetTrigger("BlockHit"); } if ((bool)CombatOverhaul.config.GetValue(Settings.Blocking_Staggers_Attacker)) { // Debug.Log("autoknocking " + _dealerChar.Name); if (_dealerChar.CurrentWeapon.Type != Weapon.WeaponType.Bow) { bool ShouldBounce = true; if (!(bool)CombatOverhaul.config.GetValue(Settings.BossShieldBounce)) { ShouldBounce = (int)EnemyClass.getEnemyLevel(_dealerChar) < (int)EnemyLevel.MINIBOSS; } if ((bool)CombatOverhaul.config.GetValue(Settings.OneHBounceOnly)) { if (_dealerChar.CurrentWeapon.TwoHanded && EnemyClass.getEnemyLevel(_dealerChar) != EnemyLevel.WEAKLING) { ShouldBounce = false; //2h weapons should not bounce off shields } } if (ShouldBounce) { _dealerChar.AutoKnock(false, new Vector3(0, 0, 0)); } } } }
public static bool Prefix(Character __instance, float _knockValue, float _angle, bool _block, Character _dealerChar) { var self = __instance; var _base = self as Photon.MonoBehaviour; if (At.GetValue(typeof(Character), self, "m_impactImmune") is bool m_impactImmune && At.GetValue(typeof(Character), self, "m_shieldStability") is float m_shieldStability && At.GetValue(typeof(Character), self, "m_stability") is float m_stability && At.GetValue(typeof(Character), self, "m_knockbackCount") is float m_knockbackCount && At.GetValue(typeof(Character), self, "m_knockHurtAllowed") is bool m_knockHurtAllowed && At.GetValue(typeof(Character), self, "m_currentlyChargingAttack") is bool m_currentlyChargingAttack && At.GetValue(typeof(Character), self, "m_animator") is Animator m_animator) { String m_nameLocKey = (String)At.GetValue(typeof(Character), self, "m_nameLocKey"); String m_name = (String)At.GetValue(typeof(Character), self, "m_name"); // Begin actual stability hit function var hit = _knockValue; if (hit < 0) { hit = 0; } if (!m_impactImmune && hit > 0f) { //Debug.Log("--------- " + self.Name + " ---------"); // check stagger immunity dictionary (custom) float lastStagger = -1; if (Instance.LastStaggerTimes.ContainsKey(self.UID)) { lastStagger = Instance.LastStaggerTimes[self.UID]; } // if you run out of stamina and get hit, you will always get staggered. (unchanged, except to reflect custom stagger threshold) if (self.Stats.CurrentStamina < 1f) { float hitToStagger = m_shieldStability + m_stability - (100 - (float)CombatOverhaul.config.GetValue(Settings.Stagger_Threshold)); if (hit < hitToStagger) { hit = hitToStagger; } //Debug.LogError("Stamina autostagger called! hitToStagger: " + hitToStagger + ", hit: " + hit); } At.SetValue(Time.time, typeof(Character), self, "m_timeOfLastStabilityHit"); // Debug.Log("Set " + Time.time + " as character's last stability hit"); if (self.CharacterCamera != null && hit > 0f) { self.CharacterCamera.Hit(hit * 6f); } // check shield stability if blocking (unchanged) if (_block && m_shieldStability > 0f) { if (hit > m_shieldStability) { var num2 = m_stability - (hit - m_shieldStability); At.SetValue(num2, typeof(Character), self, "m_stability"); m_stability = num2; } var num3 = Mathf.Clamp(m_shieldStability - hit, 0f, 50f); At.SetValue(num3, typeof(Character), self, "m_shieldStability"); m_shieldStability = num3; } // check non-blocking stability (unchanged) else { var num2 = Mathf.Clamp(m_stability - hit, 0f, 100f); At.SetValue(num2, typeof(Character), self, "m_stability"); m_stability = num2; } // if hit takes us below knockdown threshold, or if AI auto-knockdown stagger count was reached... float knockdownThreshold = (float)CombatOverhaul.config.GetValue(Settings.Knockdown_Threshold); bool playerHasPoiseBoost = ((bool)CombatOverhaul.config.GetValue(Settings.PlayerPoiseBoost) && EnemyClass.isPlayer(self)); if ((bool)CombatOverhaul.config.GetValue(Settings.BossPoise)) { if ((int)EnemyClass.getEnemyLevel(self) >= (int)EnemyLevel.MINIBOSS || playerHasPoiseBoost) { knockdownThreshold = -100f; //Bosses MUST be staggered. They can't be knocked down so easily. } } float staggerThreshold = (float)CombatOverhaul.config.GetValue(Settings.Stagger_Threshold); //TODO: Boss stagger thresholds if ((bool)CombatOverhaul.config.GetValue(Settings.BossPoise)) { //Debug.Log("Enemy level: " + EnemyClass.getCleanName(self) + " " + EnemyClass.getEnemyLevel(self)); //TODO: Test if this is really necessary. Maybe bosses already get good poise. if (EnemyClass.getEnemyLevel(self) == EnemyLevel.BOSS) { staggerThreshold = staggerThreshold / (float)CombatOverhaul.config.GetValue(Settings.BossStaggerMultiplier); } if (EnemyClass.getEnemyLevel(self) == EnemyLevel.MINIBOSS || playerHasPoiseBoost) { staggerThreshold = staggerThreshold / (float)CombatOverhaul.config.GetValue(Settings.MinibossStaggerMultiplier); } } if (m_stability <= knockdownThreshold || (self.IsAI && m_knockbackCount >= (float)CombatOverhaul.config.GetValue(Settings.Enemy_AutoKD_Count))) { //Debug.LogError("Knockdown! Hit Value: " + _knockValue + ", current stability: " + m_stability); if ((!self.IsAI && _base.photonView.isMine) || (self.IsAI && (_dealerChar == null || _dealerChar.photonView.isMine))) { _base.photonView.RPC("SendKnock", PhotonTargets.All, new object[] { true, m_stability }); } else { At.Call(typeof(Character), self, "Knock", null, true); } At.SetValue(0f, typeof(Character), self, "m_stability"); m_stability = 0f; if (self.IsPhotonPlayerLocal) { self.BlockInput(false); } } // else if hit is a stagger... else if (m_stability <= staggerThreshold && (Time.time - lastStagger > (float)CombatOverhaul.config.GetValue(Settings.Stagger_Immunity_Period))) { // Debug.LogWarning("Stagger! Hit Value: " + _knockValue + ", current stability: " + m_stability); // update Stagger Immunity dictionary if (!Instance.LastStaggerTimes.ContainsKey(self.UID)) { Instance.LastStaggerTimes.Add(self.UID, Time.time); } else { Instance.LastStaggerTimes[self.UID] = Time.time; } if ((!self.IsAI && _base.photonView.isMine) || (self.IsAI && (_dealerChar == null || _dealerChar.photonView.isMine))) { if ((bool)CombatOverhaul.config.GetValue(Settings.Poise)) { m_stability = 100f; At.SetValue(100f, typeof(Character), self, "m_stability"); } _base.photonView.RPC("SendKnock", PhotonTargets.All, new object[] { false, m_stability }); } else { At.Call(typeof(Character), self, "Knock", null, false); } if (self.IsPhotonPlayerLocal && _block) { self.BlockInput(false); } //At.SetValue(100f, typeof(Character), self, "m_stability"); } // else if we are not blocking... else if (!_block) { // Debug.Log("Value: " + _knockValue + ", new stability: " + m_stability); if (m_knockHurtAllowed) { At.SetValue(Character.HurtType.Hurt, typeof(Character), self, "m_hurtType"); if (m_currentlyChargingAttack) { self.CancelCharging(); } m_animator.SetTrigger("Knockhurt"); _base.StopCoroutine("KnockhurtRoutine"); MethodInfo _knockhurtRoutine = self.GetType().GetMethod("KnockhurtRoutine", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); IEnumerator _knockEnum = (IEnumerator)_knockhurtRoutine.Invoke(self, new object[] { hit }); _base.StartCoroutine(_knockEnum); } if (m_stability <= (float)CombatOverhaul.config.GetValue(Settings.Stagger_Immunity_Period)) { // Debug.LogError(self.Name + " would have staggered. Current delta: " + (Time.time - lastStagger)); } } else // hit was blocked and no stagger { Instance.StaggerAttacker(self, m_animator, _dealerChar); } m_animator.SetInteger("KnockAngle", (int)_angle); self.StabilityHitCall?.Invoke(); } else if (!m_impactImmune && _block) // hit dealt 0 impact and was blocked { Instance.StaggerAttacker(self, m_animator, _dealerChar); } } return(false); }
public static bool Prefix(Character __instance) { var self = __instance; if (At.GetValue(typeof(Character), self, "m_stability") is float m_stability && At.GetValue(typeof(Character), self, "m_timeOfLastStabilityHit") is float m_timeOfLastStabilityHit && At.GetValue(typeof(Character), self, "m_shieldStability") is float m_shieldStability && At.GetValue(typeof(Character), self, "m_knockbackCount") is float m_knockbackCount) { String m_nameLocKey = (String)At.GetValue(typeof(Character), self, "m_nameLocKey"); String m_name = (String)At.GetValue(typeof(Character), self, "m_name"); // ----------- original method, unchanged other than to reflect custom values ------------- if ((bool)CombatOverhaul.config.GetValue(Settings.No_Stability_Regen_When_Blocking) && self.Blocking) // no stability regen while blocking! otherwise too op { return(false); } float num = Time.time - m_timeOfLastStabilityHit; if (num > (float)CombatOverhaul.config.GetValue(Settings.Stability_Regen_Delay)) { if (m_stability < 100f && !(bool)CombatOverhaul.config.GetValue(Settings.Poise)) { var num2 = Mathf.Clamp(m_stability + (self.StabilityRegen * (float)CombatOverhaul.config.GetValue(Settings.Stability_Regen_Speed)) * Time.deltaTime, 0f, 100f); At.SetValue(num2, typeof(Character), self, "m_stability"); } else if (m_shieldStability < 50f) { var num2 = Mathf.Clamp(m_shieldStability + self.StabilityRegen * Time.deltaTime, 0f, 50f); At.SetValue(num2, typeof(Character), self, "m_shieldStability"); } if (num > (float)CombatOverhaul.config.GetValue(Settings.Enemy_AutoKD_Reset_Time)) { bool flag = m_knockbackCount > 0; var num2 = Mathf.Clamp(m_knockbackCount - Time.deltaTime, 0f, 4f); if ((bool)CombatOverhaul.config.GetValue(Settings.BossPoise)) { if ((int)EnemyClass.getEnemyLevel(self) < (int)EnemyLevel.MINIBOSS) { At.SetValue(num2, typeof(Character), self, "m_knockbackCount"); } } else { At.SetValue(num2, typeof(Character), self, "m_knockbackCount"); } if (flag && num2 <= 0) { // Debug.Log("Resetting AI stagger count for " + self.Name); } } } if ((bool)CombatOverhaul.config.GetValue(Settings.Poise)) { if (num > (float)CombatOverhaul.config.GetValue(Settings.PoiseResetTime)) { bool resetStability = false; if ((bool)CombatOverhaul.config.GetValue(Settings.BossPoise)) { //Minibosses do NOT regenerate stamina. if ((int)EnemyClass.getEnemyLevel(self) < (int)EnemyLevel.MINIBOSS) { resetStability = true; } } else { resetStability = true; } //Initially for readability, allowing display of stability hurt on a stagger actually meant (even badly) coordinated strikes knocked down too much. if (resetStability /*&& num > 0.25*/) { At.SetValue(100f, typeof(Character), self, "m_stability"); } } } } return(false); }