예제 #1
0
            public static bool Prefix(Character __instance, Vector3 _direction)
            {
                var self = __instance;

                // only use this hook for local players. return orig everything else
                if (self.IsAI || !self.IsPhotonPlayerLocal)
                {
                    return(true);
                }

                float staminaCost = (float)CombatOverhaul.config.GetValue(Settings.Custom_Dodge_Cost);

                // if dodge cancelling is NOT enabled, just do a normal dodge check.
                if (!(bool)CombatOverhaul.config.GetValue(Settings.Dodge_Cancelling))
                {
                    if (At.GetField(self, "m_currentlyChargingAttack") is bool m_currentlyChargingAttack &&
                        At.GetField(self, "m_preparingToSleep") is bool m_preparingToSleep &&
                        At.GetField(self, "m_nextIsLocomotion") is bool m_nextIsLocomotion &&
                        At.GetField(self, "m_dodgeAllowedInAction") is int m_dodgeAllowedInAction)
                    {
                        if (self.Stats.MovementSpeed > 0f &&
                            !m_preparingToSleep &&
                            (!self.LocomotionAction || m_currentlyChargingAttack) &&
                            (m_nextIsLocomotion || m_dodgeAllowedInAction > 0))
                        {
                            if (!self.Dodging)
                            {
                                Instance.SendDodge(self, staminaCost, _direction);
                            }
                            return(false);
                        }
                    }
                }
                else // cancelling enabled. check if we should allow the dodge
                {
                    if (Instance.PlayerLastHitTimes.ContainsKey(self.UID) &&
                        Time.time - Instance.PlayerLastHitTimes[self.UID] < (float)CombatOverhaul.config.GetValue(Settings.Dodge_DelayAfterHit))
                    {
                        //  Debug.Log("Player has hit within the last few seconds. Dodge not allowed!");
                        return(false);
                    }

                    Character.HurtType hurtType = (Character.HurtType)At.GetField(self, "m_hurtType");

                    // manual fix (game sometimes does not reset HurtType to NONE when animation ends.
                    float timeout = (float)CombatOverhaul.config.GetValue(Settings.Dodge_DelayAfterStagger);
                    if (hurtType == Character.HurtType.Knockdown)
                    {
                        timeout = (float)CombatOverhaul.config.GetValue(Settings.Dodge_DelayAfterKD);
                    }

                    if ((float)At.GetField(self, "m_timeOfLastStabilityHit") is float lasthit && Time.time - lasthit > timeout)
                    {
                        hurtType = Character.HurtType.NONE;
                        At.SetField(self, "m_hurtType", hurtType);
                    }

                    // if we're not currently dodging or staggered, force an animation cancel dodge (provided we have enough stamina).
                    if (!self.Dodging && hurtType == Character.HurtType.NONE)
                    {
                        Instance.SendDodge(self, staminaCost, _direction);
                    }

                    // send a fix to force m_dodging to false after a short delay.
                    // this is a fix for if the player dodges while airborne, the game wont reset their m_dodging to true when they land.
                    Instance.StartCoroutine(Instance.DodgeLateFix(self));
                }

                return(false);
            }
예제 #2
0
        // actual function to set an enemy's stats
        private void SetEnemyMods(ModConfig _config, CharacterStats _stats, Character m_character)
        {
            if (m_character == null || !m_character.IsAI || m_character.Faction == Character.Factions.Player)
            {
                //Debug.Log("trying to set stats for a null character, or a non-AI character");
                return;
            }

            if (FixedEnemies.Contains(m_character.UID))
            {
                // Debug.Log("Fixed enemies already contains " + m_character.Name);
                return;
            }

            var m_staminaUseModiifers = new Stat(1f);

            m_staminaUseModiifers.AddMultiplierStack(new StatStack("MyStat", -0.9f));

            if ((bool)_config.GetValue(Settings.Enemy_Balancing))
            {
                string stackSource = "CombatOverhaul";

                if (!PhotonNetwork.isNonMasterClientInRoom)
                {
                    // set health modifier
                    var healthTag   = TagSourceManager.Instance.GetTag("77"); // 77 = max health
                    var healthStack = new StatStack(stackSource, (float)_config.GetValue(Settings.Enemy_Health) - 1);
                    _stats.RemoveStatStack(healthTag, stackSource, true);
                    _stats.AddStatStack(healthTag, healthStack, true);
                    At.SetValue(_stats.CurrentHealth * (float)_config.GetValue(Settings.Enemy_Health), typeof(CharacterStats), _stats, "m_health");
                }

                // set impact resistance
                var impactTag = TagSourceManager.Instance.GetTag("84"); // 84 = impact res
                _stats.RemoveStatStack(impactTag, stackSource, false);
                var impactStack = new StatStack(stackSource, (float)_config.GetValue(Settings.Enemy_ImpactRes));
                _stats.AddStatStack(impactTag, impactStack, false);

                // damage bonus
                var damageTag = TagSourceManager.Instance.GetTag("96"); // 96 = all damage bonus
                _stats.RemoveStatStack(damageTag, stackSource, true);
                var damageStack = new StatStack(stackSource, (float)_config.GetValue(Settings.Enemy_Damages) * 0.01f);
                _stats.AddStatStack(damageTag, damageStack, true);

                // impact modifier
                var impactModifier = At.GetValue(typeof(CharacterStats), _stats, "m_impactModifier") as Stat;
                impactModifier.RemoveStack(stackSource, true);
                impactModifier.AddStack(new StatStack(stackSource, (float)_config.GetValue(Settings.Enemy_ImpactDmg) * 0.01f), true);

                for (int i = 0; i < 6; i++)
                {
                    // damage resistance (Capped at 99, unless already 100)
                    float currentRes = m_character.Stats.GetDamageResistance((DamageType.Types)i);
                    if (currentRes < 100)
                    {
                        var valueToSet = (float)_config.GetValue(Settings.Enemy_Resistances);

                        if (currentRes + valueToSet >= 99)
                        {
                            valueToSet = 99 - currentRes;
                        }

                        int tag          = 113 + i; // 113 to 118 = damage resistance stats
                        var damageResTag = TagSourceManager.Instance.GetTag(tag.ToString());
                        _stats.RemoveStatStack(damageResTag, stackSource, true);
                        var resStack = new StatStack(stackSource, valueToSet);
                        _stats.AddStatStack(damageResTag, resStack, false);
                    }
                }
            }

            if ((bool)_config.GetValue(Settings.All_Enemies_Allied))
            {
                m_character.ChangeFaction(Character.Factions.Bandits);
                m_character.TargetingSystem.AlliedToSameFaction = true;

                Character.Factions[] targets = new Character.Factions[] { Character.Factions.Player };
                At.SetValue(targets, typeof(TargetingSystem), m_character.TargetingSystem, "TargetableFactions");

                // fix skills
                foreach (var uid in m_character.Inventory.SkillKnowledge.GetLearnedActiveSkillUIDs())
                {
                    if (ItemManager.Instance.GetItem(uid) is Skill skill)
                    {
                        foreach (Shooter shooter in skill.GetComponentsInChildren <Shooter>())
                        {
                            shooter.Setup(targets, shooter.transform.parent);
                        }
                    }
                }
            }

            FixedEnemies.Add(m_character.UID);
        }
예제 #3
0
        // called from RPC manager
        public void SetSyncInfo(bool modsEnabled, bool enemiesAllied, bool customStats, float healthModifier, float damageModifier, float impactRes, float damageRes, float impactDmg)
        {
            m_currentHostUID = CharacterManager.Instance.GetWorldHostCharacter()?.UID;
            //Debug.Log("Received sync from host uid: " + m_currentHostUID);

            this.m_currentSyncInfos = new ModConfig
            {
                ModName         = "CombatOverhaul_Sync",
                SettingsVersion = 1.0,
                Settings        = new List <BBSetting>
                {
                    new BoolSetting
                    {
                        Name         = Settings.All_Enemies_Allied,
                        m_value      = enemiesAllied,
                        DefaultValue = false,
                    },
                    new BoolSetting
                    {
                        Name    = Settings.Enemy_Balancing,
                        m_value = customStats
                    },
                    new FloatSetting
                    {
                        Name    = Settings.Enemy_Health,
                        m_value = healthModifier
                    },
                    new FloatSetting
                    {
                        Name    = Settings.Enemy_Damages,
                        m_value = damageModifier
                    },
                    new FloatSetting
                    {
                        Name    = Settings.Enemy_Resistances,
                        m_value = damageRes
                    },
                    new FloatSetting
                    {
                        Name    = Settings.Enemy_ImpactRes,
                        m_value = impactRes
                    },
                    new FloatSetting
                    {
                        Name    = Settings.Enemy_ImpactDmg,
                        m_value = impactDmg
                    },
                }
            };

            // manually fix the settings dictionary since we are not using ModConfig.Register()
            var dict = new Dictionary <string, BBSetting>();

            foreach (var setting in m_currentSyncInfos.Settings)
            {
                dict.Add(setting.Name, setting);
            }
            At.SetValue(dict, typeof(ModConfig), m_currentSyncInfos, "m_Settings");

            if (modsEnabled)
            {
                //Debug.Log("Updating all current characters");
                foreach (Character c in CharacterManager.Instance.Characters.Values.Where(x => x.IsAI))
                {
                    SetEnemyMods(m_currentSyncInfos, c.Stats, c);
                }
            }
        }
            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)
                {
                    // 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...
                        if (m_stability <= (float)CombatOverhaul.config.GetValue(Settings.Knockdown_Threshold) ||
                            (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(self, "Knock", new object[]
                                {
                                    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 <= (float)CombatOverhaul.config.GetValue(Settings.Stagger_Threshold) && (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)))
                            {
                                _base.photonView.RPC("SendKnock", PhotonTargets.All, new object[]
                                {
                                    false,
                                    m_stability
                                });
                            }
                            else
                            {
                                At.Call(self, "Knock", new object[]
                                {
                                    false
                                });
                            }
                            if (self.IsPhotonPlayerLocal && _block)
                            {
                                self.BlockInput(false);
                            }
                        }
                        // 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);
            }
예제 #5
0
            public static void Postfix(Character __instance, Vector3 _direction, bool ___m_pendingDeath, ref int ___m_dodgeAllowedInAction)
            {
                if (!CombatTweaksMod.Dodge_Cancelling.Value)
                {
                    return;
                }

                if (!__instance.IsPhotonPlayerLocal || __instance.IsAI || __instance.Dodging)
                {
                    return;
                }

                if (___m_pendingDeath)
                {
                    return;
                }

                // check player has enough stamina
                if (!(bool)At.Invoke(__instance, "HasEnoughStamina", (float)__instance.DodgeStamCost))
                {
                    return;
                }

                if (PlayerLastHitTimes.ContainsKey(__instance.UID) &&
                    Time.time - PlayerLastHitTimes[__instance.UID] < CombatTweaksMod.Dodge_DelayAfterPlayerHits.Value)
                {
                    //  Debug.Log("Player has hit within the last few seconds. Dodge not allowed!");
                    return;
                }

                Character.HurtType hurtType = (Character.HurtType)At.GetField(__instance, "m_hurtType");

                // manual fix (game sometimes does not reset HurtType to NONE when animation ends.
                float timeout;

                if (hurtType == Character.HurtType.Knockdown)
                {
                    timeout = CombatTweaksMod.Dodge_DelayAfterKnockdown.Value;
                }
                else
                {
                    timeout = CombatTweaksMod.Dodge_DelayAfterStagger.Value;
                }

                if ((float)At.GetField(__instance, "m_timeOfLastStabilityHit") is float lasthit &&
                    Time.time - lasthit > timeout)
                {
                    hurtType = Character.HurtType.NONE;
                    At.SetField(__instance, "m_hurtType", hurtType);
                }

                // if we're not currently staggered, force an animation cancel dodge (provided we have enough stamina).
                if (hurtType == Character.HurtType.NONE)
                {
                    //SendDodge(__instance, __instance.DodgeStamCost, _direction);

                    __instance.Stats.UseStamina(TagSourceManager.Dodge, __instance.DodgeStamCost);

                    ___m_dodgeAllowedInAction = 0;

                    if (__instance.CharacterCamera && __instance.CharacterCamera.InZoomMode)
                    {
                        __instance.SetZoomMode(false);
                    }

                    __instance.ForceCancel(false, true);
                    __instance.ResetCastType();

                    __instance.photonView.RPC("SendDodgeTriggerTrivial", PhotonTargets.All, new object[]
                    {
                        _direction
                    });

                    At.Invoke(__instance, "ActionPerformed", true);


                    __instance.Invoke("ResetDodgeTrigger", 0.5f);
                }

                // send a fix to force m_dodging to false after a short delay.
                // this is a fix for if the player dodges while airborne, the game wont reset their m_dodging to true when they land.
                CombatTweaksMod.Instance.StartCoroutine(DodgeLateFix(__instance));
            }
예제 #6
0
            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);
            }