/// <summary>
        /// Update armor values after equipping or unequipping a piece of armor.
        /// </summary>
        public void UpdateEquippedArmorValues(DaggerfallUnityItem armor, bool equipping)
        {
            if (armor.ItemGroup == ItemGroups.Armor ||
                (armor.ItemGroup == ItemGroups.MensClothing && armor.GroupIndex >= 6 && armor.GroupIndex <= 8) ||
                (armor.ItemGroup == ItemGroups.WomensClothing && armor.GroupIndex >= 4 && armor.GroupIndex <= 6)
                )
            {
                if (!armor.IsShield)
                {
                    // Get slot used by this armor
                    EquipSlots slot = ItemEquipTable.GetEquipSlot(armor);

                    // Get equip index with out of range check
                    int index = (int)DaggerfallUnityItem.GetBodyPartForEquipSlot(slot);
                    if (armorValues == null || index < 0 || index >= armorValues.Length)
                    {
                        return;
                    }

                    if (equipping)
                    {
                        armorValues[index] -= (sbyte)(armor.GetMaterialArmorValue() * 5);
                    }
                    else
                    {
                        armorValues[index] += (sbyte)(armor.GetMaterialArmorValue() * 5);
                    }
                }
                else
                {
                    // Shield armor values in classic are unaffected by their material type.
                    int[]       values             = { 0, 0, 0, 0, 0, 0, 0 }; // shield's effect on the 7 armor values
                    int         armorBonus         = armor.GetShieldArmorValue();
                    BodyParts[] protectedBodyParts = armor.GetShieldProtectedBodyParts();

                    foreach (var BodyPart in protectedBodyParts)
                    {
                        values[(int)BodyPart] = armorBonus;
                    }

                    for (int i = 0; i < armorValues.Length; i++)
                    {
                        if (equipping)
                        {
                            armorValues[i] -= (sbyte)(values[i] * 5);
                        }
                        else
                        {
                            armorValues[i] += (sbyte)(values[i] * 5);
                        }
                    }
                }
            }
        }
Ejemplo n.º 2
0
        /// Allocate any equipment damage from a strike, and reduce item condition.
        private static bool DamageEquipment(DaggerfallEntity attacker, DaggerfallEntity target, int damage, DaggerfallUnityItem weapon, int struckBodyPart)
        {
            int   atkStrength    = attacker.Stats.LiveStrength;
            int   tarMatMod      = 0;
            int   matDifference  = 0;
            bool  bluntWep       = false;
            bool  shtbladeWep    = false;
            bool  missileWep     = false;
            int   wepEqualize    = 1;
            int   wepWeight      = 1;
            float wepDamResist   = 1f;
            float armorDamResist = 1f;

            // If damage was done by a weapon, damage the weapon and armor of the hit body part.
            if (weapon != null && damage > 0)
            {
                int atkMatMod = weapon.GetWeaponMaterialModifier() + 2;
                int wepDam    = damage;
                wepEqualize = EqualizeMaterialConditions(weapon);
                wepDam     *= wepEqualize;

                if (weapon.GetWeaponSkillIDAsShort() == 32)                 // Checks if the weapon being used is in the Blunt Weapon category, then sets a bool value to true.
                {
                    wepDam      += (atkStrength / 10);
                    wepDamResist = (wepEqualize * .20f) + 1;
                    wepDam       = (int)Mathf.Ceil(wepDam / wepDamResist);
                    bluntWep     = true;
                    wepWeight    = (int)Mathf.Ceil(weapon.EffectiveUnitWeightInKg());

                    ApplyConditionDamageThroughWeaponDamage(weapon, attacker, wepDam, bluntWep, shtbladeWep, missileWep, wepEqualize); // Does condition damage to the attackers weapon.
                }
                else if (weapon.GetWeaponSkillIDAsShort() == 28)                                                                       // Checks if the weapon being used is in the Short Blade category, then sets a bool value to true.
                {
                    if (weapon.TemplateIndex == (int)Weapons.Dagger || weapon.TemplateIndex == (int)Weapons.Tanto)
                    {
                        wepDam      += (atkStrength / 30);
                        wepDamResist = (wepEqualize * .90f) + 1;
                        wepDam       = (int)Mathf.Ceil(wepDam / wepDamResist);
                        shtbladeWep  = true;
                    }
                    else
                    {
                        wepDam      += (atkStrength / 30);
                        wepDamResist = (wepEqualize * .30f) + 1;
                        wepDam       = (int)Mathf.Ceil(wepDam / wepDamResist);
                        shtbladeWep  = true;
                    }

                    ApplyConditionDamageThroughWeaponDamage(weapon, attacker, wepDam, bluntWep, shtbladeWep, missileWep, wepEqualize); // Does condition damage to the attackers weapon.
                }
                else if (weapon.GetWeaponSkillIDAsShort() == 33)                                                                       // Checks if the weapon being used is in the Missile Weapon category, then sets a bool value to true.
                {
                    missileWep = true;

                    ApplyConditionDamageThroughWeaponDamage(weapon, attacker, wepDam, bluntWep, shtbladeWep, missileWep, wepEqualize); // Does condition damage to the attackers weapon.
                }
                else                                                                                                                   // If all other weapons categories have not been found, it defaults to this, which currently includes long blades and axes.
                {
                    wepDam      += (atkStrength / 10);
                    wepDamResist = (wepEqualize * .20f) + 1;
                    wepDam       = (int)Mathf.Ceil(wepDam / wepDamResist);

                    ApplyConditionDamageThroughWeaponDamage(weapon, attacker, wepDam, bluntWep, shtbladeWep, missileWep, wepEqualize);                     // Does condition damage to the attackers weapon.
                }

                if (attacker == GameManager.Instance.PlayerEntity)
                {
                    WarningMessagePlayerEquipmentCondition(weapon);
                }

                DaggerfallUnityItem shield = target.ItemEquipTable.GetItem(EquipSlots.LeftHand);                 // Checks if character is using a shield or not.
                bool shieldTakesDamage     = false;
                if (shield != null)
                {
                    BodyParts[] protectedBodyParts = shield.GetShieldProtectedBodyParts();

                    for (int i = 0; (i < protectedBodyParts.Length) && !shieldTakesDamage; i++)
                    {
                        if (protectedBodyParts[i] == (BodyParts)struckBodyPart)
                        {
                            shieldTakesDamage = true;
                        }
                    }
                }

                if (shieldTakesDamage)
                {
                    int shieldEqualize = EqualizeMaterialConditions(shield);
                    damage       *= shieldEqualize;
                    tarMatMod     = ArmorMaterialModifierFinder(shield);
                    matDifference = tarMatMod - atkMatMod;
                    damage        = MaterialDifferenceDamageCalculation(shield, matDifference, atkStrength, damage, bluntWep, wepWeight, shieldTakesDamage);

                    ApplyConditionDamageThroughWeaponDamage(shield, target, damage, bluntWep, shtbladeWep, missileWep, wepEqualize);

                    if (target == GameManager.Instance.PlayerEntity)
                    {
                        WarningMessagePlayerEquipmentCondition(shield);
                    }
                }
                else
                {
                    EquipSlots          hitSlot = DaggerfallUnityItem.GetEquipSlotForBodyPart((BodyParts)struckBodyPart);
                    DaggerfallUnityItem armor   = target.ItemEquipTable.GetItem(hitSlot);
                    if (armor != null)
                    {
                        int armorEqualize = EqualizeMaterialConditions(armor);
                        damage       *= armorEqualize;
                        tarMatMod     = ArmorMaterialModifierFinder(armor);
                        matDifference = tarMatMod - atkMatMod;
                        damage        = MaterialDifferenceDamageCalculation(armor, matDifference, atkStrength, damage, bluntWep, wepWeight, shieldTakesDamage);

                        ApplyConditionDamageThroughWeaponDamage(armor, target, damage, bluntWep, shtbladeWep, missileWep, wepEqualize);

                        if (target == GameManager.Instance.PlayerEntity)
                        {
                            WarningMessagePlayerEquipmentCondition(armor);
                        }
                    }
                }
                return(false);
            }
            else if (weapon == null && damage > 0)             // Handles Unarmed attacks.
            {
                DaggerfallUnityItem shield = target.ItemEquipTable.GetItem(EquipSlots.LeftHand);
                bool shieldTakesDamage     = false;
                if (shield != null)
                {
                    BodyParts[] protectedBodyParts = shield.GetShieldProtectedBodyParts();

                    for (int i = 0; (i < protectedBodyParts.Length) && !shieldTakesDamage; i++)
                    {
                        if (protectedBodyParts[i] == (BodyParts)struckBodyPart)
                        {
                            shieldTakesDamage = true;
                        }
                    }
                }

                if (shieldTakesDamage)
                {
                    int shieldEqualize = EqualizeMaterialConditions(shield);
                    damage        *= shieldEqualize;
                    tarMatMod      = ArmorMaterialModifierFinder(shield);
                    atkStrength   /= 5;
                    armorDamResist = (tarMatMod * .35f) + 1;
                    damage         = (int)Mathf.Ceil((damage + atkStrength) / armorDamResist);

                    ApplyConditionDamageThroughUnarmedDamage(shield, target, damage);

                    if (target == GameManager.Instance.PlayerEntity)
                    {
                        WarningMessagePlayerEquipmentCondition(shield);
                    }
                }
                else
                {
                    EquipSlots          hitSlot = DaggerfallUnityItem.GetEquipSlotForBodyPart((BodyParts)struckBodyPart);
                    DaggerfallUnityItem armor   = target.ItemEquipTable.GetItem(hitSlot);
                    if (armor != null)
                    {
                        int armorEqualize = EqualizeMaterialConditions(armor);
                        damage        *= armorEqualize;
                        tarMatMod      = ArmorMaterialModifierFinder(armor);
                        atkStrength   /= 5;
                        armorDamResist = (tarMatMod * .20f) + 1;
                        damage         = (int)Mathf.Ceil((damage + atkStrength) / armorDamResist);

                        ApplyConditionDamageThroughUnarmedDamage(armor, target, damage);

                        if (target == GameManager.Instance.PlayerEntity)
                        {
                            WarningMessagePlayerEquipmentCondition(armor);
                        }
                    }
                }
                return(false);
            }
            return(false);
        }
Ejemplo n.º 3
0
        public static int CalculateAttackDamagePhysicalCombat(DaggerfallEntity attacker, DaggerfallEntity target, bool enemyAnimStateRecord, int weaponAnimTime, DaggerfallUnityItem weapon)
        {
            if (attacker == null || target == null)
            {
                return(0);
            }

            int          damageModifiers      = 0;
            int          damage               = 0;
            int          chanceToHitMod       = 0;
            int          backstabChance       = 0;
            PlayerEntity player               = GameManager.Instance.PlayerEntity;
            short        skillID              = 0;
            bool         unarmedAttack        = false;
            bool         weaponAttack         = false;
            bool         bluntWep             = false;
            bool         specialMonsterWeapon = false;
            bool         monsterArmorCheck    = false;
            bool         critSuccess          = false;
            float        critDamMulti         = 1f;
            int          critHitAddi          = 0;
            float        matReqDamMulti       = 1f;

            EnemyEntity AITarget = null;

            AITarget = target as EnemyEntity;

            // Choose whether weapon-wielding enemies use their weapons or weaponless attacks.
            // In classic, weapon-wielding enemies use the damage values of their weapons
            // instead of their weaponless values.
            // For some enemies this gives lower damage than similar-tier monsters
            // and the weaponless values seems more appropriate, so here
            // enemies will choose to use their weaponless attack if it is more damaging.
            EnemyEntity AIAttacker = attacker as EnemyEntity;

            if (AIAttacker != null && weapon != null)
            {
                int weaponAverage   = (weapon.GetBaseDamageMin() + weapon.GetBaseDamageMax()) / 2;
                int noWeaponAverage = (AIAttacker.MobileEnemy.MinDamage + AIAttacker.MobileEnemy.MaxDamage) / 2;
                if (noWeaponAverage > weaponAverage)
                {
                    // Use hand-to-hand
                    weapon = null;
                }
            }

            if (weapon != null)
            {
                if (PhysicalCombatArmorPatch.softMatRequireModuleCheck) // Only run if "Soft Material Requirements" module is active.
                {
                    // If the attacker is using a weapon, check if the material is high enough to damage the target
                    if (target.MinMetalToHit > (WeaponMaterialTypes)weapon.NativeMaterialValue)
                    {
                        int targetMatRequire = (int)target.MinMetalToHit;
                        int weaponMatValue   = weapon.NativeMaterialValue;
                        matReqDamMulti = targetMatRequire - weaponMatValue;

                        if (matReqDamMulti <= 0) // There is no "bonus" damage for meeting material requirements, nor for exceeding them, just normal unmodded damage.
                        {
                            matReqDamMulti = 1;
                        }
                        else // There is a damage penalty for attacking a target with below the minimum material requirements of that target, more as the difference between becomes greater.
                        {
                            matReqDamMulti = (Mathf.Min(matReqDamMulti * 0.2f, 0.9f) - 1) * -1; // Keeps the damage multiplier penalty from going above 90% reduced damage.
                        }
                        if (attacker == player)
                        {
                            Debug.LogFormat("1. matReqDamMulti = {0}", matReqDamMulti);
                        }
                    }
                    // Get weapon skill used
                    skillID = weapon.GetWeaponSkillIDAsShort();
                    if (skillID == 32) // Checks if the weapon being used is in the Blunt Weapon category, then sets a bool value to true.
                    {
                        bluntWep = true;
                    }
                }
                else
                {
                    // If the attacker is using a weapon, check if the material is high enough to damage the target
                    if (target.MinMetalToHit > (WeaponMaterialTypes)weapon.NativeMaterialValue)
                    {
                        if (attacker == player)
                        {
                            DaggerfallUI.Instance.PopupMessage(TextManager.Instance.GetLocalizedText("materialIneffective"));
                        }
                        return(0);
                    }
                    // Get weapon skill used
                    skillID = weapon.GetWeaponSkillIDAsShort();
                    if (skillID == 32) // Checks if the weapon being used is in the Blunt Weapon category, then sets a bool value to true.
                    {
                        bluntWep = true;
                    }
                }
            }
            else
            {
                skillID = (short)DFCareer.Skills.HandToHand;
            }

            if (attacker == player)
            {
                int playerWeaponSkill = attacker.Skills.GetLiveSkillValue(skillID);
                playerWeaponSkill = (int)Mathf.Ceil(playerWeaponSkill * 1.5f); // Makes it so player weapon skill has 150% of the effect it normally would on hit chance. So now instead of 50 weapon skill adding +50 to the end, 50 will now add +75.
                chanceToHitMod    = playerWeaponSkill;
            }
            else
            {
                chanceToHitMod = attacker.Skills.GetLiveSkillValue(skillID);
            }

            if (PhysicalCombatArmorPatch.critStrikeModuleCheck)                             // Applies the 'Critical Strikes Increase Damage' module if it is enabled in the settings.
            {
                if (attacker == player)                                                     // Crit modifiers, if true, for the player.
                {
                    critSuccess = PhysicalCombatArmorPatch.CriticalStrikeHandler(attacker); // Rolls for if the attacker is sucessful with a critical strike, if yes, critSuccess is set to 'true'.

                    if (critSuccess)
                    {
                        critDamMulti = (attacker.Skills.GetLiveSkillValue(DFCareer.Skills.CriticalStrike) / 5);
                        //Debug.LogFormat("1. critDamMulti From PLAYER Skills = {0}", critDamMulti);
                        critHitAddi = (attacker.Skills.GetLiveSkillValue(DFCareer.Skills.CriticalStrike) / 4);
                        //Debug.LogFormat("2. critHitAddi From PLAYER Skills = {0}", critHitAddi);

                        critDamMulti = (critDamMulti * .05f) + 1;
                        //Debug.LogFormat("3. Final critDamMulti From PLAYER Skills = {0}", critDamMulti);

                        chanceToHitMod += critHitAddi; // Adds the critical success value to the 'chanceToHitMod'.
                    }
                }
                else // Crit modifiers, if true, for monsters/enemies.
                {
                    critSuccess = PhysicalCombatArmorPatch.CriticalStrikeHandler(attacker); // Rolls for if the attacker is sucessful with a critical strike, if yes, critSuccess is set to 'true'.

                    if (critSuccess)
                    {
                        critDamMulti = (attacker.Skills.GetLiveSkillValue(DFCareer.Skills.CriticalStrike) / 5);
                        //Debug.LogFormat("1. critDamMulti From MONSTER Skills = {0}", critDamMulti);
                        critHitAddi = (attacker.Skills.GetLiveSkillValue(DFCareer.Skills.CriticalStrike) / 10);
                        //Debug.LogFormat("2. critHitAddi From MONSTER Skills = {0}", critHitAddi);

                        critDamMulti = (critDamMulti * .025f) + 1;
                        //Debug.LogFormat("3. Final critDamMulti From MONSTER Skills = {0}", critDamMulti);

                        chanceToHitMod += critHitAddi; // Adds the critical success value to the 'chanceToHitMod'.
                    }
                }
            }

            if (attacker == player)
            {
                // Apply swing modifiers
                FormulaHelper.ToHitAndDamageMods swingMods = FormulaHelper.CalculateSwingModifiers(GameManager.Instance.WeaponManager.ScreenWeapon);
                damageModifiers += swingMods.damageMod;
                chanceToHitMod  += swingMods.toHitMod;

                // Apply proficiency modifiers
                FormulaHelper.ToHitAndDamageMods proficiencyMods = FormulaHelper.CalculateProficiencyModifiers(attacker, weapon);
                damageModifiers += proficiencyMods.damageMod;
                chanceToHitMod  += proficiencyMods.toHitMod;

                // Apply racial bonuses
                FormulaHelper.ToHitAndDamageMods racialMods = FormulaHelper.CalculateRacialModifiers(attacker, weapon, player);
                damageModifiers += racialMods.damageMod;
                chanceToHitMod  += racialMods.toHitMod;

                backstabChance  = FormulaHelper.CalculateBackstabChance(player, null, enemyAnimStateRecord);
                chanceToHitMod += backstabChance;
            }

            // Choose struck body part
            int struckBodyPart = FormulaHelper.CalculateStruckBodyPart();

            // Get damage for weaponless attacks
            if (skillID == (short)DFCareer.Skills.HandToHand)
            {
                unarmedAttack = true; // Check for later if weapon is NOT being used.

                if (attacker == player || (AIAttacker != null && AIAttacker.EntityType == EntityTypes.EnemyClass))
                {
                    if (FormulaHelper.CalculateSuccessfulHit(attacker, target, chanceToHitMod, struckBodyPart))
                    {
                        damage = FormulaHelper.CalculateHandToHandAttackDamage(attacker, target, damageModifiers, attacker == player); // Added my own, non-overriden version of this method for modification.

                        damage = FormulaHelper.CalculateBackstabDamage(damage, backstabChance);
                    }
                }
                else if (AIAttacker != null) // attacker is a monster
                {
                    specialMonsterWeapon = PhysicalCombatArmorPatch.SpecialWeaponCheckForMonsters(attacker);

                    if (specialMonsterWeapon)
                    {
                        unarmedAttack = false;
                        weaponAttack  = true;
                        weapon        = PhysicalCombatArmorPatch.MonsterWeaponAssign(attacker);
                        skillID       = weapon.GetWeaponSkillIDAsShort();
                        if (skillID == 32) // Checks if the weapon being used is in the Blunt Weapon category, then sets a bool value to true.
                        {
                            bluntWep = true;
                        }
                    }

                    // Handle multiple attacks by AI
                    int minBaseDamage = 0;
                    int maxBaseDamage = 0;
                    int attackNumber  = 0;
                    while (attackNumber < 3) // Classic supports up to 5 attacks but no monster has more than 3
                    {
                        if (attackNumber == 0)
                        {
                            minBaseDamage = AIAttacker.MobileEnemy.MinDamage;
                            maxBaseDamage = AIAttacker.MobileEnemy.MaxDamage;
                        }
                        else if (attackNumber == 1)
                        {
                            minBaseDamage = AIAttacker.MobileEnemy.MinDamage2;
                            maxBaseDamage = AIAttacker.MobileEnemy.MaxDamage2;
                        }
                        else if (attackNumber == 2)
                        {
                            minBaseDamage = AIAttacker.MobileEnemy.MinDamage3;
                            maxBaseDamage = AIAttacker.MobileEnemy.MaxDamage3;
                        }

                        int reflexesChance = 50 - (10 * ((int)player.Reflexes - 2));

                        if (DFRandom.rand() % 100 < reflexesChance && minBaseDamage > 0 && FormulaHelper.CalculateSuccessfulHit(attacker, target, chanceToHitMod, struckBodyPart))
                        {
                            int hitDamage = UnityEngine.Random.Range(minBaseDamage, maxBaseDamage + 1);
                            // Apply special monster attack effects
                            //SHIELD MODULE ADDITION: If player is not blocking with shield, allow custom hit effects to apply.\\
                            if (hitDamage > 0 && !FPSShield.isBlocking)
                            {
                                FormulaHelper.OnMonsterHit(AIAttacker, target, hitDamage);
                            }

                            damage += hitDamage;
                        }
                        ++attackNumber;
                    }
                    if (damage >= 1)
                    {
                        damage = FormulaHelper.CalculateHandToHandAttackDamage(attacker, target, damage, attacker == player); // Added my own, non-overriden version of this method for modification.
                    }
                }
            }
            // Handle weapon attacks
            else if (weapon != null)
            {
                weaponAttack = true; // Check for later on if weapon is being used.

                // Apply weapon material modifier.
                chanceToHitMod += FormulaHelper.CalculateWeaponToHit(weapon);

                // Mod hook for adjusting final hit chance mod. (is a no-op in DFU)
                if (PhysicalCombatArmorPatch.archeryModuleCheck)
                {
                    chanceToHitMod = FormulaHelper.AdjustWeaponHitChanceMod(attacker, target, chanceToHitMod, weaponAnimTime, weapon);
                }

                if (FormulaHelper.CalculateSuccessfulHit(attacker, target, chanceToHitMod, struckBodyPart))
                {
                    damage = FormulaHelper.CalculateWeaponAttackDamage(attacker, target, damageModifiers, weaponAnimTime, weapon);

                    damage = FormulaHelper.CalculateBackstabDamage(damage, backstabChance);
                }

                // Handle poisoned weapons
                //SHIELD MODULE ADDITION: If player is not blocking with shield, allow custom hit effects to apply.\\
                if (damage > 0 && weapon.poisonType != Poisons.None && !FPSShield.isBlocking)
                {
                    FormulaHelper.InflictPoison(attacker, target, weapon.poisonType, false);
                    weapon.poisonType = Poisons.None;
                }
            }

            damage = Mathf.Max(0, damage); // I think this is just here to keep damage from outputting a negative value.

            //Debug.LogFormat("4. Here is damage value before crit modifier is applied = {0}", damage);

            if (critSuccess)                                      // Since the critSuccess variable only ever becomes true inside when the module is active, this is always false when that module is disabled.
            {
                damage = (int)Mathf.Round(damage * critDamMulti); // Multiplies 'Final' damage values, before reductions, with the critical damage multiplier.
                                                                  //Debug.LogFormat("5. Here is damage value AFTER crit modifier is applied = {0}", damage);
            }

            //if (attacker == player)
            //Debug.LogFormat("2. Here is damage value BEFORE soft material requirement modifier is applied = {0}", damage);

            float damCheckBeforeMatMod = damage;

            damage = (int)Mathf.Round(damage * matReqDamMulti); // Could not find much better place to put there, so here seems fine, right after crit multiplier is taken into account.

            //if (attacker == player)
            //Debug.LogFormat("3. Here is damage value AFTER soft material requirement modifier is applied = {0}", damage);

            float damCheckAfterMatMod = damage;

            if (PhysicalCombatArmorPatch.softMatRequireModuleCheck)
            {
                if (attacker == player)
                {
                    if (damCheckBeforeMatMod > 0 && (damCheckAfterMatMod / damCheckBeforeMatMod) <= 0.45f)
                    {
                        DaggerfallUI.AddHUDText("This Weapon Is Not Very Effective Against This Creature.", 1.00f);
                    }
                }
            }

            int targetEndur = target.Stats.LiveEndurance - 50;
            int targetStren = target.Stats.LiveStrength - 50; // Every point of these does something, positive and negative between 50.
            int targetWillp = target.Stats.LiveWillpower - 50;

            float naturalDamResist = (targetEndur * .002f);

            naturalDamResist += (targetStren * .001f);
            naturalDamResist += (targetWillp * .001f);

            Mathf.Clamp(naturalDamResist, -0.2f, 0.2f);                                      // This is to keep other mods that allow over 100 attribute points from allowing damage reduction values to go over 20%. May actually remove this cap for monsters, possibly, since some of the higher level ones have over 100 attribute points.
                                                                                             //Debug.LogFormat("Natural Damage Resist = {0}", naturalDamResist);

            DaggerfallUnityItem shield = target.ItemEquipTable.GetItem(EquipSlots.LeftHand); // Checks if character is using a shield or not.
            bool shieldStrongSpot      = false;

            PhysicalCombatArmorPatch.shieldBlockSuccess = false;
            if (shield != null)
            {
                BodyParts[] protectedBodyParts = shield.GetShieldProtectedBodyParts();

                for (int i = 0; (i < protectedBodyParts.Length) && !shieldStrongSpot; i++)
                {
                    if (protectedBodyParts[i] == (BodyParts)struckBodyPart)
                    {
                        shieldStrongSpot = true;
                    }
                }
                PhysicalCombatArmorPatch.shieldBlockSuccess = PhysicalCombatArmorPatch.ShieldBlockChanceCalculation(target, shieldStrongSpot, shield);

                if (PhysicalCombatArmorPatch.shieldBlockSuccess)
                {
                    PhysicalCombatArmorPatch.shieldBlockSuccess = PhysicalCombatArmorPatch.CompareShieldToUnderArmor(target, struckBodyPart, naturalDamResist);
                }
            }

            if (PhysicalCombatArmorPatch.condBasedEffectModuleCheck) // Only runs if "Condition Based Effectiveness" module is active. As well if a weapon is even being used.
            {
                if (attacker == player && weapon != null)            // Only the player has weapon damage effected by condition value.
                {
                    damage = PhysicalCombatArmorPatch.AlterDamageBasedOnWepCondition(damage, bluntWep, weapon);
                    //Debug.LogFormat("Damage Multiplier Due To Weapon Condition = {0}", damage);
                }
            }


            //--->AMBIDEXTERITY MODULE ADDITION<---\\
            //beginning of major code additions to catch and redirect damage for the parry and shield mechanics.

            //--->PARRY ADDITION<---\\
            //beginning of parry system. Checks who is the target and attacker and activates proper parry accordingly.

            //if the player is not involved in the attack, do the following npc parry check code.....
            if (target != GameManager.Instance.PlayerEntity && attacker != GameManager.Instance.PlayerEntity)
            {
                //sets up attacker and target objects to check if they are in attack state when damage is being done.
                DaggerfallMobileUnit targetController   = target.EntityBehaviour.GetComponentInChildren <DaggerfallMobileUnit>();
                DaggerfallMobileUnit attackerController = attacker.EntityBehaviour.GetComponentInChildren <DaggerfallMobileUnit>();

                if (targetController.Summary.EnemyState == MobileStates.PrimaryAttack && attackerController.Summary.EnemyState == MobileStates.PrimaryAttack)
                {
                    //grabs attackers sense object.
                    EnemySenses attackerSenses = attacker.EntityBehaviour.GetComponent <EnemySenses>();

                    //uses attackers sense to figure out their direction to target using their position data.
                    Vector3 toTarget = attackerSenses.PredictedTargetPos - attackerSenses.transform.position;
                    toTarget.y = 0;

                    //uses attackers sense to figure out their direction to target using their position data.
                    Vector3 targetDirection2D = attackerSenses.PredictedTargetPos - attackerSenses.transform.position;
                    targetDirection2D.y = 0;

                    //if the attack angle is 35 degree angle degrees or more (player does not have them close to center screen) don't register the parry.
                    if (!(Vector3.Angle(toTarget, targetDirection2D) > 30))
                    {
                        AmbidexterityManager.AmbidexterityManagerInstance.activateNPCParry(target, attacker, damage);
                        Debug.Log("Enemy Parry!");
                        damage = 0;
                    }
                }
            }

            //--SHIELD REDIRECT CODE--\\
            //checks to see if player is blocking yet and if the target is the player. If so, assign damage to attackerDamage, enemy object to enemyEntity, and
            //0 out the damage, so player doesn't take any.
            if (FPSShield.isBlocking && target == GameManager.Instance.PlayerEntity && damage != 0)
            {
                //grabs attackers sense object.
                EnemySenses attackerSenses = attacker.EntityBehaviour.GetComponent <EnemySenses>();

                //uses attackers sense to figure out their direction to target using their position data.
                Vector3 toTarget = attackerSenses.PredictedTargetPos - attackerSenses.transform.position;
                toTarget.y = 0;

                //grabs players main camera object and sets up player direction using the camera object.
                Vector3 targetDirection2D;
                Camera  mainCamera = GameObject.FindGameObjectWithTag("MainCamera").GetComponent <Camera>();
                targetDirection2D = -new Vector3(mainCamera.transform.forward.x, 0, mainCamera.transform.forward.z);

                //if the attack angle is shield block angle degrees or more (player does not have them on screen) don't register the block.
                if (!(Vector3.Angle(toTarget, targetDirection2D) > FPSShield.blockAngle) || !(Vector3.Angle(toTarget, targetDirection2D) > 40))
                {
                    Debug.Log("Attack parried!");
                    AmbidexterityManager.isHit          = true;
                    AmbidexterityManager.attackerDamage = damage;
                    damage = 0;
                    AmbidexterityManager.AmbidexterityManagerInstance.attackerEntity = attacker;
                }
            }

            if (damage < 1) // Cut off the execution if the damage is still not anything higher than 1 at this point in the method.
            {
                return(damage);
            }

            FormulaHelper.DamageEquipment(attacker, target, damage, weapon, struckBodyPart); // Might alter this later so that equipment damage is only calculated with the amount that was reduced, not the whole initial amount, will see.

            if (((target != player) && (AITarget.EntityType == EntityTypes.EnemyMonster)))
            {
                monsterArmorCheck = PhysicalCombatArmorPatch.ArmorStruckVerification(target, struckBodyPart); // Check for if a monster has a piece of armor/shield hit by an attack, returns true if so.

                if (!monsterArmorCheck)
                {
                    //Debug.Log("------------------------------------------------------------------------------------------");
                    //Debug.LogFormat("Here is damage value before Monster 'Natural' Damage reduction is applied = {0}", damage);

                    damage = PhysicalCombatArmorPatch.PercentageReductionCalculationForMonsters(attacker, target, damage, bluntWep, naturalDamResist);

                    //Debug.LogFormat("Here is damage value after Monster 'Natural' Damage reduction = {0}", damage);
                    //Debug.Log("------------------------------------------------------------------------------------------");
                }
                else
                {
                    if (unarmedAttack)
                    {
                        //Debug.Log("------------------------------------------------------------------------------------------");
                        //Debug.LogFormat("Here is damage value before armor reduction is applied = {0}", damage);

                        damage = PhysicalCombatArmorPatch.CalculateArmorDamageReductionWithUnarmed(attacker, target, damage, struckBodyPart, naturalDamResist); // This will be the method call for armor reduction against unarmed.

                        //Debug.LogFormat("Here is damage value after armor reduction = {0}", damage);
                        //Debug.Log("------------------------------------------------------------------------------------------");
                    }
                    else if (weaponAttack)
                    {
                        //Debug.Log("------------------------------------------------------------------------------------------");
                        //Debug.LogFormat("Here is damage value before armor reduction is applied = {0}", damage);

                        damage = PhysicalCombatArmorPatch.CalculateArmorDamageReductionWithWeapon(attacker, target, damage, weapon, struckBodyPart, naturalDamResist); // This will be the method call for armor reduction against weapons.

                        //Debug.LogFormat("Here is damage value after armor reduction = {0}", damage);
                        //Debug.Log("------------------------------------------------------------------------------------------");
                    }
                }
            }
            else
            {
                if (unarmedAttack)
                {
                    //Debug.Log("------------------------------------------------------------------------------------------");
                    //Debug.LogFormat("Here is damage value before armor reduction is applied = {0}", damage);
                    int damBefore = damage;

                    damage = PhysicalCombatArmorPatch.CalculateArmorDamageReductionWithUnarmed(attacker, target, damage, struckBodyPart, naturalDamResist); // This will be the method call for armor reduction against unarmed.

                    int damAfter = damage;
                    //Debug.LogFormat("Here is damage value after armor reduction = {0}", damage);
                    if (damBefore > 0)
                    {
                        int damReduPercent = ((100 * damAfter / damBefore) - 100) * -1;
                        //Debug.LogFormat("Here is damage reduction percent = {0}%", damReduPercent);
                    }
                    //Debug.Log("------------------------------------------------------------------------------------------");
                }
                else if (weaponAttack)
                {
                    //Debug.Log("------------------------------------------------------------------------------------------");
                    //Debug.LogFormat("Here is damage value before armor reduction is applied = {0}", damage);
                    int damBefore = damage;

                    damage = PhysicalCombatArmorPatch.CalculateArmorDamageReductionWithWeapon(attacker, target, damage, weapon, struckBodyPart, naturalDamResist); // This will be the method call for armor reduction against weapons.

                    int damAfter = damage;
                    //Debug.LogFormat("Here is damage value after armor reduction = {0}", damage);
                    if (damBefore > 0)
                    {
                        int damReduPercent = ((100 * damAfter / damBefore) - 100) * -1;
                        //Debug.LogFormat("Here is damage reduction percent = {0}%", damReduPercent);
                    }
                    //Debug.Log("------------------------------------------------------------------------------------------");
                }
            }

            // Apply Ring of Namira effect
            if (target == player)
            {
                DaggerfallUnityItem[] equippedItems = target.ItemEquipTable.EquipTable;
                DaggerfallUnityItem   item          = null;
                if (equippedItems.Length != 0)
                {
                    if (IsRingOfNamira(equippedItems[(int)EquipSlots.Ring0]) || IsRingOfNamira(equippedItems[(int)EquipSlots.Ring1]))
                    {
                        IEntityEffect effectTemplate = GameManager.Instance.EntityEffectBroker.GetEffectTemplate(RingOfNamiraEffect.EffectKey);
                        effectTemplate.EnchantmentPayloadCallback(EnchantmentPayloadFlags.None,
                                                                  targetEntity: AIAttacker.EntityBehaviour,
                                                                  sourceItem: item,
                                                                  sourceDamage: damage);
                    }
                }
            }

            //Debug.LogFormat("Damage {0} applied, animTime={1}  ({2})", damage, weaponAnimTime, GameManager.Instance.WeaponManager.ScreenWeapon.WeaponState);

            return(damage);
        }
Ejemplo n.º 4
0
        // Refresh armour value labels
        void RefreshArmourValues(PlayerEntity playerEntity, bool suppress = false)
        {
            DaggerfallUnityItem shield = playerEntity.ItemEquipTable.GetItem(EquipSlots.LeftHand); // Checks if character is using a shield or not.

            if (shield != null && !shield.IsShield)
            {
                shield = null;
            }
            bool hasShield = (shield != null) ? true : false; // if shield has a value, then true, if not, false.

            int[] shieldCovered = { 0, 0, 0, 0, 0, 0, 0 };    // shield's effect on the 7 armor values
            if (hasShield)
            {
                int         armorBonus         = shield.GetShieldArmorValue();
                BodyParts[] protectedBodyParts = shield.GetShieldProtectedBodyParts();

                foreach (var BodyPart in protectedBodyParts)
                {
                    shieldCovered[(int)BodyPart] = armorBonus;
                }
            }


            for (int bpIdx = 0; bpIdx < DaggerfallEntity.NumberBodyParts; bpIdx++)
            {
                int    armorMod      = playerEntity.DecreasedArmorValueModifier - playerEntity.IncreasedArmorValueModifier;
                float  armorDamReduc = 0f;
                float  bpAvB         = 0;
                float  bpAvS         = 0;
                float  bpAvP         = 0;
                string bludResist    = "";
                string slasResist    = "";
                string pierResist    = "";

                EquipSlots          hitSlot = DaggerfallUnityItem.GetEquipSlotForBodyPart((BodyParts)bpIdx);
                DaggerfallUnityItem armor   = playerEntity.ItemEquipTable.GetItem(hitSlot);
                if (armor != null)
                {
                    armorDamReduc = FormulaHelper.PercentageDamageReductionCalculation(armor, false, 0f, 1);
                    bpAvB         = (int)Mathf.Round((armorDamReduc - 1) * -100f) - armorMod;

                    armorDamReduc = FormulaHelper.PercentageDamageReductionCalculation(armor, false, 0f, 2);
                    bpAvS         = (int)Mathf.Round((armorDamReduc - 1) * -100f) - armorMod;

                    armorDamReduc = FormulaHelper.PercentageDamageReductionCalculation(armor, false, 0f, 3);
                    bpAvP         = (int)Mathf.Round((armorDamReduc - 1) * -100f) - armorMod;

                    bludResist = "B: " + bpAvB + "%";
                    slasResist = "S: " + bpAvS + "%";
                    pierResist = "P: " + bpAvP + "%";

                    if (armor.ItemGroup == ItemGroups.Tiara_Jewelry || armor.ItemGroup == ItemGroups.Crown_Jewelry)
                    {
                        bludResist = "";
                        slasResist = "";
                        pierResist = "";
                    }
                }
                armourLabelsB[bpIdx].Text = (!suppress) ? bludResist : string.Empty;
                armourLabelsS[bpIdx].Text = (!suppress) ? slasResist : string.Empty;
                armourLabelsP[bpIdx].Text = (!suppress) ? pierResist : string.Empty;

                if (armorMod < 0)
                {
                    armourLabelsB[bpIdx].TextColor = DaggerfallUI.DaggerfallUnityStatDrainedTextColor2;
                    armourLabelsS[bpIdx].TextColor = DaggerfallUI.DaggerfallUnityStatDrainedTextColor2;
                    armourLabelsP[bpIdx].TextColor = DaggerfallUI.DaggerfallUnityStatDrainedTextColor2;
                }
                else if (armorMod > 0)
                {
                    armourLabelsB[bpIdx].TextColor = DaggerfallUI.DaggerfallUnityStatIncreasedTextColor2;
                    armourLabelsS[bpIdx].TextColor = DaggerfallUI.DaggerfallUnityStatIncreasedTextColor2;
                    armourLabelsP[bpIdx].TextColor = DaggerfallUI.DaggerfallUnityStatIncreasedTextColor2;
                }
                else
                {
                    armourLabelsB[bpIdx].TextColor = DaggerfallUI.DaggerfallDefaultTextColor;
                    armourLabelsS[bpIdx].TextColor = DaggerfallUI.DaggerfallDefaultTextColor;
                    armourLabelsP[bpIdx].TextColor = DaggerfallUI.DaggerfallDefaultTextColor;
                }

                if (hasShield)
                {
                    bool   covered         = (shieldCovered[bpIdx] > 0) ? true : false;
                    float  shieldBlockChan = (int)Mathf.Round(FormulaHelper.ShieldBlockChance(shield, playerEntity, covered));
                    string shieldText      = "Bk:" + shieldBlockChan + "%";

                    if (covered)
                    {
                        shieldLabels[bpIdx].Text      = (!suppress) ? shieldText : string.Empty;
                        shieldLabels[bpIdx].TextColor = DaggerfallUI.DaggerfallDefaultTextColor;
                    }
                    else
                    {
                        shieldLabels[bpIdx].Text      = (!suppress) ? shieldText : string.Empty;
                        shieldLabels[bpIdx].TextColor = DaggerfallUI.DaggerfallDefaultTextColor;
                    }
                }
                else
                {
                    shieldLabels[bpIdx].Text = "";
                }
            }
        }