Exemplo n.º 1
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);
                            }
                        }
                    }
                }
            }
        }
Exemplo n.º 2
0
        void FixedUpdate()
        {
            classicUpdateTimer += Time.deltaTime;
            if (classicUpdateTimer >= PlayerEntity.ClassicUpdateInterval)
            {
                classicUpdateTimer = 0;
                classicUpdate      = true;
            }
            else
            {
                classicUpdate = false;
            }

            // Reset whether enemy would be spawned or not in classic.
            if (classicUpdate)
            {
                wouldBeSpawnedInClassic = 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 (classicUpdate && 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;
                    }
                }
            }

            if (classicUpdate)
            {
                classicTargetUpdateTimer += Time.deltaTime / systemTimerUpdatesDivisor;

                if (entityBehaviour.Target != null && entityBehaviour.Target.Entity.CurrentHealth <= 0)
                {
                    entityBehaviour.Target = null;
                }

                // NoTarget mode
                if ((GameManager.Instance.PlayerEntity.NoTargetMode || !motor.IsHostile) && entityBehaviour.Target == Player)
                {
                    entityBehaviour.Target = null;
                }

                if (entityBehaviour.Target == null)
                {
                    lastKnownTargetPos = ResetPlayerPos;
                }

                if ((motor.IsHostile && entityBehaviour.Target == null) || classicTargetUpdateTimer > 10) // Timing is 200 in classic, about 10 seconds.
                {
                    classicTargetUpdateTimer = 0f;

                    // Is enemy in area around player or can see player?
                    if (wouldBeSpawnedInClassic || playerInSight)
                    {
                        entityBehaviour.Target = GetTarget();
                    }

                    // Make targeted character also target this character if it doesn't have a target yet.
                    if (entityBehaviour.Target != null && entityBehaviour.Target.Target == null)
                    {
                        entityBehaviour.Target.Target = entityBehaviour;
                    }
                }
            }

            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);
                }

                Vector3 toTarget = ResetPlayerPos;
                if (entityBehaviour.Target != null)
                {
                    toTarget = entityBehaviour.Target.transform.position - transform.position;
                }

                if (toTarget != ResetPlayerPos)
                {
                    distanceToTarget  = toTarget.magnitude;
                    directionToTarget = toTarget.normalized;
                }

                if (entityBehaviour.Target == null)
                {
                    targetInSight  = false;
                    detectedTarget = false;
                    return;
                }

                targetInSight = CanSeeTarget(entityBehaviour.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(entityBehaviour.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 (classicUpdate)
                {
                    blockedByIllusionEffect = BlockedByIllusionEffect();
                    if (lastHadLOSTimer > 0)
                    {
                        lastHadLOSTimer--;
                    }
                }

                if (!blockedByIllusionEffect && (targetInSight || targetInEarshot))
                {
                    detectedTarget     = true;
                    lastKnownTargetPos = entityBehaviour.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 = entityBehaviour.Target.transform.position;
                    }
                }
                else
                {
                    detectedTarget = false;
                }

                if (detectedTarget && !hasEncounteredPlayer && entityBehaviour.Target == Player)
                {
                    hasEncounteredPlayer = true;

                    // Check appropriate language skill to see if player can pacify enemy
                    DaggerfallEntityBehaviour entityBehaviour = GetComponent <DaggerfallEntityBehaviour>();
                    if (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 (assumed) 1 in classic on success to make raising language skills easier
                            }
                            else if (languageSkill != DFCareer.Skills.Etiquette && languageSkill != DFCareer.Skills.Streetwise)
                            {
                                player.TallySkill(languageSkill, 1);
                            }
                        }
                    }
                }
            }
        }
Exemplo n.º 3
0
        void FixedUpdate()
        {
            classicUpdateTimer += Time.deltaTime;
            if (classicUpdateTimer >= PlayerEntity.ClassicUpdateInterval)
            {
                classicUpdateTimer = 0;
                classicUpdate      = true;
            }
            else
            {
                classicUpdate = false;
            }

            if (Player != null)
            {
                Vector3 toPlayer = Player.transform.position - transform.position;
                directionToPlayer = toPlayer.normalized;
                distanceToPlayer  = toPlayer.magnitude;

                playerInSight = CanSeePlayer();

                // Classic stealth mechanics would be interfered with by hearing, so only enable
                // hearing if the enemy has detected the player. If player has been seen we can omit hearing.
                if (detectedPlayer && !playerInSight)
                {
                    playerInEarshot = CanHearPlayer();
                }
                else
                {
                    playerInEarshot = false;
                }

                // Note: In classic an enemy can continue to track the player as long as their
                // giveUpTimer is > 0. Since the timer is reset to 200 on every detection this
                // would make chameleon and shade essentially useless, since the enemy is sure
                // to detect the player during one of the many AI updates. Here, the enemy has to
                // successfully see through the illusion spell each classic update to continue
                // to know where the player is.
                if (classicUpdate)
                {
                    blockedByIllusionEffect = BlockedByIllusionEffect();
                    if (lastHadLOSTimer > 0)
                    {
                        lastHadLOSTimer--;
                    }
                }

                if (!blockedByIllusionEffect && (playerInSight || playerInEarshot))
                {
                    detectedPlayer     = true;
                    lastKnownPlayerPos = Player.transform.position;
                    lastHadLOSTimer    = 200f;
                }
                else if (!blockedByIllusionEffect && StealthCheck())
                {
                    detectedPlayer = true;

                    // Only get the player's location from the stealth check if we haven't had
                    // actual LOS for a while. This gives better pursuit behavior since enemies
                    // will go to the last spot they saw the player instead of walking into walls.
                    if (lastHadLOSTimer <= 0)
                    {
                        lastKnownPlayerPos = Player.transform.position;
                    }
                }
                else
                {
                    detectedPlayer = false;
                }

                if (detectedPlayer && !hasEncounteredPlayer)
                {
                    hasEncounteredPlayer = true;

                    // Check appropriate language skill to see if player can pacify enemy
                    DaggerfallEntityBehaviour entityBehaviour = GetComponent <DaggerfallEntityBehaviour>();
                    EnemyMotor motor = GetComponent <EnemyMotor>();
                    if (entityBehaviour && motor &&
                        (entityBehaviour.EntityType == EntityTypes.EnemyMonster || entityBehaviour.EntityType == EntityTypes.EnemyClass))
                    {
                        EnemyEntity     enemyEntity   = entityBehaviour.Entity as EnemyEntity;
                        DFCareer.Skills languageSkill = enemyEntity.GetLanguageSkill();
                        if (languageSkill != DFCareer.Skills.None)
                        {
                            PlayerEntity player = GameManager.Instance.PlayerEntity;
                            if (FormulaHelper.CalculateEnemyPacification(player, languageSkill))
                            {
                                motor.IsHostile = false;
                                DaggerfallUI.AddHUDText(HardStrings.languagePacified.Replace("%e", enemyEntity.Name).Replace("%s", languageSkill.ToString()), 5);
                                player.TallySkill(languageSkill, 3);    // BCHG: increased skill uses from (assumed) 1 in classic on success to make raising language skills easier
                            }
                            else if (languageSkill != DFCareer.Skills.Etiquette && languageSkill != DFCareer.Skills.Streetwise)
                            {
                                player.TallySkill(languageSkill, 1);
                            }
                        }
                    }
                }
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Heal skill damage by amount.
        /// Does nothing if this effect does not damage skills.
        /// Skill will not heal past 0.
        /// </summary>
        /// <param name="skill">Skill to heal.</param>
        /// <param name="amount">Amount to heal. Must be positive value.</param>
        public virtual void HealSkillDamage(DFCareer.Skills skill, int amount)
        {
            if (amount < 0)
            {
                Debug.LogWarning("EntityEffect.HealSkillDamage() received a negative value for amount - ignoring.");
                return;
            }

            int result = GetSkillMod(skill) + amount;

            if (result > 0)
            {
                result = 0;
            }

            SetSkillMod(skill, result);
            Debug.LogFormat("Healed {0}'s {1} by {2} points", GetPeeredEntityBehaviour(manager).name, skill.ToString(), amount);
        }
Exemplo n.º 5
0
        void FixedUpdate()
        {
            if (Player != null)
            {
                Vector3 toPlayer = Player.transform.position - transform.position;
                directionToPlayer = toPlayer.normalized;
                distanceToPlayer  = toPlayer.magnitude;

                playerInSight = CanSeePlayer();

                if (playerInSight)
                {
                    detectedPlayer = true;
                }

                // Classic stealth mechanics would be interfered with by hearing, so only enable
                // hearing if the enemy has detected the player. If player has been seen we can omit hearing.
                if (detectedPlayer && !playerInSight)
                {
                    playerInEarshot = CanHearPlayer();
                }
                else
                {
                    playerInEarshot = false;
                }

                if ((playerInEarshot || playerInSight) && !hasEncounteredPlayer)
                {
                    hasEncounteredPlayer = true;

                    // Check appropriate language skill to see if player can pacify enemy
                    DaggerfallEntityBehaviour entityBehaviour = GetComponent <DaggerfallEntityBehaviour>();
                    EnemyMotor motor = GetComponent <EnemyMotor>();
                    if (entityBehaviour && motor &&
                        (entityBehaviour.EntityType == EntityTypes.EnemyMonster || entityBehaviour.EntityType == EntityTypes.EnemyClass))
                    {
                        EnemyEntity     enemyEntity   = entityBehaviour.Entity as EnemyEntity;
                        DFCareer.Skills languageSkill = enemyEntity.GetLanguageSkill();
                        if (languageSkill != DFCareer.Skills.None)
                        {
                            PlayerEntity player = GameManager.Instance.PlayerEntity;
                            if (FormulaHelper.CalculateEnemyPacification(player, languageSkill))
                            {
                                motor.IsHostile = false;
                                DaggerfallUI.AddHUDText(HardStrings.languagePacified.Replace("%e", enemyEntity.Name).Replace("%s", languageSkill.ToString()), 5);
                                player.TallySkill(languageSkill, 3);    // BCHG: increased skill uses from (assumed) 1 in classic on success to make raising language skills easier
                            }
                            else if (languageSkill != DFCareer.Skills.Etiquette && languageSkill != DFCareer.Skills.Streetwise)
                            {
                                player.TallySkill(languageSkill, 1);
                            }
                        }
                    }
                }
            }
        }