static int GetBonusOrPenaltyByEnemyType(Entity.DaggerfallEntity attacker, Entity.EnemyEntity AITarget) { if (attacker == null || AITarget == null) { return(0); } int damage = 0; // Apply bonus or penalty by opponent type. // In classic this is broken and only works if the attack is done with a weapon that has the maximum number of enchantments. if (AITarget.GetEnemyGroup() == DFCareer.EnemyGroups.Undead) { if (((int)attacker.Career.UndeadAttackModifier & (int)DFCareer.AttackModifier.Bonus) != 0) { damage += attacker.Level; } if (((int)attacker.Career.UndeadAttackModifier & (int)DFCareer.AttackModifier.Phobia) != 0) { damage -= attacker.Level; } } else if (AITarget.GetEnemyGroup() == DFCareer.EnemyGroups.Daedra) { if (((int)attacker.Career.DaedraAttackModifier & (int)DFCareer.AttackModifier.Bonus) != 0) { damage += attacker.Level; } if (((int)attacker.Career.DaedraAttackModifier & (int)DFCareer.AttackModifier.Phobia) != 0) { damage -= attacker.Level; } } else if (AITarget.GetEnemyGroup() == DFCareer.EnemyGroups.Humanoid) { if (((int)attacker.Career.HumanoidAttackModifier & (int)DFCareer.AttackModifier.Bonus) != 0) { damage += attacker.Level; } if (((int)attacker.Career.HumanoidAttackModifier & (int)DFCareer.AttackModifier.Phobia) != 0) { damage -= attacker.Level; } } else if (AITarget.GetEnemyGroup() == DFCareer.EnemyGroups.Animals) { if (((int)attacker.Career.AnimalsAttackModifier & (int)DFCareer.AttackModifier.Bonus) != 0) { damage += attacker.Level; } if (((int)attacker.Career.AnimalsAttackModifier & (int)DFCareer.AttackModifier.Phobia) != 0) { damage -= attacker.Level; } } return(damage); }
public static int CalculateWeaponDamage(Entity.DaggerfallEntity attacker, Entity.DaggerfallEntity target, FPSWeapon onscreenWeapon) { if (attacker == null || target == null) { return(0); } int damageLow = 0; int damageHigh = 0; int damageModifiers = 0; int baseDamage = 0; int damageResult = 0; int chanceToHitMod = 0; Items.DaggerfallUnityItem weapon = null; Entity.PlayerEntity player = GameManager.Instance.PlayerEntity; Entity.EnemyEntity AIAttacker = null; Entity.EnemyEntity AITarget = null; if (attacker != player) { AIAttacker = attacker as Entity.EnemyEntity; weapon = attacker.ItemEquipTable.GetItem(Items.EquipSlots.RightHand); if (weapon == null) { weapon = attacker.ItemEquipTable.GetItem(Items.EquipSlots.LeftHand); } } else { if (GameManager.Instance.WeaponManager.UsingRightHand) { weapon = attacker.ItemEquipTable.GetItem(Items.EquipSlots.RightHand); } } if (target != player) { AITarget = target as Entity.EnemyEntity; } if (weapon != null) { // If the attacker has a weapon equipped, check if the material is high enough to damage the target if (target.MinMetalToHit > (Items.WeaponMaterialTypes)weapon.NativeMaterialValue) { if (attacker == player) { DaggerfallUI.Instance.PopupMessage(UserInterfaceWindows.HardStrings.materialIneffective); } return(0); } // If the attacker has a weapon equipped, get the weapon's damage damageLow = weapon.GetBaseDamageMin(); damageHigh = weapon.GetBaseDamageMax(); short skillID = weapon.GetWeaponSkillIDAsShort(); chanceToHitMod = attacker.Skills.GetSkillValue(skillID); } else if (attacker == player) { // If the player is attacking with no weapon equipped, use hand-to-hand skill for damage damageLow = CalculateHandToHandMinDamage(attacker.Skills.HandToHand); damageHigh = CalculateHandToHandMaxDamage(attacker.Skills.HandToHand); chanceToHitMod = attacker.Skills.HandToHand; } if (AIAttacker != null) { // Note: In classic, for enemies that have weapons, the damage values in the enemy // definitions are overridden by the weapon stats. This is fine for enemy classes, // who have non-weapon damage values of 0, but for the monsters that use weapons, // they may have a better attack if they don't use a weapon. // In DF Unity, enemies are using whichever is more damaging, the weapon or non-weapon attack. int weaponAverage = ((damageLow + damageHigh) / 2); int noWeaponAverage = ((AIAttacker.MobileEnemy.MinDamage + AIAttacker.MobileEnemy.MaxDamage) / 2); if (noWeaponAverage > weaponAverage) { damageLow = AIAttacker.MobileEnemy.MinDamage; damageHigh = AIAttacker.MobileEnemy.MaxDamage; chanceToHitMod = attacker.Skills.HandToHand; } } baseDamage = UnityEngine.Random.Range(damageLow, damageHigh + 1); if (onscreenWeapon != null && (attacker == player)) { // Apply swing modifiers for player. // The Daggerfall manual groups diagonal slashes to the left and right as if they are the same, but they are different. // Classic does not apply swing modifiers to hand-to-hand. if (onscreenWeapon.WeaponState == WeaponStates.StrikeUp) { damageModifiers += -4; chanceToHitMod += 10; } if (onscreenWeapon.WeaponState == WeaponStates.StrikeDownRight) { damageModifiers += -2; chanceToHitMod += 5; } if (onscreenWeapon.WeaponState == WeaponStates.StrikeDownLeft) { damageModifiers += 2; chanceToHitMod += -5; } if (onscreenWeapon.WeaponState == WeaponStates.StrikeDown) { damageModifiers += 4; chanceToHitMod += -10; } } // Apply weapon proficiency modifiers for player. if ((attacker == player) && weapon != null && ((int)attacker.Career.ExpertProficiencies & weapon.GetWeaponSkillUsed()) != 0) { damageModifiers += ((attacker.Level / 3) + 1); chanceToHitMod += attacker.Level; } // Apply hand-to-hand proficiency modifiers for player. Hand-to-hand proficiencty is not applied in classic. else if ((attacker == player) && weapon == null && ((int)attacker.Career.ExpertProficiencies & (int)(DaggerfallConnect.DFCareer.ProficiencyFlags.HandToHand)) != 0) { damageModifiers += ((attacker.Level / 3) + 1); chanceToHitMod += attacker.Level; } // Apply modifiers for Skeletal Warrior. // In classic these appear to be applied after the swing and weapon proficiency modifiers but before all other // damage modifiers. Doing the same here. // DF Chronicles just says "Edged weapons inflict 1/2 damage" if (weapon != null && (target != player) && AITarget.CareerIndex == (int)Entity.MonsterCareers.SkeletalWarrior) { if (weapon.NativeMaterialValue == (int)Items.WeaponMaterialTypes.Silver) { baseDamage *= 2; damageModifiers *= 2; } if (weapon.GetWeaponSkillUsed() != (int)DaggerfallConnect.DFCareer.ProficiencyFlags.BluntWeapons) { baseDamage /= 2; damageModifiers /= 2; } } // Apply bonus or penalty by opponent type. // In classic this is broken and only works if the attack is done with a weapon that has the maximum number of enchantments. if ((target != player) && (AITarget.GetEnemyGroup() == DaggerfallConnect.DFCareer.EnemyGroups.Undead)) { if (((int)attacker.Career.UndeadAttackModifier & (int)DaggerfallConnect.DFCareer.AttackModifier.Bonus) != 0) { damageModifiers += attacker.Level; } if (((int)attacker.Career.UndeadAttackModifier & (int)DaggerfallConnect.DFCareer.AttackModifier.Phobia) != 0) { damageModifiers -= attacker.Level; } } else if ((target != player) && (AITarget.GetEnemyGroup() == DaggerfallConnect.DFCareer.EnemyGroups.Daedra)) { if (((int)attacker.Career.DaedraAttackModifier & (int)DaggerfallConnect.DFCareer.AttackModifier.Bonus) != 0) { damageModifiers += attacker.Level; } if (((int)attacker.Career.DaedraAttackModifier & (int)DaggerfallConnect.DFCareer.AttackModifier.Phobia) != 0) { damageModifiers -= attacker.Level; } } else if ((target != player) && (AITarget.GetEnemyGroup() == DaggerfallConnect.DFCareer.EnemyGroups.Humanoid)) { if (((int)attacker.Career.HumanoidAttackModifier & (int)DaggerfallConnect.DFCareer.AttackModifier.Bonus) != 0) { damageModifiers += attacker.Level; } if (((int)attacker.Career.HumanoidAttackModifier & (int)DaggerfallConnect.DFCareer.AttackModifier.Phobia) != 0) { damageModifiers -= attacker.Level; } } else if ((target != player) && (AITarget.GetEnemyGroup() == DaggerfallConnect.DFCareer.EnemyGroups.Animals)) { if (((int)attacker.Career.AnimalsAttackModifier & (int)DaggerfallConnect.DFCareer.AttackModifier.Bonus) != 0) { damageModifiers += attacker.Level; } if (((int)attacker.Career.AnimalsAttackModifier & (int)DaggerfallConnect.DFCareer.AttackModifier.Phobia) != 0) { damageModifiers -= attacker.Level; } } // Apply racial modifiers for player. if ((attacker == player) && weapon != null) { if (player.RaceTemplate.ID == (int)Entity.Races.DarkElf) { damageModifiers += (attacker.Level / 4); chanceToHitMod += (attacker.Level / 4); } else if (weapon.GetWeaponSkillUsed() == (int)DaggerfallConnect.DFCareer.ProficiencyFlags.MissileWeapons) { if (player.RaceTemplate.ID == (int)Entity.Races.WoodElf) { damageModifiers += (attacker.Level / 3); chanceToHitMod += (attacker.Level / 3); } } else if (player.RaceTemplate.ID == (int)Entity.Races.Redguard) { damageModifiers += (attacker.Level / 3); chanceToHitMod += (attacker.Level / 3); } } // Apply strength modifier for player or for AI characters using weapons. // The in-game display of the strength modifier in Daggerfall is incorrect. It is actually ((STR - 50) / 5). if ((attacker == player) || (weapon != null)) { damageModifiers += DamageModifier(attacker.Stats.Strength); } // Apply material modifier. // The in-game display in Daggerfall of weapon damages with material modifiers is incorrect. The material modifier is half of what the display suggests. if (weapon != null) { damageModifiers += weapon.GetWeaponMaterialModifier(); } // Choose struck body part int[] bodyParts = { 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6 }; int struckBodyPart = bodyParts[UnityEngine.Random.Range(0, bodyParts.Length)]; // Check for a successful hit. if (CalculateSuccessfulHit(attacker, target, chanceToHitMod, weapon, struckBodyPart) == true) { // 0 damage is possible. Creates no blood splash. damageResult = Mathf.Max(0, (baseDamage + damageModifiers)); } // If damage was done by a weapon, damage condition of weapon and armor of hit body part // In classic, shields are never damaged because the item in the equip slot of the hit // body part is all that is handled. // Here, if an equipped shield covered the hit body part, it takes damage instead. if (weapon != null && damageResult > 0) { weapon.DamageThroughPhysicalHit(damageResult, attacker); Items.DaggerfallUnityItem shield = target.ItemEquipTable.GetItem(Items.EquipSlots.LeftHand); bool shieldTakesDamage = false; if (shield != null) { Items.BodyParts[] protectedBodyParts = shield.GetShieldProtectedBodyParts(); for (int i = 0; (i < protectedBodyParts.Length) && !shieldTakesDamage; i++) { if (protectedBodyParts[i] == (Items.BodyParts)struckBodyPart) { shieldTakesDamage = true; } } } if (shieldTakesDamage) { shield.DamageThroughPhysicalHit(damageResult, target); } else { Items.EquipSlots hitSlot = Items.DaggerfallUnityItem.GetEquipSlotForBodyPart((Items.BodyParts)struckBodyPart); Items.DaggerfallUnityItem armor = target.ItemEquipTable.GetItem(hitSlot); if (armor != null) { armor.DamageThroughPhysicalHit(damageResult, target); } } } // If attack was by player or weapon-based, end here if ((attacker == player) || (weapon != null)) { return(damageResult); } // Handle multiple attacks by AI characters. else { if (AIAttacker.MobileEnemy.MaxDamage2 != 0 && (CalculateSuccessfulHit(attacker, target, chanceToHitMod, weapon, struckBodyPart) == true)) { baseDamage = UnityEngine.Random.Range(AIAttacker.MobileEnemy.MinDamage2, AIAttacker.MobileEnemy.MaxDamage2 + 1); damageResult += Mathf.Max(0, (baseDamage + damageModifiers)); } if (AIAttacker.MobileEnemy.MaxDamage3 != 0 && (CalculateSuccessfulHit(attacker, target, chanceToHitMod, weapon, struckBodyPart) == true)) { baseDamage = UnityEngine.Random.Range(AIAttacker.MobileEnemy.MinDamage3, AIAttacker.MobileEnemy.MaxDamage3 + 1); damageResult += Mathf.Max(0, (baseDamage + damageModifiers)); } return(damageResult); } }
public static int CalculateWeaponDamage(Entity.DaggerfallEntity attacker, Entity.DaggerfallEntity target, FPSWeapon onscreenWeapon) { if (attacker == null || target == null) { return(0); } int damageLow = 0; int damageHigh = 0; int damageModifiers = 0; int baseDamage = 0; int damageResult = 0; int chanceToHitMod = 0; Items.DaggerfallUnityItem weapon = null; Entity.PlayerEntity player = GameManager.Instance.PlayerEntity; Entity.EnemyEntity AIAttacker = null; Entity.EnemyEntity AITarget = null; if (attacker != player) { AIAttacker = attacker as Entity.EnemyEntity; } if (target != player) { AITarget = target as Entity.EnemyEntity; } // TODO: Get weapons of enemy classes and monsters. if (attacker == player) { if (GameManager.Instance.WeaponManager.UsingRightHand) { weapon = attacker.ItemEquipTable.GetItem(Items.EquipSlots.RightHand); } else { weapon = attacker.ItemEquipTable.GetItem(Items.EquipSlots.LeftHand); } } // If the player is attacking with no weapon equipped, use hand-to-hand skill for damage if (weapon == null && attacker == player) { damageLow = CalculateHandToHandMinDamage(attacker.Skills.HandToHand); damageHigh = CalculateHandToHandMaxDamage(attacker.Skills.HandToHand); chanceToHitMod = attacker.Skills.HandToHand; } // If a monster is attacking, use damage values from enemy definitions else if (weapon == null && AIAttacker != null) { damageLow = AIAttacker.MobileEnemy.MinDamage; damageHigh = AIAttacker.MobileEnemy.MaxDamage; chanceToHitMod = attacker.Skills.HandToHand; } // If the player is attacking with a weapon equipped, use the weapon's damage else if (attacker == player) { damageLow = weapon.GetBaseDamageMin(); damageHigh = weapon.GetBaseDamageMax(); short skillID = weapon.GetWeaponSkillID(); chanceToHitMod = attacker.Skills.GetSkillValue(skillID); } baseDamage = UnityEngine.Random.Range(damageLow, damageHigh + 1); if (onscreenWeapon != null && (attacker == player)) { // Apply swing modifiers for player. // The Daggerfall manual groups diagonal slashes to the left and right as if they are the same, but they are different. // Classic does not apply swing modifiers to hand-to-hand. if (onscreenWeapon.WeaponState == WeaponStates.StrikeUp) { damageModifiers += -4; chanceToHitMod += 10; } if (onscreenWeapon.WeaponState == WeaponStates.StrikeDownRight) { damageModifiers += -2; chanceToHitMod += 5; } if (onscreenWeapon.WeaponState == WeaponStates.StrikeDownLeft) { damageModifiers += 2; chanceToHitMod += -5; } if (onscreenWeapon.WeaponState == WeaponStates.StrikeDown) { damageModifiers += 4; chanceToHitMod += -10; } } // Apply weapon proficiency modifiers for player. if ((attacker == player) && weapon != null && ((int)attacker.Career.ExpertProficiencies & weapon.GetWeaponSkillUsed()) != 0) { damageModifiers += ((attacker.Level / 3) + 1); chanceToHitMod += attacker.Level; } // Apply hand-to-hand proficiency modifiers for player. Hand-to-hand proficiencty is not applied in classic. else if ((attacker == player) && weapon == null && ((int)attacker.Career.ExpertProficiencies & (int)(DaggerfallConnect.DFCareer.ProficiencyFlags.HandToHand)) != 0) { damageModifiers += ((attacker.Level / 3) + 1); chanceToHitMod += attacker.Level; } // Apply modifiers for Skeletal Warrior. // In classic these appear to be applied after the swing and weapon proficiency modifiers but before all other // damage modifiers. Doing the same here. // DF Chronicles just says "Edged weapons inflict 1/2 damage" if (weapon != null && (target != player) && AITarget.CareerIndex == (int)Entity.MonsterCareers.SkeletalWarrior) { if (weapon.NativeMaterialValue == (int)Items.WeaponMaterialTypes.Silver) { baseDamage *= 2; damageModifiers *= 2; } if (weapon.GetWeaponSkillUsed() != (int)DaggerfallConnect.DFCareer.ProficiencyFlags.BluntWeapons) { baseDamage /= 2; damageModifiers /= 2; } } // Apply bonus or penalty by opponent type. // In classic this is broken and only works if the attack is done with a weapon that has the maximum number of enchantments. if ((target != player) && (AITarget.GetEnemyGroup() == DaggerfallConnect.DFCareer.EnemyGroups.Undead)) { if (((int)attacker.Career.UndeadAttackModifier & (int)DaggerfallConnect.DFCareer.AttackModifier.Bonus) != 0) { damageModifiers += attacker.Level; } if (((int)attacker.Career.UndeadAttackModifier & (int)DaggerfallConnect.DFCareer.AttackModifier.Phobia) != 0) { damageModifiers -= attacker.Level; } } else if ((target != player) && (AITarget.GetEnemyGroup() == DaggerfallConnect.DFCareer.EnemyGroups.Daedra)) { if (((int)attacker.Career.DaedraAttackModifier & (int)DaggerfallConnect.DFCareer.AttackModifier.Bonus) != 0) { damageModifiers += attacker.Level; } if (((int)attacker.Career.DaedraAttackModifier & (int)DaggerfallConnect.DFCareer.AttackModifier.Phobia) != 0) { damageModifiers -= attacker.Level; } } else if ((target != player) && (AITarget.GetEnemyGroup() == DaggerfallConnect.DFCareer.EnemyGroups.Humanoid)) { if (((int)attacker.Career.HumanoidAttackModifier & (int)DaggerfallConnect.DFCareer.AttackModifier.Bonus) != 0) { damageModifiers += attacker.Level; } if (((int)attacker.Career.HumanoidAttackModifier & (int)DaggerfallConnect.DFCareer.AttackModifier.Phobia) != 0) { damageModifiers -= attacker.Level; } } else if ((target != player) && (AITarget.GetEnemyGroup() == DaggerfallConnect.DFCareer.EnemyGroups.Animals)) { if (((int)attacker.Career.AnimalsAttackModifier & (int)DaggerfallConnect.DFCareer.AttackModifier.Bonus) != 0) { damageModifiers += attacker.Level; } if (((int)attacker.Career.AnimalsAttackModifier & (int)DaggerfallConnect.DFCareer.AttackModifier.Phobia) != 0) { damageModifiers -= attacker.Level; } } // Apply racial modifiers for player. if ((attacker == player) && weapon != null) { if (player.RaceTemplate.ID == (int)Entity.Races.DarkElf) { damageModifiers += (attacker.Level / 4); chanceToHitMod += (attacker.Level / 4); } else if (weapon.GetWeaponSkillUsed() == (int)DaggerfallConnect.DFCareer.ProficiencyFlags.MissileWeapons) { if (player.RaceTemplate.ID == (int)Entity.Races.WoodElf) { damageModifiers += (attacker.Level / 3); chanceToHitMod += (attacker.Level / 3); } } else if (player.RaceTemplate.ID == (int)Entity.Races.Redguard) { damageModifiers += (attacker.Level / 3); chanceToHitMod += (attacker.Level / 3); } } // Apply strength modifier for player or for AI characters using weapons. // The in-game display of the strength modifier in Daggerfall is incorrect. It is actually ((STR - 50) / 5). if ((attacker == player) || (weapon != null)) { damageModifiers += DamageModifier(attacker.Stats.Strength); } // Apply material modifier. // The in-game display in Daggerfall of weapon damages with material modifiers is incorrect. The material modifier is half of what the display suggests. if (weapon != null) { damageModifiers += weapon.GetWeaponMaterialModifier(); } // Check for a successful hit. if (CalculateSuccessfulHit(attacker, target, chanceToHitMod, weapon) == true) { // 0 damage is possible. Creates no blood splash. damageResult = Mathf.Max(0, (baseDamage + damageModifiers)); } // If attack was by player or weapon-based, end here if ((attacker == player) || (weapon != null)) { return(damageResult); } // Handle multiple attacks by AI characters. else { if (AIAttacker.MobileEnemy.MaxDamage2 != 0 && (CalculateSuccessfulHit(attacker, target, chanceToHitMod, weapon) == true)) { baseDamage = UnityEngine.Random.Range(AIAttacker.MobileEnemy.MinDamage2, AIAttacker.MobileEnemy.MaxDamage2 + 1); damageResult += Mathf.Max(0, (baseDamage + damageModifiers)); } if (AIAttacker.MobileEnemy.MaxDamage3 != 0 && (CalculateSuccessfulHit(attacker, target, chanceToHitMod, weapon) == true)) { baseDamage = UnityEngine.Random.Range(AIAttacker.MobileEnemy.MinDamage3, AIAttacker.MobileEnemy.MaxDamage3 + 1); damageResult += Mathf.Max(0, (baseDamage + damageModifiers)); } return(damageResult); } }