/// <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);
        }
Ejemplo n.º 2
0
        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);
            }
        }
Ejemplo n.º 4
0
        /// <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);
        }
Ejemplo n.º 5
0
        /// <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>();
     }
 }
Ejemplo n.º 7
0
        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
            });
        }
Ejemplo n.º 9
0
        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);
     }
 }
Ejemplo n.º 11
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.");
                 }
             }
         }
     }
 }
Ejemplo n.º 12
0
        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);
        }
Ejemplo n.º 13
0
 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;
                 }
             }
         }
     }
 }
Ejemplo n.º 14
0
 /// <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;
             }
         }
     }
 }
Ejemplo n.º 15
0
        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);
        }
Ejemplo n.º 16
0
        /// <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);
        }
Ejemplo n.º 18
0
        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
            });
        }
Ejemplo n.º 19
0
        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
            }
        }
Ejemplo n.º 20
0
        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);
        }
Ejemplo n.º 21
0
        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);
                }
            }
        }
Ejemplo n.º 23
0
        /// <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);
        }
Ejemplo n.º 24
0
        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);
        }
Ejemplo n.º 25
0
        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;
                }
            }
        }
Ejemplo n.º 26
0
        // 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);
                }
            }
        }
Ejemplo n.º 27
0
        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;
        }
Ejemplo n.º 28
0
        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;
                }
            }
        }
Ejemplo n.º 29
0
        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>());
            }
        }
Ejemplo n.º 30
0
        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);
                            }
                        }
                    }
                }
            }
        }