/// <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); }
private void Start() { // Setup light and shadows myLight = GetComponent <Light>(); myLight.enabled = EnableLight; forceDisableSpellLighting = !DaggerfallUnity.Settings.EnableSpellLighting; forceDisableSpellShadows = !DaggerfallUnity.Settings.EnableSpellShadows; if (forceDisableSpellLighting) { myLight.enabled = false; } if (forceDisableSpellShadows) { myLight.shadows = LightShadows.None; } initialRange = myLight.range; initialIntensity = myLight.intensity; // Setup collider myCollider = GetComponent <SphereCollider>(); myCollider.radius = ColliderRadius; myCollider.isTrigger = true; // Setup rigidbody myRigidbody = GetComponent <Rigidbody>(); myRigidbody.isKinematic = true; myRigidbody.useGravity = false; // Use payload when available if (payload != null) { // Set payload missile properties caster = payload.CasterEntityBehaviour; targetType = payload.Settings.TargetType; elementType = payload.Settings.ElementType; // Set spell billboard anims automatically from payload for mobile missiles if (targetType == TargetTypes.SingleTargetAtRange || targetType == TargetTypes.AreaAtRange) { UseSpellBillboardAnims(elementType); } } // Ignore missile collision with caster (this is a different check to AOE targets) if (caster) { Physics.IgnoreCollision(caster.GetComponent <Collider>(), this.GetComponent <Collider>()); } }
void DrainTargetStrength(DaggerfallEntityBehaviour entity, int amount) { if (entity == null) { return; } EntityEffectManager targetManager = entity.GetComponent <EntityEffectManager>(); if (targetManager == null) { return; } // Find incumbent strength drain effect on target or assign new drain DrainStrength drain = targetManager.FindIncumbentEffect <DrainStrength>() as DrainStrength; if (drain == null) { // Create and assign bundle // We bypass saving throws as target already had a chance at start of payload delivery EntityEffectBundle bundle = targetManager.CreateSpellBundle(DrainStrength.EffectKey); targetManager.AssignBundle(bundle, AssignBundleFlags.BypassSavingThrows); // Find new bundle now its assigned drain = targetManager.FindIncumbentEffect <DrainStrength>() as DrainStrength; } // Increment incumbent drain magnitude on target if (drain != null) { drain.IncreaseMagnitude(amount); } }
/// <summary> /// Determines if enemies are nearby. Uses include whether player is able to rest or not. /// Based on minimum distance to nearest monster, and if monster can actually sense player. /// </summary> /// <param name="minMonsterDistance">Monsters must be at least this far away.</param> /// <returns>True if enemies are nearby.</returns> public bool AreEnemiesNearby(float minMonsterDistance = 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) { // Is a monster inside min distance? if (Vector3.Distance(entityBehaviour.transform.position, PlayerController.transform.position) < minMonsterDistance) { areEnemiesNearby = true; break; } // Is monster already aware of player? EnemySenses enemySenses = entityBehaviour.GetComponent <EnemySenses>(); if (enemySenses) { if (enemySenses.PlayerInSight || enemySenses.PlayerInEarshot) { areEnemiesNearby = true; break; } } } } return(areEnemiesNearby); }
/// <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); }
private void Start() { // Get references enemyMobile = GetComponent <DaggerfallMobileUnit>(); enemyEntityBehaviour = GetComponentInParent <DaggerfallEntityBehaviour>(); if (enemyEntityBehaviour && enemyEntityBehaviour.EntityType == EntityTypes.EnemyMonster) { enemyEntity = (EnemyEntity)enemyEntityBehaviour.Entity; enemySenses = enemyEntityBehaviour.GetComponent <EnemySenses>(); } }
public override PayloadCallbackResults?EnchantmentPayloadCallback(EnchantmentPayloadFlags context, EnchantmentParam?param = null, DaggerfallEntityBehaviour sourceEntity = null, DaggerfallEntityBehaviour targetEntity = null, DaggerfallUnityItem sourceItem = null, int sourceDamage = 0) { base.EnchantmentPayloadCallback(context, param, sourceEntity, targetEntity, sourceItem, sourceDamage); // Validate if (context != EnchantmentPayloadFlags.Equipped || param == null || sourceEntity == null || sourceItem == null) { return(null); } // Get caster effect manager EntityEffectManager casterManager = sourceEntity.GetComponent <EntityEffectManager>(); if (!casterManager) { return(null); } // Cast when held enchantment invokes a spell bundle that is permanent until item is removed if (!string.IsNullOrEmpty(param.Value.CustomParam)) { // TODO: Instantiate a custom spell bundle } else { // Instantiate a classic spell bundle SpellRecord.SpellRecordData spell; if (GameManager.Instance.EntityEffectBroker.GetClassicSpellRecord(param.Value.ClassicParam, out spell)) { UnityEngine.Debug.LogFormat("CastWhenHeld callback found enchantment '{0}'", spell.spellName); // Create effect bundle settings from classic spell EffectBundleSettings bundleSettings; if (GameManager.Instance.EntityEffectBroker.ClassicSpellRecordDataToEffectBundleSettings(spell, BundleTypes.HeldMagicItem, out bundleSettings)) { // Assign bundle EntityEffectBundle bundle = new EntityEffectBundle(bundleSettings, sourceEntity); bundle.FromEquippedItem = sourceItem; casterManager.AssignBundle(bundle, AssignBundleFlags.BypassSavingThrows); // Play cast sound on equip for player only if (casterManager.IsPlayerEntity) { casterManager.PlayCastSound(sourceEntity, casterManager.GetCastSoundID(bundle.Settings.ElementType)); } // TODO: Apply durability loss to equipped item on equip and over time // http://en.uesp.net/wiki/Daggerfall:Magical_Items#Durability_of_Magical_Items } } } return(null); }
public override PayloadCallbackResults?EnchantmentPayloadCallback(EnchantmentPayloadFlags context, EnchantmentParam?param = null, DaggerfallEntityBehaviour sourceEntity = null, DaggerfallEntityBehaviour targetEntity = null, DaggerfallUnityItem sourceItem = null, int sourceDamage = 0) { base.EnchantmentPayloadCallback(context, param, sourceEntity, targetEntity, sourceItem); // Validate if (context != EnchantmentPayloadFlags.Used || sourceEntity == null || param == null) { return(null); } // Get caster effect manager EntityEffectManager effectManager = sourceEntity.GetComponent <EntityEffectManager>(); if (!effectManager) { return(null); } // Cast when used enchantment prepares a new ready spell if (!string.IsNullOrEmpty(param.Value.CustomParam)) { // TODO: Ready a custom spell bundle } else { // Ready a classic spell bundle SpellRecord.SpellRecordData spell; EffectBundleSettings bundleSettings; EntityEffectBundle bundle; if (GameManager.Instance.EntityEffectBroker.GetClassicSpellRecord(param.Value.ClassicParam, out spell)) { if (GameManager.Instance.EntityEffectBroker.ClassicSpellRecordDataToEffectBundleSettings(spell, BundleTypes.Spell, out bundleSettings)) { // Self-cast spells are all assigned directly to self, "click to cast" spells are loaded to ready spell // TODO: Support multiple ready spells so all loaded spells are launched on click bundle = new EntityEffectBundle(bundleSettings, sourceEntity); bundle.CastByItem = sourceItem; if (bundle.Settings.TargetType == TargetTypes.CasterOnly) { effectManager.AssignBundle(bundle, AssignBundleFlags.BypassSavingThrows | AssignBundleFlags.BypassChance); } else { effectManager.SetReadySpell(bundle, true); } } } } return(new PayloadCallbackResults() { durabilityLoss = durabilityLossOnUse }); }
public override PayloadCallbackResults?EnchantmentPayloadCallback(EnchantmentPayloadFlags context, EnchantmentParam?param = null, DaggerfallEntityBehaviour sourceEntity = null, DaggerfallEntityBehaviour targetEntity = null, DaggerfallUnityItem sourceItem = null, int sourceDamage = 0) { base.EnchantmentPayloadCallback(context, param, sourceEntity, targetEntity, sourceItem, sourceDamage); // Validate if (context != EnchantmentPayloadFlags.Strikes || targetEntity == null) { return(null); } // Change target enemy if (targetEntity.Entity is EnemyEntity) { // Get enemy entity - cannot have Wabbajack active already EnemyEntity enemy = (EnemyEntity)targetEntity.Entity; if (enemy == null || enemy.WabbajackActive) { return(null); } // Get new enemy career and transform MobileTypes enemyType = careerIDs[Random.Range(0, careerIDs.Length)]; if ((int)enemyType == enemy.CareerIndex) { enemyType = (MobileTypes)(((int)enemyType + 1) % careerIDs.Length); } Transform parentTransform = targetEntity.gameObject.transform.parent; // Do not disable enemy if in use by the quest system QuestResourceBehaviour questResourceBehaviour = targetEntity.GetComponent <QuestResourceBehaviour>(); if (questResourceBehaviour && !questResourceBehaviour.IsFoeDead) { return(null); } string[] enemyNames = TextManager.Instance.GetLocalizedTextList("enemyNames"); if (enemyNames == null) { throw new System.Exception("enemyNames array text not found"); } // Switch entity targetEntity.gameObject.SetActive(false); GameObject gameObject = GameObjectHelper.CreateEnemy(enemyNames[(int)enemyType], enemyType, targetEntity.transform.localPosition, MobileGender.Unspecified, parentTransform); DaggerfallEntityBehaviour newEnemyBehaviour = gameObject.GetComponent <DaggerfallEntityBehaviour>(); EnemyEntity newEnemy = (EnemyEntity)newEnemyBehaviour.Entity; newEnemy.WabbajackActive = true; newEnemy.CurrentHealth -= enemy.MaxHealth - enemy.CurrentHealth; // carry over damage to new monster } return(null); }
ulong GetCasterLoadID(DaggerfallEntityBehaviour caster) { // Only supporting LoadID from enemies at this time if (caster.EntityType == EntityTypes.EnemyMonster || caster.EntityType == EntityTypes.EnemyClass) { ISerializableGameObject serializableEnemy = caster.GetComponent <SerializableEnemy>() as ISerializableGameObject; return(serializableEnemy.LoadID); } else { return(0); } }
private static void PacifyWere(bool isBeast) { DaggerfallEntityBehaviour[] entityBehaviours = FindObjectsOfType <DaggerfallEntityBehaviour>(); for (int i = 0; i < entityBehaviours.Length; i++) { DaggerfallEntityBehaviour entityBehaviour = entityBehaviours[i]; if (entityBehaviour.EntityType == EntityTypes.EnemyMonster) { EnemyEntity enemyEntity = entityBehaviour.Entity as EnemyEntity; EnemySenses enemySenses = entityBehaviour.GetComponent <EnemySenses>(); EnemyMotor enemyMotor = entityBehaviour.GetComponent <EnemyMotor>(); if (enemySenses && enemySenses.HasEncounteredPlayer && enemyEntity.MobileEnemy.Team == MobileTeams.Werecreatures && enemyMotor.IsHostile && enemyEntity.MobileEnemy.Team != MobileTeams.PlayerAlly) { if (isBeast) { enemyMotor.IsHostile = false; DaggerfallUI.AddHUDText("Pacified " + enemyEntity.Name + " using your lycanthropy."); } } } } }
public NearbyObjectFlags GetEntityFlags(DaggerfallEntityBehaviour entity) { NearbyObjectFlags result = NearbyObjectFlags.None; if (!entity) { return(result); } if (entity.EntityType == EntityTypes.EnemyClass || entity.EntityType == EntityTypes.EnemyMonster) { result |= NearbyObjectFlags.Enemy; DFCareer.EnemyGroups enemyGroup = (entity.Entity as EnemyEntity).GetEnemyGroup(); switch (enemyGroup) { case DFCareer.EnemyGroups.Undead: result |= NearbyObjectFlags.Undead; break; case DFCareer.EnemyGroups.Daedra: result |= NearbyObjectFlags.Daedra; break; case DFCareer.EnemyGroups.Humanoid: result |= NearbyObjectFlags.Humanoid; break; case DFCareer.EnemyGroups.Animals: result |= NearbyObjectFlags.Animal; break; } } else if (entity.EntityType == EntityTypes.CivilianNPC) { result |= NearbyObjectFlags.Humanoid; } // Set magic flag // Not completely sure what conditions should flag entity for "detect magic" // Currently just assuming entity has active effects EntityEffectManager manager = entity.GetComponent <EntityEffectManager>(); if (manager && manager.EffectCount > 0) { result |= NearbyObjectFlags.Magic; } return(result); }
private static void Halt() { DaggerfallEntityBehaviour[] entityBehaviours = FindObjectsOfType <DaggerfallEntityBehaviour>(); for (int i = 0; i < entityBehaviours.Length; i++) { DaggerfallEntityBehaviour entityBehaviour = entityBehaviours[i]; if (entityBehaviour.EntityType == EntityTypes.EnemyClass && !playerEntity.HaveShownSurrenderToGuardsDialogue) { EnemyEntity enemyEntity = entityBehaviour.Entity as EnemyEntity; EnemyMotor enemyMotor = entityBehaviour.GetComponent <EnemyMotor>(); if (enemyEntity.MobileEnemy.Team == MobileTeams.CityWatch && enemyMotor.IsHostile && Vector3.Distance(entityBehaviour.transform.position, GameManager.Instance.PlayerObject.transform.position) < 4f) { EnemySenses enemySenses = entityBehaviour.GetComponent <EnemySenses>(); bool guardCanSeePlayer = enemySenses.Target == GameManager.Instance.PlayerEntityBehaviour && enemySenses.TargetInSight; if (guardCanSeePlayer) { playerEntity.HaveShownSurrenderToGuardsDialogue = true; BribePrompt(); return; } } } } }
/// <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; } } } }
MaceOfMolagBalEffect FindLiveEffect(DaggerfallEntityBehaviour entity) { if (entity == null) { return(null); } EntityEffectManager targetManager = entity.GetComponent <EntityEffectManager>(); if (targetManager == null) { return(null); } return(targetManager.FindIncumbentEffect <MaceOfMolagBalEffect>() as MaceOfMolagBalEffect); }
/// <summary> /// Determines if player is able to rest or not. /// Based on minimum distance to nearest monster, and if monster can actually sense player. /// </summary> /// <param name="minMonsterDistance">Monsters must be at least this far away.</param> /// <returns>True if player can rest.</returns> public bool CanPlayerRest(float minMonsterDistance = 12f) { const int enemiesNearby = 354; if (!PlayerController.isGrounded) { return(false); } bool canRest = true; 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) { // Is a monster inside min distance? if (Vector3.Distance(entityBehaviour.transform.position, PlayerController.transform.position) < minMonsterDistance) { canRest = false; break; } // Is monster already aware of player? EnemySenses enemySenses = entityBehaviour.GetComponent <EnemySenses>(); if (enemySenses) { if (enemySenses.PlayerInSight || enemySenses.PlayerInEarshot) { canRest = false; break; } } } } // Alert player if monsters neaby if (!canRest) { DaggerfallUI.MessageBox(enemiesNearby); } return(canRest); }
/// <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); }
public override PayloadCallbackResults?EnchantmentPayloadCallback(EnchantmentPayloadFlags context, EnchantmentParam?param = null, DaggerfallEntityBehaviour sourceEntity = null, DaggerfallEntityBehaviour targetEntity = null, DaggerfallUnityItem sourceItem = null, int sourceDamage = 0) { base.EnchantmentPayloadCallback(context, param, sourceEntity, targetEntity, sourceItem, sourceDamage); // Validate if (context != EnchantmentPayloadFlags.Strikes || targetEntity == null || param == null || sourceDamage == 0) { return(null); } // Get target effect manager EntityEffectManager effectManager = targetEntity.GetComponent <EntityEffectManager>(); if (!effectManager) { return(null); } // Cast when strikes enchantment prepares a new ready spell if (!string.IsNullOrEmpty(param.Value.CustomParam)) { // TODO: Ready a custom spell bundle } else { // Ready a classic spell bundle SpellRecord.SpellRecordData spell; EffectBundleSettings bundleSettings; EntityEffectBundle bundle; if (GameManager.Instance.EntityEffectBroker.GetClassicSpellRecord(param.Value.ClassicParam, out spell)) { if (GameManager.Instance.EntityEffectBroker.ClassicSpellRecordDataToEffectBundleSettings(spell, BundleTypes.Spell, out bundleSettings)) { bundle = new EntityEffectBundle(bundleSettings, sourceEntity); effectManager.AssignBundle(bundle, AssignBundleFlags.ShowNonPlayerFailures); } } } return(new PayloadCallbackResults() { durabilityLoss = durabilityLossOnStrike }); }
public override void MagicRound() { base.MagicRound(); DaggerfallEntityBehaviour entityBehaviour = GetPeeredEntityBehaviour(manager); if (!entityBehaviour) { return; } if (entityBehaviour.Entity is EnemyEntity) { EnemyEntity enemy = (EnemyEntity)entityBehaviour.Entity; if (enemy.WabbajackActive) { return; } MobileTypes enemyType = careerIDs[Random.Range(0, careerIDs.Length)]; if ((int)enemyType == enemy.CareerIndex) { enemyType = (MobileTypes)(((int)enemyType + 1) % careerIDs.Length); } Transform parentTransform = entityBehaviour.gameObject.transform.parent; // Do not disable enemy if in use by the quest system QuestResourceBehaviour questResourceBehaviour = entityBehaviour.GetComponent <QuestResourceBehaviour>(); if (questResourceBehaviour) { if (!questResourceBehaviour.IsFoeDead) { return; } } entityBehaviour.gameObject.SetActive(false); GameObject gameObject = GameObjectHelper.CreateEnemy(HardStrings.enemyNames[(int)enemyType], enemyType, entityBehaviour.transform.localPosition, parentTransform); DaggerfallEntityBehaviour newEnemyBehaviour = gameObject.GetComponent <DaggerfallEntityBehaviour>(); EnemyEntity newEnemy = (EnemyEntity)newEnemyBehaviour.Entity; newEnemy.WabbajackActive = true; newEnemy.CurrentHealth -= enemy.MaxHealth - enemy.CurrentHealth; // carry over damage to new monster } }
public override PayloadCallbackResults?EnchantmentPayloadCallback(EnchantmentPayloadFlags context, EnchantmentParam?param = null, DaggerfallEntityBehaviour sourceEntity = null, DaggerfallEntityBehaviour targetEntity = null, DaggerfallUnityItem sourceItem = null, int sourceDamage = 0) { base.EnchantmentPayloadCallback(context, param, sourceEntity, targetEntity, sourceItem, sourceDamage); // Validate if ((context != EnchantmentPayloadFlags.Equipped && context != EnchantmentPayloadFlags.MagicRound && context != EnchantmentPayloadFlags.RerollEffect) || param == null || sourceEntity == null || sourceItem == null) { return(null); } // Get caster effect manager EntityEffectManager casterManager = sourceEntity.GetComponent <EntityEffectManager>(); if (!casterManager) { return(null); } if (context == EnchantmentPayloadFlags.Equipped) { // Cast when held enchantment invokes a spell bundle that is permanent until item is removed InstantiateSpellBundle(param.Value, sourceEntity, sourceItem, casterManager); } else if (context == EnchantmentPayloadFlags.MagicRound) { // Apply CastWhenHeld durability loss ApplyDurabilityLoss(sourceItem, sourceEntity); } else if (context == EnchantmentPayloadFlags.RerollEffect) { // Recast spell bundle - previous instance has already been removed by EntityEffectManager prior to callback InstantiateSpellBundle(param.Value, sourceEntity, sourceItem, casterManager, true); } return(null); }
public static void EnemyDeath_OnEnemyDeath(object sender, EventArgs e) { EnemyDeath enemyDeath = sender as EnemyDeath; if (enemyDeath != null) { DaggerfallEntityBehaviour entityBehaviour = enemyDeath.GetComponent <DaggerfallEntityBehaviour>(); if (entityBehaviour != null) { EnemyEntity enemyEntity = entityBehaviour.Entity as EnemyEntity; if (enemyEntity != null) { if (entityBehaviour.GetComponent <EnemySenses>().Target == GameManager.Instance.PlayerEntityBehaviour) { string monsterName = AllTextClass.MonsterCareerIndexToString(enemyEntity.CareerIndex); if (killCounts.ContainsKey(monsterName)) { killCounts[monsterName] += 1; for (int i = 0; i < AllText.Pages.Count; i++) { AllText.Pages[i].PageSummary = new Summary(AllText.Pages[i].PageSummary.Name); } } else { if (SettingEntries == 1 && monsterName != "false") { DaggerfallUI.AddHUDText(String.Format("{0} has been added to the Bestiary.", new List <string>(mod.GetAsset <TextAsset>(monsterName).text.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries))[2])); } killCounts.Add(monsterName, 1); InitializeUI(); } } } } } }
public override void MagicRound() { base.MagicRound(); // Get peered entity gameobject DaggerfallEntityBehaviour entityBehaviour = GetPeeredEntityBehaviour(manager); if (!entityBehaviour) { return; } // Set target non-hostile if (IsAffinityMatch(entityBehaviour.Entity)) { EnemyMotor enemyMotor = entityBehaviour.GetComponent <EnemyMotor>(); if (enemyMotor) { enemyMotor.IsHostile = false; Debug.LogFormat("Enemy {0} is now non-hostile", enemyMotor.name); } } }
/// <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 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) { // Is enemy already aware of player or close enough they would be spawned in classic? if (enemySenses.PlayerInSight || enemySenses.PlayerInEarshot || enemySenses.WouldBeSpawnedInClassic) { 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); }
bool CanEnemySeePlayer() { bool enemyCanSeePlayer = false; DaggerfallEntityBehaviour[] entityBehaviours = GameManager.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 enemyCanSeePlayer = enemySenses.Target == GameManager.Instance.PlayerEntityBehaviour && enemySenses.TargetInSight; if (enemyCanSeePlayer) { break; } } } } return(enemyCanSeePlayer); }
void StartLevitating() { // Get peered entity gameobject DaggerfallEntityBehaviour entityBehaviour = GetPeeredEntityBehaviour(manager); if (!entityBehaviour) { return; } // Enable levitation for player or enemies if (entityBehaviour.EntityType == EntityTypes.Player) { GameManager.Instance.PlayerMotor.GetComponent <LevitateMotor>().IsLevitating = true; } else if (entityBehaviour.EntityType == EntityTypes.EnemyMonster || entityBehaviour.EntityType == EntityTypes.EnemyClass) { EnemyMotor enemyMotor = entityBehaviour.GetComponent <EnemyMotor>(); if (enemyMotor) { enemyMotor.IsLevitating = true; } } }
// 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); } } }
public void CastSpellQueue(Foe foe, DaggerfallEntityBehaviour enemyEntityBehaviour) { // Validate if (!enemyEntityBehaviour || foe == null || foe.SpellQueue == null || foeSpellQueuePosition == foe.SpellQueue.Count) { return; } // Target entity must be alive if (enemyEntityBehaviour.Entity.CurrentHealth == 0) { return; } // Get effect manager on enemy EntityEffectManager enemyEffectManager = enemyEntityBehaviour.GetComponent <EntityEffectManager>(); if (!enemyEffectManager) { return; } // Cast queued spells on foe from current position for (int i = foeSpellQueuePosition; i < foe.SpellQueue.Count; i++) { SpellReference spell = foe.SpellQueue[i]; EntityEffectBundle spellBundle = null; // Create classic or custom spell bundle if (string.IsNullOrEmpty(spell.CustomKey)) { // Get classic spell data SpellRecord.SpellRecordData spellData; if (!GameManager.Instance.EntityEffectBroker.GetClassicSpellRecord(spell.ClassicID, out spellData)) { continue; } // Create classic spell bundle settings EffectBundleSettings bundleSettings; if (!GameManager.Instance.EntityEffectBroker.ClassicSpellRecordDataToEffectBundleSettings(spellData, BundleTypes.Spell, out bundleSettings)) { continue; } // Create classic spell bundle spellBundle = new EntityEffectBundle(bundleSettings, enemyEntityBehaviour); } else { // Create custom spell bundle - must be previously registered to broker try { EntityEffectBroker.CustomSpellBundleOffer offer = GameManager.Instance.EntityEffectBroker.GetCustomSpellBundleOffer(spell.CustomKey); spellBundle = new EntityEffectBundle(offer.BundleSetttings, enemyEntityBehaviour); } catch (Exception ex) { Debug.LogErrorFormat("QuestResourceBehaviour.CastSpellQueue() could not find custom spell offer with key: {0}, exception: {1}", spell.CustomKey, ex.Message); } } // Assign spell bundle to enemy if (spellBundle != null) { enemyEffectManager.AssignBundle(spellBundle, AssignBundleFlags.BypassSavingThrows); } } // Set index positon to end of queue foeSpellQueuePosition = foe.SpellQueue.Count; }
void GetTargets() { DaggerfallEntityBehaviour highestPriorityTarget = null; DaggerfallEntityBehaviour secondHighestPriorityTarget = null; float highestPriority = -1; float secondHighestPriority = -1; bool sawSelectedTarget = false; Vector3 directionToTargetHolder = directionToTarget; float distanceToTargetHolder = distanceToTarget; DaggerfallEntityBehaviour[] entityBehaviours = FindObjectsOfType <DaggerfallEntityBehaviour>(); for (int i = 0; i < entityBehaviours.Length; i++) { DaggerfallEntityBehaviour targetBehaviour = entityBehaviours[i]; EnemyEntity targetEntity = null; if (targetBehaviour != Player) { targetEntity = targetBehaviour.Entity as EnemyEntity; } // Can't target self if (targetBehaviour == entityBehaviour) { continue; } // Evaluate potential targets if (targetBehaviour.EntityType == EntityTypes.EnemyMonster || targetBehaviour.EntityType == EntityTypes.EnemyClass || targetBehaviour.EntityType == EntityTypes.Player) { // NoTarget mode if ((GameManager.Instance.PlayerEntity.NoTargetMode || !motor.IsHostile || enemyEntity.MobileEnemy.Team == MobileTeams.PlayerAlly) && targetBehaviour == Player) { continue; } // Can't target ally if (targetBehaviour == Player && enemyEntity.Team == MobileTeams.PlayerAlly) { continue; } else if (DaggerfallUnity.Settings.EnemyInfighting) { if (targetEntity != null && targetEntity.Team == enemyEntity.Team) { continue; } } else { if (targetBehaviour != Player && enemyEntity.MobileEnemy.Team != MobileTeams.PlayerAlly) { continue; } } // For now, quest AI only targets player if (questBehaviour && targetBehaviour != Player) { continue; } EnemySenses targetSenses = null; if (targetBehaviour.EntityType == EntityTypes.EnemyMonster || targetBehaviour.EntityType == EntityTypes.EnemyClass) { targetSenses = targetBehaviour.GetComponent <EnemySenses>(); } // For now, quest AI can't be targeted if (targetSenses && targetSenses.QuestBehaviour) { continue; } Vector3 toTarget = targetBehaviour.transform.position - transform.position; directionToTarget = toTarget.normalized; distanceToTarget = toTarget.magnitude; bool see = CanSeeTarget(targetBehaviour); // Is potential target neither visible nor in area around player? If so, reject as target. if (targetSenses && !targetSenses.WouldBeSpawnedInClassic && !see) { continue; } float priority = 0; // Add 5 priority if this potential target isn't already targeting someone if (targetSenses && targetSenses.Target == null) { priority += 5; } if (see) { priority += 10; } // Add distance priority float distancePriority = 30 - distanceToTarget; if (distancePriority < 0) { distancePriority = 0; } priority += distancePriority; if (priority > highestPriority) { secondHighestPriority = highestPriority; highestPriority = priority; secondHighestPriorityTarget = highestPriorityTarget; highestPriorityTarget = targetBehaviour; sawSecondaryTarget = sawSelectedTarget; sawSelectedTarget = see; directionToTargetHolder = directionToTarget; distanceToTargetHolder = distanceToTarget; } else if (priority > secondHighestPriority) { sawSecondaryTarget = see; secondHighestPriority = priority; secondHighestPriorityTarget = targetBehaviour; } } } // Restore direction and distance values directionToTarget = directionToTargetHolder; distanceToTarget = distanceToTargetHolder; targetInSight = sawSelectedTarget; target = highestPriorityTarget; if (DaggerfallUnity.Settings.EnhancedCombatAI && secondHighestPriorityTarget) { secondaryTarget = secondHighestPriorityTarget; if (sawSecondaryTarget) { secondaryTargetPos = secondaryTarget.transform.position; } } }
private void Start() { // Setup light and shadows myLight = GetComponent <Light>(); myLight.enabled = EnableLight; forceDisableSpellLighting = !DaggerfallUnity.Settings.EnableSpellLighting; if (forceDisableSpellLighting) { myLight.enabled = false; } if (!DaggerfallUnity.Settings.EnableSpellShadows) { myLight.shadows = LightShadows.None; } initialRange = myLight.range; initialIntensity = myLight.intensity; // Setup collider myCollider = GetComponent <SphereCollider>(); myCollider.radius = ColliderRadius; // Setup rigidbody myRigidbody = GetComponent <Rigidbody>(); myRigidbody.useGravity = false; // Use payload when available if (payload != null) { // Set payload missile properties caster = payload.CasterEntityBehaviour; targetType = payload.Settings.TargetType; elementType = payload.Settings.ElementType; // Set spell billboard anims automatically from payload for mobile missiles if (targetType == TargetTypes.SingleTargetAtRange || targetType == TargetTypes.AreaAtRange) { UseSpellBillboardAnims(); } } // Setup senses if (caster != GameManager.Instance.PlayerEntityBehaviour) { enemySenses = caster.GetComponent <EnemySenses>(); } // Setup arrow if (isArrow) { // Create and orient 3d arrow goModel = GameObjectHelper.CreateDaggerfallMeshGameObject(99800, transform); Vector3 adjust; // Offset up so it comes from same place LOS check is done from if (caster != GameManager.Instance.PlayerEntityBehaviour) { CharacterController controller = caster.transform.GetComponent <CharacterController>(); adjust = caster.transform.forward * 0.6f; adjust.y += controller.height / 3; } else { // Offset forward to avoid collision with player adjust = GameManager.Instance.MainCamera.transform.forward * 0.6f; // Adjust slightly downward to match bow animation adjust.y -= 0.11f; // Adjust to the right or left to match bow animation if (!GameManager.Instance.WeaponManager.ScreenWeapon.FlipHorizontal) { adjust += GameManager.Instance.MainCamera.transform.right * 0.15f; } else { adjust -= GameManager.Instance.MainCamera.transform.right * 0.15f; } } goModel.transform.localPosition = adjust; goModel.transform.rotation = Quaternion.LookRotation(GetAimDirection()); } // Ignore missile collision with caster (this is a different check to AOE targets) if (caster) { Physics.IgnoreCollision(caster.GetComponent <Collider>(), this.GetComponent <Collider>()); } }
void FixedUpdate() { if (GameManager.Instance.DisableAI) { return; } targetPosPredictTimer += Time.deltaTime; if (targetPosPredictTimer >= predictionInterval) { targetPosPredictTimer = 0f; targetPosPredict = true; } else { targetPosPredict = false; } // Update whether enemy would be spawned or not in classic. // Only check if within the maximum possible distance (Just under 1094 classic units) if (GameManager.ClassicUpdate) { if (distanceToPlayer < 1094 * MeshReader.GlobalScale) { float upperXZ = 0; float upperY = 0; float lowerY = 0; bool playerInside = GameManager.Instance.PlayerGPS.GetComponent <PlayerEnterExit>().IsPlayerInside; if (!playerInside) { upperXZ = classicSpawnDespawnExterior; } else { if (!wouldBeSpawnedInClassic) { upperXZ = classicSpawnXZDist; upperY = classicSpawnYDistUpper; lowerY = classicSpawnYDistLower; } else { upperXZ = classicDespawnXZDist; upperY = classicDespawnYDist; } } float YDiffToPlayer = transform.position.y - Player.transform.position.y; float YDiffToPlayerAbs = Mathf.Abs(YDiffToPlayer); float distanceToPlayerXZ = Mathf.Sqrt(distanceToPlayer * distanceToPlayer - YDiffToPlayerAbs * YDiffToPlayerAbs); wouldBeSpawnedInClassic = true; if (distanceToPlayerXZ > upperXZ) { wouldBeSpawnedInClassic = false; } if (playerInside) { if (lowerY == 0) { if (YDiffToPlayerAbs > upperY) { wouldBeSpawnedInClassic = false; } } else if (YDiffToPlayer < lowerY || YDiffToPlayer > upperY) { wouldBeSpawnedInClassic = false; } } } else { wouldBeSpawnedInClassic = false; } } if (GameManager.ClassicUpdate) { classicTargetUpdateTimer += Time.deltaTime / systemTimerUpdatesDivisor; if (target != null && target.Entity.CurrentHealth <= 0) { target = null; } // Non-hostile mode if (GameManager.Instance.PlayerEntity.NoTargetMode || !motor.IsHostile) { if (target == Player) { target = null; } if (secondaryTarget == Player) { secondaryTarget = null; } } // Reset these values if no target if (target == null) { lastKnownTargetPos = ResetPlayerPos; predictedTargetPos = ResetPlayerPos; directionToTarget = ResetPlayerPos; lastDistanceToTarget = 0; targetRateOfApproach = 0; distanceToTarget = 0; targetSenses = null; // If we have a valid secondary target that we acquired when we got the primary, switch to it. // There will only be a secondary target if using enhanced combat AI. if (secondaryTarget != null && secondaryTarget.Entity.CurrentHealth > 0) { target = secondaryTarget; // If the secondary target was actually seen, use the last place we saw it to begin pursuit. if (sawSecondaryTarget) { lastKnownTargetPos = secondaryTargetPos; } awareOfTargetForLastPrediction = false; } } // Compare change in target position to give AI some ability to read opponent's movements if (target != null && target == targetOnLastUpdate) { if (DaggerfallUnity.Settings.EnhancedCombatAI) { targetRateOfApproach = (lastDistanceToTarget - distanceToTarget); } } else { lastDistanceToTarget = 0; targetRateOfApproach = 0; } if (target != null) { lastDistanceToTarget = distanceToTarget; targetOnLastUpdate = target; } } if (Player != null) { // Get distance to player Vector3 toPlayer = Player.transform.position - transform.position; distanceToPlayer = toPlayer.magnitude; // If out of classic spawn range, still check for direct LOS to player so that enemies who see player will // try to attack. if (!wouldBeSpawnedInClassic) { distanceToTarget = distanceToPlayer; directionToTarget = toPlayer.normalized; playerInSight = CanSeeTarget(Player); } if (classicTargetUpdateTimer > 5) { classicTargetUpdateTimer = 0f; // Is enemy in area around player or can see player? if (wouldBeSpawnedInClassic || playerInSight) { GetTargets(); if (target != null && target != Player) { targetSenses = target.GetComponent <EnemySenses>(); } else { targetSenses = null; } } // Make targeted character also target this character if it doesn't have a target yet. if (target != null && targetSenses && targetSenses.Target == null) { targetSenses.Target = entityBehaviour; } } if (target == null) { targetInSight = false; detectedTarget = false; return; } if (!wouldBeSpawnedInClassic && target == Player) { distanceToTarget = distanceToPlayer; directionToTarget = toPlayer.normalized; targetInSight = playerInSight; } else { Vector3 toTarget = ResetPlayerPos; toTarget = target.transform.position - transform.position; if (toTarget != ResetPlayerPos) { distanceToTarget = toTarget.magnitude; directionToTarget = toTarget.normalized; } targetInSight = CanSeeTarget(target); } // Classic stealth mechanics would be interfered with by hearing, so only enable // hearing if the enemy has detected the target. If target is visible we can omit hearing. if (detectedTarget && !targetInSight) { targetInEarshot = CanHearTarget(target); } else { targetInEarshot = 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 (GameManager.ClassicUpdate) { blockedByIllusionEffect = BlockedByIllusionEffect(); if (lastHadLOSTimer > 0) { lastHadLOSTimer--; } } if (!blockedByIllusionEffect && (targetInSight || targetInEarshot)) { detectedTarget = true; lastKnownTargetPos = target.transform.position; lastHadLOSTimer = 200f; } else if (!blockedByIllusionEffect && StealthCheck()) { detectedTarget = true; // Only get the target'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) { lastKnownTargetPos = target.transform.position; } } else { detectedTarget = false; } if (oldLastKnownTargetPos == ResetPlayerPos) { oldLastKnownTargetPos = lastKnownTargetPos; } if (predictedTargetPos == ResetPlayerPos || !DaggerfallUnity.Settings.EnhancedCombatAI) { predictedTargetPos = lastKnownTargetPos; } // Predict target's next position if (targetPosPredict && lastKnownTargetPos != ResetPlayerPos) { // Be sure to only take difference of movement if we've seen the target for two consecutive prediction updates if (!blockedByIllusionEffect && (targetInSight || targetInEarshot)) { if (awareOfTargetForLastPrediction) { lastPositionDiff = lastKnownTargetPos - oldLastKnownTargetPos; } // Store current last known target position for next prediction update oldLastKnownTargetPos = lastKnownTargetPos; awareOfTargetForLastPrediction = true; } else { awareOfTargetForLastPrediction = false; } if (DaggerfallUnity.Settings.EnhancedCombatAI) { float moveSpeed = (enemyEntity.Stats.LiveSpeed + PlayerSpeedChanger.dfWalkBase) * MeshReader.GlobalScale; predictedTargetPos = PredictNextTargetPos(moveSpeed); } } if (detectedTarget && !hasEncounteredPlayer && target == Player) { hasEncounteredPlayer = true; // Check appropriate language skill to see if player can pacify enemy if (!questBehaviour && entityBehaviour && motor && (entityBehaviour.EntityType == EntityTypes.EnemyMonster || entityBehaviour.EntityType == EntityTypes.EnemyClass)) { 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 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); } } } } } }