void Start() { mobile = GetComponentInChildren <DaggerfallMobileUnit>(); entityBehaviour = GetComponent <DaggerfallEntityBehaviour>(); enemyEntity = entityBehaviour.Entity as EnemyEntity; motor = GetComponent <EnemyMotor>(); questBehaviour = GetComponent <QuestResourceBehaviour>(); short[] classicSpawnXZDistArray = { 1024, 384, 640, 768, 768, 768, 768 }; short[] classicSpawnYDistUpperArray = { 128, 128, 128, 384, 768, 128, 256 }; short[] classicSpawnYDistLowerArray = { 0, 0, 0, 0, -128, -768, 0 }; short[] classicDespawnXZDistArray = { 1024, 1024, 1024, 1024, 768, 768, 768 }; short[] classicDespawnYDistArray = { 384, 384, 384, 384, 768, 768, 768 }; byte index = mobile.Summary.ClassicSpawnDistanceType; classicSpawnXZDist = classicSpawnXZDistArray[index] * MeshReader.GlobalScale; classicSpawnYDistUpper = classicSpawnYDistUpperArray[index] * MeshReader.GlobalScale; classicSpawnYDistLower = classicSpawnYDistLowerArray[index] * MeshReader.GlobalScale; classicDespawnXZDist = classicDespawnXZDistArray[index] * MeshReader.GlobalScale; classicDespawnYDist = classicDespawnYDistArray[index] * MeshReader.GlobalScale; // 180 degrees is classic's value. 190 degrees is actual human FOV according to online sources. if (DaggerfallUnity.Settings.EnhancedCombatAI) { FieldOfView = 190; } }
void Start() { motor = GetComponent <EnemyMotor>(); senses = GetComponent <EnemySenses>(); sounds = GetComponent <EnemySounds>(); mobile = GetComponentInChildren <DaggerfallMobileUnit>(); entityBehaviour = GetComponent <DaggerfallEntityBehaviour>(); }
void Start() { motor = GetComponent <EnemyMotor>(); senses = GetComponent <EnemySenses>(); sounds = GetComponent <EnemySounds>(); mobile = GetComponent <DaggerfallEnemy>().MobileUnit; dfMobile = mobile as DaggerfallMobileUnit; entityBehaviour = GetComponent <DaggerfallEntityBehaviour>(); }
void FixedUpdate() { if (Player != null) { Vector3 toPlayer = Player.transform.position - transform.position; directionToPlayer = toPlayer.normalized; distanceToPlayer = toPlayer.magnitude; playerInSight = CanSeePlayer(); if (playerInSight) { detectedPlayer = true; } // Classic stealth mechanics would be interfered with by hearing, so only enable // hearing if the enemy has detected the player. If player has been seen we can omit hearing. if (detectedPlayer && !playerInSight) { playerInEarshot = CanHearPlayer(); } else { playerInEarshot = false; } if ((playerInEarshot || playerInSight) && !hasEncounteredPlayer) { hasEncounteredPlayer = true; // Check appropriate language skill to see if player can pacify enemy DaggerfallEntityBehaviour entityBehaviour = GetComponent <DaggerfallEntityBehaviour>(); EnemyMotor motor = GetComponent <EnemyMotor>(); if (entityBehaviour && motor && (entityBehaviour.EntityType == EntityTypes.EnemyMonster || entityBehaviour.EntityType == EntityTypes.EnemyClass)) { EnemyEntity enemyEntity = entityBehaviour.Entity as EnemyEntity; DFCareer.Skills languageSkill = enemyEntity.GetLanguageSkill(); if (languageSkill != DFCareer.Skills.None) { PlayerEntity player = GameManager.Instance.PlayerEntity; if (FormulaHelper.CalculateEnemyPacification(player, languageSkill)) { motor.IsHostile = false; DaggerfallUI.AddHUDText(HardStrings.languagePacified.Replace("%e", enemyEntity.Name).Replace("%s", languageSkill.ToString()), 5); player.TallySkill(languageSkill, 3); // BCHG: increased skill uses from (assumed) 1 in classic on success to make raising language skills easier } else if (languageSkill != DFCareer.Skills.Etiquette && languageSkill != DFCareer.Skills.Streetwise) { player.TallySkill(languageSkill, 1); } } } } } }
/// <summary> /// Determines if enemies are nearby. Uses include whether player is able to rest or not. /// Based on distance to nearest monster, and if monster can actually sense player. /// </summary> /// <param name="resting">Is player initiating or continuing rest?</param> /// <param name="includingPacified">Include pacified enemies in this test?</param> /// <returns>True if enemies are nearby.</returns> public bool AreEnemiesNearby(bool resting = false, bool includingPacified = false) { const float spawnDistance = 1024 * MeshReader.GlobalScale; const float restingDistance = 12f; bool areEnemiesNearby = false; DaggerfallEntityBehaviour[] entityBehaviours = FindObjectsOfType <DaggerfallEntityBehaviour>(); for (int i = 0; i < entityBehaviours.Length; i++) { DaggerfallEntityBehaviour entityBehaviour = entityBehaviours[i]; if (entityBehaviour.EntityType == EntityTypes.EnemyMonster || entityBehaviour.EntityType == EntityTypes.EnemyClass) { EnemySenses enemySenses = entityBehaviour.GetComponent <EnemySenses>(); if (enemySenses) { // Check if enemy can actively target player bool enemyCanSeePlayer = enemySenses.Target == Instance.PlayerEntityBehaviour && enemySenses.TargetInSight; // Allow for a shorter test distance if enemy is unaware of player while resting if (resting && !enemyCanSeePlayer && Vector3.Distance(entityBehaviour.transform.position, PlayerController.transform.position) > restingDistance) { continue; } // Can enemy see player or is close enough they would be spawned in classic? if (enemyCanSeePlayer || enemySenses.WouldBeSpawnedInClassic) { // Is it hostile or pacified? EnemyMotor enemyMotor = entityBehaviour.GetComponent <EnemyMotor>(); EnemyEntity enemyEntity = entityBehaviour.Entity as EnemyEntity; if (includingPacified || (enemyMotor.IsHostile && enemyEntity.MobileEnemy.Team != MobileTeams.PlayerAlly)) { areEnemiesNearby = true; break; } } } } } // Also check for enemy spawners that might emit an enemy FoeSpawner[] spawners = FindObjectsOfType <FoeSpawner>(); for (int i = 0; i < spawners.Length; i++) { // Is a spawner inside min distance? if (Vector3.Distance(spawners[i].transform.position, PlayerController.transform.position) < spawnDistance) { areEnemiesNearby = true; break; } } return(areEnemiesNearby); }
/// <summary> /// Make all enemies in an area go hostile. /// </summary> public void MakeEnemiesHostile() { DaggerfallEntityBehaviour[] entityBehaviours = FindObjectsOfType <DaggerfallEntityBehaviour>(); for (int i = 0; i < entityBehaviours.Length; i++) { DaggerfallEntityBehaviour entityBehaviour = entityBehaviours[i]; if (entityBehaviour.EntityType == EntityTypes.EnemyMonster || entityBehaviour.EntityType == EntityTypes.EnemyClass) { EnemyMotor enemyMotor = entityBehaviour.GetComponent <EnemyMotor>(); if (enemyMotor) { enemyMotor.IsHostile = true; } } } }
/// <summary> /// Gets how many enemies of a given type exist. /// </summary> /// <param name="type">Enemy type to search for.</param> /// <param name="stopLookingIfFound">Return as soon as an enemy of given type is found.</param> /// <returns>Number of this enemy type.</returns> public int HowManyEnemiesOfType(MobileTypes type, bool stopLookingIfFound = false, bool includingPacified = false) { int numberOfEnemies = 0; DaggerfallEntityBehaviour[] entityBehaviours = FindObjectsOfType <DaggerfallEntityBehaviour>(); for (int i = 0; i < entityBehaviours.Length; i++) { DaggerfallEntityBehaviour entityBehaviour = entityBehaviours[i]; if (entityBehaviour.EntityType == EntityTypes.EnemyMonster || entityBehaviour.EntityType == EntityTypes.EnemyClass) { EnemyEntity entity = entityBehaviour.Entity as EnemyEntity; if (entity.MobileEnemy.ID == (int)type) { // Is it hostile or pacified? EnemyMotor enemyMotor = entityBehaviour.GetComponent <EnemyMotor>(); if (includingPacified || (enemyMotor.IsHostile && entity.Team != MobileTeams.PlayerAlly)) { numberOfEnemies++; if (stopLookingIfFound) { return(numberOfEnemies); } } } } } // Also check for enemy spawners that might emit an enemy FoeSpawner[] spawners = FindObjectsOfType <FoeSpawner>(); for (int i = 0; i < spawners.Length; i++) { // Is a spawner inside min distance? if (spawners[i].FoeType == type) { numberOfEnemies++; if (stopLookingIfFound) { return(numberOfEnemies); } } } return(numberOfEnemies); }
// Handle charging into enemies. private void HandleCharge(GameObject hitGO, DaggerfallEntityBehaviour hitEntityBehaviour, Vector3 direction) { if (hitEntityBehaviour.Entity is EnemyEntity) { EnemyEntity hitEnemyEntity = (EnemyEntity)hitEntityBehaviour.Entity; if (!hitEnemyEntity.PickpocketByPlayerAttempted) { // Play heavy hit sound. EnemySounds enemySounds = hitGO.GetComponent <EnemySounds>(); DaggerfallMobileUnit entityMobileUnit = hitGO.GetComponentInChildren <DaggerfallMobileUnit>(); Genders gender; if (entityMobileUnit.Summary.Enemy.Gender == MobileGender.Male || hitEnemyEntity.MobileEnemy.ID == (int)MobileTypes.Knight_CityWatch) { gender = Genders.Male; } else { gender = Genders.Female; } enemySounds.PlayCombatVoice(gender, false, true); // Knockback the enemy. EnemyMotor enemyMotor = hitGO.GetComponent <EnemyMotor>(); enemyMotor.KnockbackSpeed = 100; enemyMotor.KnockbackDirection = direction; // Handle charge hit damage and fatigue loss. PlayerEntity playerEntity = GameManager.Instance.PlayerEntity; hitEnemyEntity.PickpocketByPlayerAttempted = true; playerEntity.DecreaseFatigue(PlayerEntity.DefaultFatigueLoss * 15); int minBaseDamage = FormulaHelper.CalculateHandToHandMinDamage(playerEntity.Skills.GetLiveSkillValue(DFCareer.Skills.HandToHand)); int maxBaseDamage = FormulaHelper.CalculateHandToHandMaxDamage(playerEntity.Skills.GetLiveSkillValue(DFCareer.Skills.HandToHand)); int damage = UnityEngine.Random.Range(minBaseDamage, maxBaseDamage + 1); damage += playerEntity.Stats.GetLiveStatValue(DFCareer.Stats.Agility) / 10; damage += playerEntity.Stats.GetLiveStatValue(DFCareer.Stats.Willpower) / 10; DaggerfallEntityBehaviour playerEntityBehaviour = playerEntity.EntityBehaviour; hitEntityBehaviour.DamageHealthFromSource(playerEntityBehaviour, damage, true, BloodPos()); Debug.LogFormat("Charged down a {0} for {1} damage!", hitEntityBehaviour.name, damage); } } }
/// <summary> /// Determines if enemies are nearby. Uses include whether player is able to rest or not. /// Based on distance to nearest monster, and if monster can actually sense player. /// </summary> /// <param name="minMonsterSpawnerDistance">Monster spawners must be at least this close.</param> /// <returns>True if enemies are nearby.</returns> public bool AreEnemiesNearby(float minMonsterSpawnerDistance = 12f, bool includingPacified = false) { bool areEnemiesNearby = false; DaggerfallEntityBehaviour[] entityBehaviours = FindObjectsOfType <DaggerfallEntityBehaviour>(); for (int i = 0; i < entityBehaviours.Length; i++) { DaggerfallEntityBehaviour entityBehaviour = entityBehaviours[i]; if (entityBehaviour.EntityType == EntityTypes.EnemyMonster || entityBehaviour.EntityType == EntityTypes.EnemyClass) { EnemySenses enemySenses = entityBehaviour.GetComponent <EnemySenses>(); if (enemySenses) { // Can enemy see player or is close enough they would be spawned in classic? if ((enemySenses.Target == Instance.PlayerEntityBehaviour && enemySenses.TargetInSight) || enemySenses.WouldBeSpawnedInClassic) { // Is it hostile or pacified? EnemyMotor enemyMotor = entityBehaviour.GetComponent <EnemyMotor>(); EnemyEntity enemyEntity = entityBehaviour.Entity as EnemyEntity; if (includingPacified || (enemyMotor.IsHostile && enemyEntity.MobileEnemy.Team != MobileTeams.PlayerAlly)) { areEnemiesNearby = true; break; } } } } } // Also check for enemy spawners that might emit an enemy FoeSpawner[] spawners = FindObjectsOfType <FoeSpawner>(); for (int i = 0; i < spawners.Length; i++) { // Is a spawner inside min distance? if (Vector3.Distance(spawners[i].transform.position, PlayerController.transform.position) < minMonsterSpawnerDistance) { areEnemiesNearby = true; break; } } return(areEnemiesNearby); }
void Start() { mobile = GetComponentInChildren <DaggerfallMobileUnit>(); entityBehaviour = GetComponent <DaggerfallEntityBehaviour>(); enemyEntity = entityBehaviour.Entity as EnemyEntity; motor = GetComponent <EnemyMotor>(); questBehaviour = GetComponent <QuestResourceBehaviour>(); lastKnownTargetPos = ResetPlayerPos; short[] classicSpawnXZDistArray = { 1024, 384, 640, 768, 768, 768, 768 }; short[] classicSpawnYDistUpperArray = { 128, 128, 128, 384, 768, 128, 256 }; short[] classicSpawnYDistLowerArray = { 0, 0, 0, 0, -128, -768, 0 }; short[] classicDespawnXZDistArray = { 1024, 1024, 1024, 1024, 768, 768, 768 }; short[] classicDespawnYDistArray = { 384, 384, 384, 384, 768, 768, 768 }; byte index = mobile.Summary.ClassicSpawnDistanceType; classicSpawnXZDist = classicSpawnXZDistArray[index] * MeshReader.GlobalScale; classicSpawnYDistUpper = classicSpawnYDistUpperArray[index] * MeshReader.GlobalScale; classicSpawnYDistLower = classicSpawnYDistLowerArray[index] * MeshReader.GlobalScale; classicDespawnXZDist = classicDespawnXZDistArray[index] * MeshReader.GlobalScale; classicDespawnYDist = classicDespawnYDistArray[index] * MeshReader.GlobalScale; }
private int ApplyDamageToNonPlayer(Items.DaggerfallUnityItem weapon, Vector3 direction, bool bowAttack = false) { if (senses.Target == null) { return(0); } // TODO: Merge with hit code in WeaponManager to eliminate duplicate code EnemyEntity entity = entityBehaviour.Entity as EnemyEntity; EnemyEntity targetEntity = senses.Target.Entity as EnemyEntity; EnemySounds targetSounds = senses.Target.GetComponent <EnemySounds>(); EnemyMotor targetMotor = senses.Target.transform.GetComponent <EnemyMotor>(); int enemyDamType = EnemyDamageTypeUsed(entity, weapon); // Returns an integer value that corresponds to a specific damage type that this type of enemy can use, will use later on in combat formula. // Calculate damage damage = FormulaHelper.CalculateAttackDamage(entity, targetEntity, -1, 0, weapon, out bool shieldBlockSuccess, out int mainDamType, out bool critStrikeSuccess, out bool armorPartAbsorbed, out bool armorCompleteAbsorbed, out Items.DaggerfallUnityItem addedAIWeapon, out bool hitSuccess, out bool metalShield, out bool metalArmor, enemyDamType); // Break any "normal power" concealment effects on enemy if (entity.IsMagicallyConcealedNormalPower && damage > 0) { EntityEffectManager.BreakNormalPowerConcealmentEffects(entityBehaviour); } // If the AI was given a weapon through the damage formula, this gives them that weapon for this part of the calling method for later use. if (weapon == null) { weapon = addedAIWeapon; } // Play associated sound when armor/shield was responsible for absorbing damage completely. if (damage <= 0) { if (hitSuccess && shieldBlockSuccess) { targetSounds.PlayShieldBlockSound(weapon, metalShield); } else if (hitSuccess && armorCompleteAbsorbed) { targetSounds.PlayArmorAbsorbSound(weapon, metalArmor); } else { WeaponTypes weaponType = WeaponTypes.Melee; if (weapon != null) { weaponType = DaggerfallUnity.Instance.ItemHelper.ConvertItemToAPIWeaponType(weapon); } if ((!bowAttack && !targetEntity.MobileEnemy.ParrySounds) || weaponType == WeaponTypes.Melee) { sounds.PlayMissSound(weapon); } else if (targetEntity.MobileEnemy.ParrySounds) { targetSounds.PlayParrySound(); } } } // Play hit sound and trigger blood splash at hit point if (damage > 0) { if (shieldBlockSuccess && armorPartAbsorbed) { sounds.PlayShieldBlockSound(weapon, metalShield); } targetSounds.PlayHitSound(weapon); EnemyBlood blood = senses.Target.transform.GetComponent <EnemyBlood>(); CharacterController targetController = senses.Target.transform.GetComponent <CharacterController>(); Vector3 bloodPos = senses.Target.transform.position + targetController.center; bloodPos.y += targetController.height / 8; if (blood) { blood.ShowBloodSplash(targetEntity.MobileEnemy.BloodIndex, bloodPos); } // Knock back enemy based on damage and enemy weight if (targetMotor && (targetMotor.KnockbackSpeed <= (5 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10)) && (entityBehaviour.EntityType == EntityTypes.EnemyClass || targetEntity.MobileEnemy.Weight > 0))) { float enemyWeight = targetEntity.GetWeightInClassicUnits(); float tenTimesDamage = damage * 10; float twoTimesDamage = damage * 2; float knockBackAmount = ((tenTimesDamage - enemyWeight) * 256) / (enemyWeight + tenTimesDamage) * twoTimesDamage; float KnockbackSpeed = (tenTimesDamage / enemyWeight) * (twoTimesDamage - (knockBackAmount / 256)); KnockbackSpeed /= (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10); if (KnockbackSpeed < (15 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10))) { KnockbackSpeed = (15 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10)); } targetMotor.KnockbackSpeed = KnockbackSpeed; targetMotor.KnockbackDirection = direction; } if (DaggerfallUnity.Settings.CombatVoices && senses.Target.EntityType == EntityTypes.EnemyClass && Dice100.SuccessRoll(40)) { DaggerfallMobileUnit targetMobileUnit = senses.Target.GetComponentInChildren <DaggerfallMobileUnit>(); Genders gender; if (targetMobileUnit.Summary.Enemy.Gender == MobileGender.Male || targetEntity.MobileEnemy.ID == (int)MobileTypes.Knight_CityWatch) { gender = Genders.Male; } else { gender = Genders.Female; } targetSounds.PlayCombatVoice(gender, false, damage >= targetEntity.MaxHealth / 4); } } // Handle Strikes payload from enemy to non-player target - this could change damage amount if (weapon != null && weapon.IsEnchanted) { EntityEffectManager effectManager = GetComponent <EntityEffectManager>(); if (effectManager) { damage = effectManager.DoItemEnchantmentPayloads(EnchantmentPayloadFlags.Strikes, weapon, entity.Items, targetEntity.EntityBehaviour, damage); } } targetEntity.DecreaseHealth(damage); if (targetMotor) { targetMotor.MakeEnemyHostileToAttacker(entityBehaviour); } return(damage); }
// Returns true if hit an enemy entity public bool WeaponDamage(RaycastHit hit, Vector3 direction, bool arrowHit = false) { DaggerfallUnityItem strikingWeapon = null; // Check if hit has an DaggerfallAction component DaggerfallAction action = hit.transform.gameObject.GetComponent <DaggerfallAction>(); if (action) { action.Receive(player, DaggerfallAction.TriggerTypes.Attack); } // Check if hit has an DaggerfallActionDoor component DaggerfallActionDoor actionDoor = hit.transform.gameObject.GetComponent <DaggerfallActionDoor>(); if (actionDoor) { actionDoor.AttemptBash(); return(false); } // Check if hit an entity and remove health DaggerfallEntityBehaviour entityBehaviour = hit.transform.GetComponent <DaggerfallEntityBehaviour>(); DaggerfallMobileUnit entityMobileUnit = hit.transform.GetComponentInChildren <DaggerfallMobileUnit>(); if (entityBehaviour) { if (entityBehaviour.EntityType == EntityTypes.EnemyMonster || entityBehaviour.EntityType == EntityTypes.EnemyClass) { EnemyEntity enemyEntity = entityBehaviour.Entity as EnemyEntity; // Calculate damage int damage; if (!arrowHit) { if (usingRightHand) { strikingWeapon = currentRightHandWeapon; } else { strikingWeapon = currentLeftHandWeapon; } } else { strikingWeapon = lastBowUsed; } damage = FormulaHelper.CalculateAttackDamage(playerEntity, enemyEntity, strikingWeapon, entityMobileUnit.Summary.AnimStateRecord); // Break any "normal power" concealment effects on player if (playerEntity.IsMagicallyConcealedNormalPower && damage > 0) { EntityEffectManager.BreakNormalPowerConcealmentEffects(GameManager.Instance.PlayerEntityBehaviour); } EnemyMotor enemyMotor = hit.transform.GetComponent <EnemyMotor>(); EnemySounds enemySounds = hit.transform.GetComponent <EnemySounds>(); // Play arrow sound and add arrow to target's inventory if (arrowHit) { DaggerfallUnityItem arrow = ItemBuilder.CreateItem(ItemGroups.Weapons, (int)Weapons.Arrow); enemyEntity.Items.AddItem(arrow); } // Play hit sound and trigger blood splash at hit point if (damage > 0) { if (usingRightHand) { enemySounds.PlayHitSound(currentRightHandWeapon); } else { enemySounds.PlayHitSound(currentLeftHandWeapon); } EnemyBlood blood = hit.transform.GetComponent <EnemyBlood>(); if (blood) { blood.ShowBloodSplash(enemyEntity.MobileEnemy.BloodIndex, hit.point); } // Knock back enemy based on damage and enemy weight if (enemyMotor) { if (enemyMotor.KnockBackSpeed <= (5 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10)) && entityBehaviour.EntityType == EntityTypes.EnemyClass || enemyEntity.MobileEnemy.Weight > 0) { float enemyWeight = enemyEntity.GetWeightInClassicUnits(); float tenTimesDamage = damage * 10; float twoTimesDamage = damage * 2; float knockBackAmount = ((tenTimesDamage - enemyWeight) * 256) / (enemyWeight + tenTimesDamage) * twoTimesDamage; float knockBackSpeed = (tenTimesDamage / enemyWeight) * (twoTimesDamage - (knockBackAmount / 256)); knockBackSpeed /= (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10); if (knockBackSpeed < (15 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10))) { knockBackSpeed = (15 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10)); } enemyMotor.KnockBackSpeed = knockBackSpeed; enemyMotor.KnockBackDirection = direction; } } if (DaggerfallUnity.Settings.CombatVoices && entityBehaviour.EntityType == EntityTypes.EnemyClass && UnityEngine.Random.Range(1, 101) <= 40) { Genders gender; if (entityMobileUnit.Summary.Enemy.Gender == MobileGender.Male || enemyEntity.MobileEnemy.ID == (int)MobileTypes.Knight_CityWatch) { gender = Genders.Male; } else { gender = Genders.Female; } bool heavyDamage = damage >= enemyEntity.MaxHealth / 4; enemySounds.PlayCombatVoice(gender, false, heavyDamage); } } else { if ((!arrowHit && !enemyEntity.MobileEnemy.ParrySounds) || strikingWeapon == null) { ScreenWeapon.PlaySwingSound(); } else if (enemyEntity.MobileEnemy.ParrySounds) { enemySounds.PlayParrySound(); } } // Remove health enemyEntity.DecreaseHealth(damage); // Assign "cast when strikes" to target entity if (strikingWeapon != null && strikingWeapon.IsEnchanted) { EntityEffectManager enemyEffectManager = enemyEntity.EntityBehaviour.GetComponent <EntityEffectManager>(); if (enemyEffectManager) { enemyEffectManager.StrikeWithItem(strikingWeapon, GameManager.Instance.PlayerEntityBehaviour); } } // Make foe attack their aggressor // Currently this is just player, but should be expanded later // for a wider variety of behaviours if (enemyMotor) { // Make enemies in an area aggressive if player attacked a non-hostile one. if (!enemyMotor.IsHostile) { GameManager.Instance.MakeEnemiesHostile(); } enemyMotor.MakeEnemyHostileToAttacker(GameManager.Instance.PlayerEntityBehaviour); } return(true); } } // Check if hit a mobile NPC MobilePersonNPC mobileNpc = hit.transform.GetComponent <MobilePersonNPC>(); if (mobileNpc) { EnemyBlood blood = hit.transform.GetComponent <EnemyBlood>(); if (blood) { blood.ShowBloodSplash(0, hit.point); } mobileNpc.Motor.gameObject.SetActive(false); playerEntity.TallyCrimeGuildRequirements(false, 5); // TODO: LOS check from each townsperson. If seen, register crime and start spawning guards as below. playerEntity.CrimeCommitted = PlayerEntity.Crimes.Murder; playerEntity.SpawnCityGuards(true); } return(false); }
// Returns true if hit an enemy entity public bool WeaponDamage(DaggerfallUnityItem strikingWeapon, bool arrowHit, bool arrowSummoned, Transform hitTransform, Vector3 impactPosition, Vector3 direction) { DaggerfallEntityBehaviour entityBehaviour = hitTransform.GetComponent <DaggerfallEntityBehaviour>(); var entityMobileUnit = hitTransform.GetComponentInChildren <MobileUnit>(); EnemyMotor enemyMotor = hitTransform.GetComponent <EnemyMotor>(); EnemySounds enemySounds = hitTransform.GetComponent <EnemySounds>(); // Check if hit a mobile NPC MobilePersonNPC mobileNpc = hitTransform.GetComponent <MobilePersonNPC>(); if (mobileNpc) { if (!mobileNpc.IsGuard) { EnemyBlood blood = hitTransform.GetComponent <EnemyBlood>(); if (blood) { blood.ShowBloodSplash(0, impactPosition); } mobileNpc.Motor.gameObject.SetActive(false); playerEntity.TallyCrimeGuildRequirements(false, 5); playerEntity.CrimeCommitted = PlayerEntity.Crimes.Murder; playerEntity.SpawnCityGuards(true); // Allow custom race handling of weapon hit against mobile NPCs, e.g. vampire feeding or lycanthrope killing if (entityBehaviour) { entityBehaviour.Entity.SetHealth(0); RacialOverrideEffect racialOverride = GameManager.Instance.PlayerEffectManager.GetRacialOverrideEffect(); if (racialOverride != null) { racialOverride.OnWeaponHitEntity(GameManager.Instance.PlayerEntity, entityBehaviour.Entity); } } } else { playerEntity.CrimeCommitted = PlayerEntity.Crimes.Assault; GameObject guard = playerEntity.SpawnCityGuard(mobileNpc.transform.position, mobileNpc.transform.forward); entityBehaviour = guard.GetComponent <DaggerfallEntityBehaviour>(); entityMobileUnit = guard.GetComponentInChildren <MobileUnit>(); enemyMotor = guard.GetComponent <EnemyMotor>(); enemySounds = guard.GetComponent <EnemySounds>(); } mobileNpc.Motor.gameObject.SetActive(false); } // Check if hit an entity and remove health if (entityBehaviour) { if (entityBehaviour.EntityType == EntityTypes.EnemyMonster || entityBehaviour.EntityType == EntityTypes.EnemyClass) { EnemyEntity enemyEntity = entityBehaviour.Entity as EnemyEntity; // Calculate damage int animTime = (int)(ScreenWeapon.GetAnimTime() * 1000); // Get animation time, converted to ms. bool isEnemyFacingAwayFromPlayer = entityMobileUnit.IsBackFacing && entityMobileUnit.EnemyState != MobileStates.SeducerTransform1 && entityMobileUnit.EnemyState != MobileStates.SeducerTransform2; int damage = FormulaHelper.CalculateAttackDamage(playerEntity, enemyEntity, isEnemyFacingAwayFromPlayer, animTime, strikingWeapon); // Break any "normal power" concealment effects on player if (playerEntity.IsMagicallyConcealedNormalPower && damage > 0) { EntityEffectManager.BreakNormalPowerConcealmentEffects(GameManager.Instance.PlayerEntityBehaviour); } // Add arrow to target's inventory if (arrowHit && !arrowSummoned) { DaggerfallUnityItem arrow = ItemBuilder.CreateItem(ItemGroups.Weapons, (int)Weapons.Arrow); enemyEntity.Items.AddItem(arrow); } // Play hit sound and trigger blood splash at hit point if (damage > 0) { if (usingRightHand) { enemySounds.PlayHitSound(currentRightHandWeapon); } else { enemySounds.PlayHitSound(currentLeftHandWeapon); } EnemyBlood blood = hitTransform.GetComponent <EnemyBlood>(); if (blood) { blood.ShowBloodSplash(enemyEntity.MobileEnemy.BloodIndex, impactPosition); } // Knock back enemy based on damage and enemy weight if (enemyMotor) { if (enemyMotor.KnockbackSpeed <= (5 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10)) && entityBehaviour.EntityType == EntityTypes.EnemyClass || enemyEntity.MobileEnemy.Weight > 0) { float enemyWeight = enemyEntity.GetWeightInClassicUnits(); float tenTimesDamage = damage * 10; float twoTimesDamage = damage * 2; float knockBackAmount = ((tenTimesDamage - enemyWeight) * 256) / (enemyWeight + tenTimesDamage) * twoTimesDamage; float KnockbackSpeed = (tenTimesDamage / enemyWeight) * (twoTimesDamage - (knockBackAmount / 256)); KnockbackSpeed /= (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10); if (KnockbackSpeed < (15 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10))) { KnockbackSpeed = (15 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10)); } enemyMotor.KnockbackSpeed = KnockbackSpeed; enemyMotor.KnockbackDirection = direction; } } if (DaggerfallUnity.Settings.CombatVoices && entityBehaviour.EntityType == EntityTypes.EnemyClass && Dice100.SuccessRoll(40)) { Genders gender; if (entityMobileUnit.Enemy.Gender == MobileGender.Male || enemyEntity.MobileEnemy.ID == (int)MobileTypes.Knight_CityWatch) { gender = Genders.Male; } else { gender = Genders.Female; } bool heavyDamage = damage >= enemyEntity.MaxHealth / 4; enemySounds.PlayCombatVoice(gender, false, heavyDamage); } } else { if ((!arrowHit && !enemyEntity.MobileEnemy.ParrySounds) || strikingWeapon == null) { ScreenWeapon.PlaySwingSound(); } else if (enemyEntity.MobileEnemy.ParrySounds) { enemySounds.PlayParrySound(); } } // Handle weapon striking enchantments - this could change damage amount if (strikingWeapon != null && strikingWeapon.IsEnchanted) { EntityEffectManager effectManager = GetComponent <EntityEffectManager>(); if (effectManager) { damage = effectManager.DoItemEnchantmentPayloads(EnchantmentPayloadFlags.Strikes, strikingWeapon, GameManager.Instance.PlayerEntity.Items, enemyEntity.EntityBehaviour, damage); } strikingWeapon.RaiseOnWeaponStrikeEvent(entityBehaviour, damage); } // Remove health enemyEntity.DecreaseHealth(damage); // Handle attack from player enemyEntity.EntityBehaviour.HandleAttackFromSource(GameManager.Instance.PlayerEntityBehaviour); // Allow custom race handling of weapon hit against enemies, e.g. vampire feeding or lycanthrope killing RacialOverrideEffect racialOverride = GameManager.Instance.PlayerEffectManager.GetRacialOverrideEffect(); if (racialOverride != null) { racialOverride.OnWeaponHitEntity(GameManager.Instance.PlayerEntity, entityBehaviour.Entity); } return(true); } } return(false); }
private void WeaponDamage(FPSWeapon weapon, out bool hitEnemy) { hitEnemy = false; if (!mainCamera || !weapon) { return; } // Fire ray along player facing using weapon range RaycastHit hit; Ray ray = new Ray(mainCamera.transform.position, mainCamera.transform.forward); if (Physics.SphereCast(ray, SphereCastRadius, out hit, weapon.Reach - SphereCastRadius)) { // Check if hit has an DaggerfallAction component DaggerfallAction action = hit.transform.gameObject.GetComponent <DaggerfallAction>(); if (action) { action.Receive(player, DaggerfallAction.TriggerTypes.Attack); } // Check if hit has an DaggerfallActionDoor component DaggerfallActionDoor actionDoor = hit.transform.gameObject.GetComponent <DaggerfallActionDoor>(); if (actionDoor) { actionDoor.AttemptBash(); return; } // Check if hit an entity and remove health DaggerfallEntityBehaviour entityBehaviour = hit.transform.GetComponent <DaggerfallEntityBehaviour>(); DaggerfallMobileUnit entityMobileUnit = hit.transform.GetComponentInChildren <DaggerfallMobileUnit>(); if (entityBehaviour) { if (entityBehaviour.EntityType == EntityTypes.EnemyMonster || entityBehaviour.EntityType == EntityTypes.EnemyClass) { EnemyEntity enemyEntity = entityBehaviour.Entity as EnemyEntity; // Calculate damage int damage; if (usingRightHand) { damage = FormulaHelper.CalculateAttackDamage(playerEntity, enemyEntity, (int)(EquipSlots.RightHand), entityMobileUnit.Summary.AnimStateRecord); } else { damage = FormulaHelper.CalculateAttackDamage(playerEntity, enemyEntity, (int)(EquipSlots.LeftHand), entityMobileUnit.Summary.AnimStateRecord); } EnemyMotor enemyMotor = hit.transform.GetComponent <EnemyMotor>(); EnemySounds enemySounds = hit.transform.GetComponent <EnemySounds>(); // Play arrow sound and add arrow to target's inventory if (weapon.WeaponType == WeaponTypes.Bow) { enemySounds.PlayArrowSound(); DaggerfallUnityItem arrow = ItemBuilder.CreateItem(ItemGroups.Weapons, (int)Weapons.Arrow); enemyEntity.Items.AddItem(arrow); } // Play hit sound and trigger blood splash at hit point if (damage > 0) { if (usingRightHand) { enemySounds.PlayHitSound(currentRightHandWeapon); } else { enemySounds.PlayHitSound(currentLeftHandWeapon); } EnemyBlood blood = hit.transform.GetComponent <EnemyBlood>(); if (blood) { blood.ShowBloodSplash(enemyEntity.MobileEnemy.BloodIndex, hit.point); } // Knock back enemy based on damage and enemy weight if (enemyMotor) { if (enemyMotor.KnockBackSpeed <= (5 / (PlayerMotor.classicToUnitySpeedUnitRatio / 10)) && entityBehaviour.EntityType == EntityTypes.EnemyClass || enemyEntity.MobileEnemy.Weight > 0) { float enemyWeight = enemyEntity.GetWeightInClassicUnits(); float tenTimesDamage = damage * 10; float twoTimesDamage = damage * 2; float knockBackAmount = ((tenTimesDamage - enemyWeight) * 256) / (enemyWeight + tenTimesDamage) * twoTimesDamage; float knockBackSpeed = (tenTimesDamage / enemyWeight) * (twoTimesDamage - (knockBackAmount / 256)); knockBackSpeed /= (PlayerMotor.classicToUnitySpeedUnitRatio / 10); if (knockBackSpeed < (15 / (PlayerMotor.classicToUnitySpeedUnitRatio / 10))) { knockBackSpeed = (15 / (PlayerMotor.classicToUnitySpeedUnitRatio / 10)); } enemyMotor.KnockBackSpeed = knockBackSpeed; enemyMotor.KnockBackDirection = mainCamera.transform.forward; } } } else { if ((weapon.WeaponType != WeaponTypes.Bow && !enemyEntity.MobileEnemy.ParrySounds) || weapon.WeaponType == WeaponTypes.Melee) { weapon.PlaySwingSound(); } else if (enemyEntity.MobileEnemy.ParrySounds) { enemySounds.PlayParrySound(); } } // Remove health enemyEntity.DecreaseHealth(damage); hitEnemy = true; // Make foe attack their aggressor // Currently this is just player, but should be expanded later // for a wider variety of behaviours if (enemyMotor) { // Make enemies in an area aggressive if player attacked a non-hostile one. if (!enemyMotor.IsHostile) { GameManager.Instance.MakeEnemiesHostile(); } enemyMotor.MakeEnemyHostileToPlayer(gameObject); } } } // Check if hit a mobile NPC MobilePersonNPC mobileNpc = hit.transform.GetComponent <MobilePersonNPC>(); if (mobileNpc) { // TODO: Create blood splash. mobileNpc.Motor.gameObject.SetActive(false); //GameManager.Instance.PlayerEntity.TallyCrimeGuildRequirements(false, 5); } } }
void Start() { motor = GetComponent<EnemyMotor>(); senses = GetComponent<EnemySenses>(); sounds = GetComponent<EnemySounds>(); mobile = GetComponentInChildren<DaggerfallMobileUnit>(); entityBehaviour = GetComponent<DaggerfallEntityBehaviour>(); }
private void WeaponDamage(FPSWeapon weapon, out bool hitEnemy) { hitEnemy = false; if (!mainCamera || !weapon) { return; } // Fire ray along player facing using weapon range RaycastHit hit; Ray ray = new Ray(mainCamera.transform.position, mainCamera.transform.forward); if (Physics.SphereCast(ray, SphereCastRadius, out hit, weapon.Reach - SphereCastRadius)) { // Check if hit has an DaggerfallAction component DaggerfallAction action = hit.transform.gameObject.GetComponent <DaggerfallAction>(); if (action) { action.Receive(player, DaggerfallAction.TriggerTypes.Attack); } // Check if hit has an DaggerfallActionDoor component DaggerfallActionDoor actionDoor = hit.transform.gameObject.GetComponent <DaggerfallActionDoor>(); if (actionDoor) { actionDoor.AttemptBash(); return; } // Check if hit an entity and remove health DaggerfallEntityBehaviour entityBehaviour = hit.transform.GetComponent <DaggerfallEntityBehaviour>(); if (entityBehaviour) { if (entityBehaviour.EntityType == EntityTypes.EnemyMonster || entityBehaviour.EntityType == EntityTypes.EnemyClass) { EnemyEntity enemyEntity = entityBehaviour.Entity as EnemyEntity; // Calculate damage int damage = FormulaHelper.CalculateWeaponDamage(playerEntity, enemyEntity, weapon); // Play hit sound and trigger blood splash at hit point if (damage > 0) { weapon.PlayHitSound(); EnemyBlood blood = hit.transform.GetComponent <EnemyBlood>(); if (blood) { blood.ShowBloodSplash(enemyEntity.MobileEnemy.BloodIndex, hit.point); } } else { if (!enemyEntity.MobileEnemy.ParrySounds || weapon.WeaponType == WeaponTypes.Melee) { weapon.PlaySwingSound(); } else { weapon.PlayParrySound(); } } // Remove health enemyEntity.DecreaseHealth(damage); hitEnemy = true; // Make foe attack their aggressor // Currently this is just player, but should be expanded later // for a wider variety of behaviours EnemyMotor enemyMotor = hit.transform.GetComponent <EnemyMotor>(); if (enemyMotor) { // Make enemies in an area aggressive if player attacked a non-hostile one. if (!enemyMotor.IsHostile) { GameManager.Instance.MakeEnemiesHostile(); } enemyMotor.MakeEnemyHostileToPlayer(gameObject); } } } // Check if hit a mobile NPC MobilePersonNPC mobileNpc = hit.transform.GetComponent <MobilePersonNPC>(); if (mobileNpc) { // TODO: Create blood splash. weapon.PlayHitSound(); mobileNpc.Motor.gameObject.SetActive(false); //GameManager.Instance.PlayerEntity.TallyCrimeGuildRequirements(false, 5); } } }
void Start() { motor = GetComponent<EnemyMotor>(); mobile = GetComponentInChildren<DaggerfallMobileUnit>(); blood = GetComponent<EnemyBlood>(); }
private int ApplyDamageToNonPlayer(Items.DaggerfallUnityItem weapon, Vector3 direction, bool bowAttack = false) { if (senses.Target == null) { return(0); } // TODO: Merge with hit code in WeaponManager to eliminate duplicate code EnemyEntity entity = entityBehaviour.Entity as EnemyEntity; EnemyEntity targetEntity = senses.Target.Entity as EnemyEntity; EnemySounds targetSounds = senses.Target.GetComponent <EnemySounds>(); EnemyMotor targetMotor = senses.Target.transform.GetComponent <EnemyMotor>(); // Calculate damage damage = FormulaHelper.CalculateAttackDamage(entity, targetEntity, false, 0, weapon); // Break any "normal power" concealment effects on enemy if (entity.IsMagicallyConcealedNormalPower && damage > 0) { EntityEffectManager.BreakNormalPowerConcealmentEffects(entityBehaviour); } // Play hit sound and trigger blood splash at hit point if (damage > 0) { targetSounds.PlayHitSound(weapon); EnemyBlood blood = senses.Target.transform.GetComponent <EnemyBlood>(); CharacterController targetController = senses.Target.transform.GetComponent <CharacterController>(); Vector3 bloodPos = senses.Target.transform.position + targetController.center; bloodPos.y += targetController.height / 8; if (blood) { blood.ShowBloodSplash(targetEntity.MobileEnemy.BloodIndex, bloodPos); } // Knock back enemy based on damage and enemy weight if (targetMotor && (targetMotor.KnockbackSpeed <= (5 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10)) && (entityBehaviour.EntityType == EntityTypes.EnemyClass || targetEntity.MobileEnemy.Weight > 0))) { float enemyWeight = targetEntity.GetWeightInClassicUnits(); float tenTimesDamage = damage * 10; float twoTimesDamage = damage * 2; float knockBackAmount = ((tenTimesDamage - enemyWeight) * 256) / (enemyWeight + tenTimesDamage) * twoTimesDamage; float KnockbackSpeed = (tenTimesDamage / enemyWeight) * (twoTimesDamage - (knockBackAmount / 256)); KnockbackSpeed /= (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10); if (KnockbackSpeed < (15 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10))) { KnockbackSpeed = (15 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10)); } targetMotor.KnockbackSpeed = KnockbackSpeed; targetMotor.KnockbackDirection = direction; } if (DaggerfallUnity.Settings.CombatVoices && senses.Target.EntityType == EntityTypes.EnemyClass && Dice100.SuccessRoll(40)) { DaggerfallMobileUnit targetMobileUnit = senses.Target.GetComponentInChildren <DaggerfallMobileUnit>(); Genders gender; if (targetMobileUnit.Summary.Enemy.Gender == MobileGender.Male || targetEntity.MobileEnemy.ID == (int)MobileTypes.Knight_CityWatch) { gender = Genders.Male; } else { gender = Genders.Female; } targetSounds.PlayCombatVoice(gender, false, damage >= targetEntity.MaxHealth / 4); } } else { WeaponTypes weaponType = WeaponTypes.Melee; if (weapon != null) { weaponType = DaggerfallUnity.Instance.ItemHelper.ConvertItemToAPIWeaponType(weapon); } if ((!bowAttack && !targetEntity.MobileEnemy.ParrySounds) || weaponType == WeaponTypes.Melee) { sounds.PlayMissSound(weapon); } else if (targetEntity.MobileEnemy.ParrySounds) { targetSounds.PlayParrySound(); } } // Handle Strikes payload from enemy to non-player target - this could change damage amount if (weapon != null && weapon.IsEnchanted) { EntityEffectManager effectManager = GetComponent <EntityEffectManager>(); if (effectManager) { damage = effectManager.DoItemEnchantmentPayloads(EnchantmentPayloadFlags.Strikes, weapon, entity.Items, targetEntity.EntityBehaviour, damage); } } targetEntity.DecreaseHealth(damage); if (targetMotor) { targetMotor.MakeEnemyHostileToAttacker(entityBehaviour); } return(damage); }
// Returns true if hit an enemy entity public bool WeaponDamage(RaycastHit hit, Vector3 direction, Collider arrowHitCollider = null, bool arrowHit = false) { DaggerfallUnityItem strikingWeapon = null; if (!arrowHit) { // Check if hit has an DaggerfallAction component DaggerfallAction action = hit.transform.gameObject.GetComponent <DaggerfallAction>(); if (action) { action.Receive(player, DaggerfallAction.TriggerTypes.Attack); } // Check if hit has an DaggerfallActionDoor component DaggerfallActionDoor actionDoor = hit.transform.gameObject.GetComponent <DaggerfallActionDoor>(); if (actionDoor) { actionDoor.AttemptBash(true); return(false); } // Check if player hit a static exterior door if (GameManager.Instance.PlayerActivate.AttemptExteriorDoorBash(hit)) { return(false); } } // Set up for use below DaggerfallEntityBehaviour entityBehaviour = null; DaggerfallMobileUnit entityMobileUnit = null; EnemyMotor enemyMotor = null; EnemySounds enemySounds = null; if (!arrowHit) { entityBehaviour = hit.transform.GetComponent <DaggerfallEntityBehaviour>(); entityMobileUnit = hit.transform.GetComponentInChildren <DaggerfallMobileUnit>(); enemyMotor = hit.transform.GetComponent <EnemyMotor>(); enemySounds = hit.transform.GetComponent <EnemySounds>(); } else if (arrowHitCollider != null) { entityBehaviour = arrowHitCollider.gameObject.transform.GetComponent <DaggerfallEntityBehaviour>(); entityMobileUnit = arrowHitCollider.gameObject.transform.GetComponentInChildren <DaggerfallMobileUnit>(); enemyMotor = arrowHitCollider.gameObject.transform.GetComponent <EnemyMotor>(); enemySounds = arrowHitCollider.gameObject.transform.GetComponent <EnemySounds>(); } // Check if hit a mobile NPC MobilePersonNPC mobileNpc = null; if (!arrowHit) { mobileNpc = hit.transform.GetComponent <MobilePersonNPC>(); } else if (arrowHitCollider != null) { mobileNpc = arrowHitCollider.gameObject.transform.GetComponent <MobilePersonNPC>(); } if (mobileNpc) { if (!mobileNpc.Billboard.IsUsingGuardTexture) { EnemyBlood blood = null; if (!arrowHit) { blood = hit.transform.GetComponent <EnemyBlood>(); } else if (arrowHitCollider != null) { blood = arrowHitCollider.gameObject.transform.GetComponent <EnemyBlood>(); } if (blood) { if (!arrowHit) { blood.ShowBloodSplash(0, hit.point); } else { blood.ShowBloodSplash(0, arrowHitCollider.gameObject.transform.position); } } mobileNpc.Motor.gameObject.SetActive(false); playerEntity.TallyCrimeGuildRequirements(false, 5); playerEntity.CrimeCommitted = PlayerEntity.Crimes.Murder; playerEntity.SpawnCityGuards(true); // Allow custom race handling of weapon hit against mobile NPCs, e.g. vampire feeding or lycanthrope killing if (entityBehaviour) { entityBehaviour.Entity.SetHealth(0); RacialOverrideEffect racialOverride = GameManager.Instance.PlayerEffectManager.GetRacialOverrideEffect(); if (racialOverride != null) { racialOverride.OnWeaponHitEntity(GameManager.Instance.PlayerEntity, entityBehaviour.Entity); } } } else { playerEntity.CrimeCommitted = PlayerEntity.Crimes.Assault; GameObject guard = playerEntity.SpawnCityGuard(mobileNpc.transform.position, mobileNpc.transform.forward); entityBehaviour = guard.GetComponent <DaggerfallEntityBehaviour>(); entityMobileUnit = guard.GetComponentInChildren <DaggerfallMobileUnit>(); enemyMotor = guard.GetComponent <EnemyMotor>(); enemySounds = guard.GetComponent <EnemySounds>(); } mobileNpc.Motor.gameObject.SetActive(false); } // Check if hit an entity and remove health if (entityBehaviour) { if (entityBehaviour.EntityType == EntityTypes.EnemyMonster || entityBehaviour.EntityType == EntityTypes.EnemyClass) { EnemyEntity enemyEntity = entityBehaviour.Entity as EnemyEntity; // Calculate damage int damage; if (!arrowHit) { if (usingRightHand) { strikingWeapon = currentRightHandWeapon; } else { strikingWeapon = currentLeftHandWeapon; } } else { strikingWeapon = lastBowUsed; } damage = FormulaHelper.CalculateAttackDamage(playerEntity, enemyEntity, strikingWeapon, entityMobileUnit.Summary.AnimStateRecord); // Break any "normal power" concealment effects on player if (playerEntity.IsMagicallyConcealedNormalPower && damage > 0) { EntityEffectManager.BreakNormalPowerConcealmentEffects(GameManager.Instance.PlayerEntityBehaviour); } // Play arrow sound and add arrow to target's inventory if (arrowHit) { DaggerfallUnityItem arrow = ItemBuilder.CreateItem(ItemGroups.Weapons, (int)Weapons.Arrow); enemyEntity.Items.AddItem(arrow); } // Play hit sound and trigger blood splash at hit point if (damage > 0) { if (usingRightHand) { enemySounds.PlayHitSound(currentRightHandWeapon); } else { enemySounds.PlayHitSound(currentLeftHandWeapon); } EnemyBlood blood = null; if (!arrowHit) { blood = hit.transform.GetComponent <EnemyBlood>(); } else if (arrowHitCollider != null) { blood = arrowHitCollider.gameObject.transform.GetComponent <EnemyBlood>(); } if (blood) { blood.ShowBloodSplash(enemyEntity.MobileEnemy.BloodIndex, hit.point); } // Knock back enemy based on damage and enemy weight if (enemyMotor) { if (enemyMotor.KnockbackSpeed <= (5 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10)) && entityBehaviour.EntityType == EntityTypes.EnemyClass || enemyEntity.MobileEnemy.Weight > 0) { float enemyWeight = enemyEntity.GetWeightInClassicUnits(); float tenTimesDamage = damage * 10; float twoTimesDamage = damage * 2; float knockBackAmount = ((tenTimesDamage - enemyWeight) * 256) / (enemyWeight + tenTimesDamage) * twoTimesDamage; float KnockbackSpeed = (tenTimesDamage / enemyWeight) * (twoTimesDamage - (knockBackAmount / 256)); KnockbackSpeed /= (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10); if (KnockbackSpeed < (15 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10))) { KnockbackSpeed = (15 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10)); } enemyMotor.KnockbackSpeed = KnockbackSpeed; enemyMotor.KnockbackDirection = direction; } } if (DaggerfallUnity.Settings.CombatVoices && entityBehaviour.EntityType == EntityTypes.EnemyClass && Dice100.SuccessRoll(40)) { Genders gender; if (entityMobileUnit.Summary.Enemy.Gender == MobileGender.Male || enemyEntity.MobileEnemy.ID == (int)MobileTypes.Knight_CityWatch) { gender = Genders.Male; } else { gender = Genders.Female; } bool heavyDamage = damage >= enemyEntity.MaxHealth / 4; enemySounds.PlayCombatVoice(gender, false, heavyDamage); } } else { if ((!arrowHit && !enemyEntity.MobileEnemy.ParrySounds) || strikingWeapon == null) { ScreenWeapon.PlaySwingSound(); } else if (enemyEntity.MobileEnemy.ParrySounds) { enemySounds.PlayParrySound(); } } // Handle weapon striking enchantments - this could change damage amount if (strikingWeapon != null && strikingWeapon.IsEnchanted) { EntityEffectManager effectManager = GetComponent <EntityEffectManager>(); if (effectManager) { damage = effectManager.DoItemEnchantmentPayloads(EnchantmentPayloadFlags.Strikes, strikingWeapon, GameManager.Instance.PlayerEntity.Items, enemyEntity.EntityBehaviour, damage); } strikingWeapon.RaiseOnWeaponStrikeEvent(entityBehaviour, damage); } // Remove health enemyEntity.DecreaseHealth(damage); // Make foe attack their aggressor // Currently this is just player, but should be expanded later // for a wider variety of behaviours if (enemyMotor) { // Make enemies in an area aggressive if player attacked a non-hostile one. if (!enemyMotor.IsHostile) { GameManager.Instance.MakeEnemiesHostile(); } enemyMotor.MakeEnemyHostileToAttacker(GameManager.Instance.PlayerEntityBehaviour); } if (enemyEntity.MobileEnemy.ID == (int)MobileTypes.Knight_CityWatch && enemyEntity.CurrentHealth <= 0) { playerEntity.TallyCrimeGuildRequirements(false, 1); playerEntity.CrimeCommitted = PlayerEntity.Crimes.Murder; } // Allow custom race handling of weapon hit against enemies, e.g. vampire feeding or lycanthrope killing RacialOverrideEffect racialOverride = GameManager.Instance.PlayerEffectManager.GetRacialOverrideEffect(); if (racialOverride != null) { racialOverride.OnWeaponHitEntity(GameManager.Instance.PlayerEntity, entityBehaviour.Entity); } return(true); } } return(false); }
void FixedUpdate() { classicUpdateTimer += Time.deltaTime; if (classicUpdateTimer >= PlayerEntity.ClassicUpdateInterval) { classicUpdateTimer = 0; classicUpdate = true; } else { classicUpdate = false; } if (Player != null) { Vector3 toPlayer = Player.transform.position - transform.position; directionToPlayer = toPlayer.normalized; distanceToPlayer = toPlayer.magnitude; playerInSight = CanSeePlayer(); // Classic stealth mechanics would be interfered with by hearing, so only enable // hearing if the enemy has detected the player. If player has been seen we can omit hearing. if (detectedPlayer && !playerInSight) { playerInEarshot = CanHearPlayer(); } else { playerInEarshot = false; } // Note: In classic an enemy can continue to track the player as long as their // giveUpTimer is > 0. Since the timer is reset to 200 on every detection this // would make chameleon and shade essentially useless, since the enemy is sure // to detect the player during one of the many AI updates. Here, the enemy has to // successfully see through the illusion spell each classic update to continue // to know where the player is. if (classicUpdate) { blockedByIllusionEffect = BlockedByIllusionEffect(); if (lastHadLOSTimer > 0) { lastHadLOSTimer--; } } if (!blockedByIllusionEffect && (playerInSight || playerInEarshot)) { detectedPlayer = true; lastKnownPlayerPos = Player.transform.position; lastHadLOSTimer = 200f; } else if (!blockedByIllusionEffect && StealthCheck()) { detectedPlayer = true; // Only get the player's location from the stealth check if we haven't had // actual LOS for a while. This gives better pursuit behavior since enemies // will go to the last spot they saw the player instead of walking into walls. if (lastHadLOSTimer <= 0) { lastKnownPlayerPos = Player.transform.position; } } else { detectedPlayer = false; } if (detectedPlayer && !hasEncounteredPlayer) { hasEncounteredPlayer = true; // Check appropriate language skill to see if player can pacify enemy DaggerfallEntityBehaviour entityBehaviour = GetComponent <DaggerfallEntityBehaviour>(); EnemyMotor motor = GetComponent <EnemyMotor>(); if (entityBehaviour && motor && (entityBehaviour.EntityType == EntityTypes.EnemyMonster || entityBehaviour.EntityType == EntityTypes.EnemyClass)) { EnemyEntity enemyEntity = entityBehaviour.Entity as EnemyEntity; DFCareer.Skills languageSkill = enemyEntity.GetLanguageSkill(); if (languageSkill != DFCareer.Skills.None) { PlayerEntity player = GameManager.Instance.PlayerEntity; if (FormulaHelper.CalculateEnemyPacification(player, languageSkill)) { motor.IsHostile = false; DaggerfallUI.AddHUDText(HardStrings.languagePacified.Replace("%e", enemyEntity.Name).Replace("%s", languageSkill.ToString()), 5); player.TallySkill(languageSkill, 3); // BCHG: increased skill uses from (assumed) 1 in classic on success to make raising language skills easier } else if (languageSkill != DFCareer.Skills.Etiquette && languageSkill != DFCareer.Skills.Streetwise) { player.TallySkill(languageSkill, 1); } } } } } }
void Start() { motor = GetComponent <EnemyMotor>(); mobile = GetComponentInChildren <MobileUnit>(); blood = GetComponent <EnemyBlood>(); }
// Player has clicked on a pickpocket target in steal mode void Pickpocket(DaggerfallEntityBehaviour target = null) { const int foundNothingValuableTextId = 8999; PlayerEntity player = GameManager.Instance.PlayerEntity; EnemyEntity enemyEntity = null; if (target != null) { enemyEntity = target.Entity as EnemyEntity; } player.TallySkill(DFCareer.Skills.Pickpocket, 1); int chance = Formulas.FormulaHelper.CalculatePickpocketingChance(player, enemyEntity); if (UnityEngine.Random.Range(0, 101) <= chance) { if (UnityEngine.Random.Range(0, 101) >= 33) { int pinchedGoldPieces = UnityEngine.Random.Range(0, 6) + 1; player.GoldPieces += pinchedGoldPieces; string gotGold; if (pinchedGoldPieces == 1) { // Classic doesn't have this string, it only has the plural one gotGold = HardStrings.youPinchedGoldPiece; } else { gotGold = HardStrings.youPinchedGoldPieces; gotGold = gotGold.Replace("%d", pinchedGoldPieces.ToString()); } DaggerfallUI.MessageBox(gotGold); //player.TallyCrimeGuildRequirements(true, 1); } else { string noGoldFound = DaggerfallUnity.Instance.TextProvider.GetRandomText(foundNothingValuableTextId); DaggerfallUI.MessageBox(noGoldFound, true); } } else { string notSuccessfulMessage = HardStrings.youAreNotSuccessful; DaggerfallUI.Instance.PopupMessage(notSuccessfulMessage); // Make enemies in an area aggressive if player failed to pickpocket a non-hostile one. EnemyMotor enemyMotor = null; if (target != null) { enemyMotor = target.GetComponent <EnemyMotor>(); } if (enemyMotor) { if (!enemyMotor.IsHostile) { GameManager.Instance.MakeEnemiesHostile(); } enemyMotor.MakeEnemyHostileToPlayer(gameObject); } } }
private void WeaponDamage(FPSWeapon weapon, out bool hitEnemy) { hitEnemy = false; DaggerfallUnityItem strikingWeapon = null; if (!mainCamera || !weapon) { return; } // Fire ray along player facing using weapon range // Origin point of ray is set back slightly to fix issue where strikes against enemy capsules touching player capsule do not connect RaycastHit hit; Ray ray = new Ray(mainCamera.transform.position + -mainCamera.transform.forward * 0.1f, mainCamera.transform.forward); if (Physics.SphereCast(ray, SphereCastRadius, out hit, weapon.Reach - SphereCastRadius)) { // Check if hit has an DaggerfallAction component DaggerfallAction action = hit.transform.gameObject.GetComponent <DaggerfallAction>(); if (action) { action.Receive(player, DaggerfallAction.TriggerTypes.Attack); } // Check if hit has an DaggerfallActionDoor component DaggerfallActionDoor actionDoor = hit.transform.gameObject.GetComponent <DaggerfallActionDoor>(); if (actionDoor) { actionDoor.AttemptBash(); return; } // Check if hit an entity and remove health DaggerfallEntityBehaviour entityBehaviour = hit.transform.GetComponent <DaggerfallEntityBehaviour>(); DaggerfallMobileUnit entityMobileUnit = hit.transform.GetComponentInChildren <DaggerfallMobileUnit>(); if (entityBehaviour) { if (entityBehaviour.EntityType == EntityTypes.EnemyMonster || entityBehaviour.EntityType == EntityTypes.EnemyClass) { EnemyEntity enemyEntity = entityBehaviour.Entity as EnemyEntity; // Calculate damage int damage; if (usingRightHand) { damage = FormulaHelper.CalculateAttackDamage(playerEntity, enemyEntity, (int)(EquipSlots.RightHand), entityMobileUnit.Summary.AnimStateRecord); strikingWeapon = currentRightHandWeapon; } else { damage = FormulaHelper.CalculateAttackDamage(playerEntity, enemyEntity, (int)(EquipSlots.LeftHand), entityMobileUnit.Summary.AnimStateRecord); strikingWeapon = currentLeftHandWeapon; } // Break any "normal power" concealment effects on player if (playerEntity.IsMagicallyConcealedNormalPower && damage > 0) { EntityEffectManager.BreakNormalPowerConcealmentEffects(GameManager.Instance.PlayerEntityBehaviour); } EnemyMotor enemyMotor = hit.transform.GetComponent <EnemyMotor>(); EnemySounds enemySounds = hit.transform.GetComponent <EnemySounds>(); // Play arrow sound and add arrow to target's inventory if (weapon.WeaponType == WeaponTypes.Bow) { enemySounds.PlayArrowSound(); DaggerfallUnityItem arrow = ItemBuilder.CreateItem(ItemGroups.Weapons, (int)Weapons.Arrow); enemyEntity.Items.AddItem(arrow); } // Play hit sound and trigger blood splash at hit point if (damage > 0) { if (usingRightHand) { enemySounds.PlayHitSound(currentRightHandWeapon); } else { enemySounds.PlayHitSound(currentLeftHandWeapon); } EnemyBlood blood = hit.transform.GetComponent <EnemyBlood>(); if (blood) { blood.ShowBloodSplash(enemyEntity.MobileEnemy.BloodIndex, hit.point); } // Knock back enemy based on damage and enemy weight if (enemyMotor) { if (enemyMotor.KnockBackSpeed <= (5 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10)) && entityBehaviour.EntityType == EntityTypes.EnemyClass || enemyEntity.MobileEnemy.Weight > 0) { float enemyWeight = enemyEntity.GetWeightInClassicUnits(); float tenTimesDamage = damage * 10; float twoTimesDamage = damage * 2; float knockBackAmount = ((tenTimesDamage - enemyWeight) * 256) / (enemyWeight + tenTimesDamage) * twoTimesDamage; float knockBackSpeed = (tenTimesDamage / enemyWeight) * (twoTimesDamage - (knockBackAmount / 256)); knockBackSpeed /= (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10); if (knockBackSpeed < (15 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10))) { knockBackSpeed = (15 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10)); } enemyMotor.KnockBackSpeed = knockBackSpeed; enemyMotor.KnockBackDirection = mainCamera.transform.forward; } } } else { if ((weapon.WeaponType != WeaponTypes.Bow && !enemyEntity.MobileEnemy.ParrySounds) || weapon.WeaponType == WeaponTypes.Melee) { weapon.PlaySwingSound(); } else if (enemyEntity.MobileEnemy.ParrySounds) { enemySounds.PlayParrySound(); } } // Remove health enemyEntity.DecreaseHealth(damage); hitEnemy = true; // Assign "cast when strikes" to target entity if (strikingWeapon != null && strikingWeapon.IsEnchanted) { EntityEffectManager enemyEffectManager = enemyEntity.EntityBehaviour.GetComponent <EntityEffectManager>(); if (enemyEffectManager) { enemyEffectManager.StrikeWithItem(strikingWeapon, GameManager.Instance.PlayerEntityBehaviour); } } // Make foe attack their aggressor // Currently this is just player, but should be expanded later // for a wider variety of behaviours if (enemyMotor) { // Make enemies in an area aggressive if player attacked a non-hostile one. if (!enemyMotor.IsHostile) { GameManager.Instance.MakeEnemiesHostile(); } enemyMotor.MakeEnemyHostileToPlayer(gameObject); } } } // Check if hit a mobile NPC MobilePersonNPC mobileNpc = hit.transform.GetComponent <MobilePersonNPC>(); if (mobileNpc) { EnemyBlood blood = hit.transform.GetComponent <EnemyBlood>(); if (blood) { blood.ShowBloodSplash(0, hit.point); } mobileNpc.Motor.gameObject.SetActive(false); playerEntity.TallyCrimeGuildRequirements(false, 5); // TODO: LOS check from each townsperson. If seen, register crime and start spawning guards as below. playerEntity.CrimeCommitted = PlayerEntity.Crimes.Murder; playerEntity.SpawnCityGuards(true); } } }