예제 #1
0
        private void Move()
        {
            // Cancel movement and animations if paralyzed, but still allow gavity to take effect
            // This will have the (intentional for now) side-effect of making paralyzed flying enemies fall out of the air
            // Paralyzed swimming enemies will just freeze in place
            // Freezing anims also prevents the attack from triggering until paralysis cleared
            if (entityBehaviour.Entity.IsParalyzed)
            {
                mobile.FreezeAnims = true;

                if (swims)
                {
                    controller.Move(Vector3.zero);
                }
                else
                {
                    controller.SimpleMove(Vector3.zero);
                }

                return;
            }
            else
            {
                mobile.FreezeAnims = false;
            }

            // If hit, get knocked back
            if (knockBackSpeed > 0)
            {
                // Limit knockBackSpeed. This can be higher than what is actually used for the speed of motion,
                // making it last longer and do more damage if the enemy collides with something.
                if (knockBackSpeed > (40 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10)))
                {
                    knockBackSpeed = (40 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10));
                }

                if (knockBackSpeed > (5 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10)) &&
                    mobile.Summary.EnemyState != MobileStates.PrimaryAttack)
                {
                    mobile.ChangeEnemyState(MobileStates.Hurt);
                }

                // Actual speed of motion is limited
                Vector3 motion;
                if (knockBackSpeed <= (25 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10)))
                {
                    motion = knockBackDirection * knockBackSpeed;
                }
                else
                {
                    motion = knockBackDirection * (25 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10));
                }

                if (swims)
                {
                    WaterMove(motion);
                }
                else if (flies || isLevitating)
                {
                    controller.Move(motion * Time.deltaTime);
                }
                else
                {
                    controller.SimpleMove(motion);
                }

                if (classicUpdate)
                {
                    knockBackSpeed -= (5 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10));
                    if (knockBackSpeed <= (5 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10)) &&
                        mobile.Summary.EnemyState != MobileStates.PrimaryAttack)
                    {
                        mobile.ChangeEnemyState(MobileStates.Move);
                    }
                }

                return;
            }

            // Monster speed of movement follows the same formula as for when the player walks
            EnemyEntity entity    = entityBehaviour.Entity as EnemyEntity;
            float       moveSpeed = ((entity.Stats.LiveSpeed + PlayerSpeedChanger.dfWalkBase) / PlayerSpeedChanger.classicToUnitySpeedUnitRatio);

            // Reduced speed if playing a one-shot animation
            if (mobile.IsPlayingOneShot())
            {
                moveSpeed /= AttackSpeedDivisor;
            }

            // Remain idle when not hostile
            if (!isHostile)
            {
                mobile.ChangeEnemyState(MobileStates.Idle);
                return;
            }
            // If hostile but the enemy doesn't see the player, run the stealth check
            else if (senses.LastKnownPlayerPos == EnemySenses.ResetPlayerPos)
            {
                if (senses.StealthCheck())
                {
                    // Enemy noticed the player
                    senses.LastKnownPlayerPos = GameManager.Instance.PlayerObject.transform.position;
                    senses.DetectedPlayer     = true;
                }
                else
                {
                    // Enemy didn't notice the player
                    mobile.ChangeEnemyState(MobileStates.Idle);
                    senses.DetectedPlayer = false;
                    return;
                }
            }

            // As long as the player is directly seen/heard,
            // giveUpTimer is reset to full
            if (senses.PlayerInSight || senses.PlayerInEarshot)
            {
                giveUpTimer = 200;
            }
            else if (giveUpTimer == 0)
            {
                // Player lost for too long, or wasn't in sight/earshot to begin with. Time to give up
                senses.LastKnownPlayerPos = EnemySenses.ResetPlayerPos;
                return;
            }

            // GiveUpTimer value is from classic, so decrease at the speed of classic's update loop
            if (!senses.PlayerInSight && !senses.PlayerInEarshot &&
                giveUpTimer > 0 && classicUpdate)
            {
                giveUpTimer--;
            }

            // Enemy will keep moving towards last known player position
            targetPos = senses.LastKnownPlayerPos;

            // Flying enemies and slaughterfish aim for player face
            if (flies || isLevitating || (swims && mobile.Summary.Enemy.ID == (int)MonsterCareers.Slaughterfish))
            {
                targetPos.y += 0.9f;
            }
            else
            {
                // Ground enemies target at their own height
                // This avoids short enemies from stepping on each other as they approach the player
                // Otherwise, their target vector aims up towards the player
                var playerController = GameManager.Instance.PlayerController;
                var deltaHeight      = (playerController.height - controller.height) / 2;
                targetPos.y -= deltaHeight;
            }

            // Get direction & distance.
            var   direction = targetPos - transform.position;
            float distance  = direction.magnitude;

            // If attacking, randomly follow player with attack.
            if (mobile.Summary.EnemyState == MobileStates.PrimaryAttack)
            {
                if (!isAttackFollowsPlayerSet)
                {
                    attackFollowsPlayer      = (Random.Range(0f, 1f) > 0.5f);
                    isAttackFollowsPlayerSet = true;
                }
            }
            else
            {
                isAttackFollowsPlayerSet = false;
            }

            if (attackFollowsPlayer)
            {
                transform.forward = direction.normalized;
            }

            // Bow attack for enemies that have the appropriate animation
            if (senses.PlayerInSight && 360 * MeshReader.GlobalScale < distance && distance < 2048 * MeshReader.GlobalScale)
            {
                if (senses.TargetIsWithinYawAngle(22.5f))
                {
                    if (mobile.Summary.Enemy.HasRangedAttack1 && mobile.Summary.Enemy.ID > 129 && mobile.Summary.Enemy.ID != 132)
                    {
                        // Random chance to shoot bow
                        if (classicUpdate && DFRandom.rand() < 1000)
                        {
                            if (mobile.Summary.Enemy.HasRangedAttack1 && !mobile.Summary.Enemy.HasRangedAttack2 &&
                                mobile.Summary.EnemyState != MobileStates.RangedAttack1)
                            {
                                mobile.ChangeEnemyState(MobileStates.RangedAttack1);
                            }
                            else if (mobile.Summary.Enemy.HasRangedAttack2 && mobile.Summary.EnemyState != MobileStates.RangedAttack2)
                            {
                                mobile.ChangeEnemyState(MobileStates.RangedAttack2);
                            }
                        }
                        // Otherwise hold ground
                        else if (!mobile.IsPlayingOneShot())
                        {
                            mobile.ChangeEnemyState(MobileStates.Idle);
                        }
                    }
                    //else if (spellPoints > 0 && canCastRangeSpells && DFRandom.rand() % 40 == 0) TODO: Ranged spell shooting
                    //          CastRangedSpell();
                    //          Spell Cast Animation;
                    else
                    {
                        // If no ranged attack, move towards target
                        PursueTarget(direction, moveSpeed);
                    }
                }
                else
                {
                    if (!mobile.IsPlayingOneShot())
                    {
                        mobile.ChangeEnemyState(MobileStates.Move);
                    }
                    TurnToTarget(direction.normalized);
                    return;
                }
            }
            // Move towards target
            else if (distance > stopDistance)
            {
                PursueTarget(direction, moveSpeed);
            }
            else if (!senses.TargetIsWithinYawAngle(22.5f))
            {
                TurnToTarget(direction.normalized);
            }
            //else
            //{
            // TODO: Touch spells.
            //if (hasSpellPoints && attackCoolDownFinished && CanCastTouchSpells)
            //{
            //    Cast Touch Spell
            //    Spell Cast Animation
            //}
            //}
            else if (!senses.PlayerInSight && !senses.PlayerInEarshot)
            {
                mobile.ChangeEnemyState(MobileStates.Idle);
            }
        }
예제 #2
0
        private void Move()
        {
            // If hit, get knocked back
            if (knockBackSpeed > 0)
            {
                // Limit knockBackSpeed. This can be higher than what is actually used for the speed of motion,
                // making it last longer and do more damage if the enemy collides with something.
                if (knockBackSpeed > (40 / (PlayerMotor.classicToUnitySpeedUnitRatio / 10)))
                {
                    knockBackSpeed = (40 / (PlayerMotor.classicToUnitySpeedUnitRatio / 10));
                }

                if (knockBackSpeed > (5 / (PlayerMotor.classicToUnitySpeedUnitRatio / 10)) &&
                    mobile.Summary.EnemyState != MobileStates.PrimaryAttack)
                {
                    mobile.ChangeEnemyState(MobileStates.Hurt);
                }

                // Actual speed of motion is limited
                Vector3 motion;
                if (knockBackSpeed <= (25 / (PlayerMotor.classicToUnitySpeedUnitRatio / 10)))
                {
                    motion = knockBackDirection * knockBackSpeed;
                }
                else
                {
                    motion = knockBackDirection * (25 / (PlayerMotor.classicToUnitySpeedUnitRatio / 10));
                }

                if (flies)
                {
                    controller.Move(motion * Time.deltaTime);
                }
                else
                {
                    controller.SimpleMove(motion);
                }

                if (classicUpdate)
                {
                    knockBackSpeed -= (5 / (PlayerMotor.classicToUnitySpeedUnitRatio / 10));
                    if (knockBackSpeed <= (5 / (PlayerMotor.classicToUnitySpeedUnitRatio / 10)) &&
                        mobile.Summary.EnemyState != MobileStates.PrimaryAttack)
                    {
                        mobile.ChangeEnemyState(MobileStates.Move);
                    }
                }

                return;
            }

            // Monster speed of movement follows the same formula as for when the player walks
            EnemyEntity entity    = entityBehaviour.Entity as EnemyEntity;
            float       moveSpeed = ((entity.Stats.LiveSpeed + PlayerMotor.dfWalkBase) / PlayerMotor.classicToUnitySpeedUnitRatio);

            // Reduced speed if playing a one-shot animation
            if (mobile.IsPlayingOneShot())
            {
                moveSpeed /= AttackSpeedDivisor;
            }

            // Remain idle when not hostile
            if (!isHostile)
            {
                mobile.ChangeEnemyState(MobileStates.Idle);
                return;
            }
            // If hostile but the enemy doesn't see the player, run the stealth check
            else if (senses.LastKnownPlayerPos == EnemySenses.ResetPlayerPos)
            {
                if (senses.StealthCheck())
                {
                    // Enemy noticed the player
                    senses.LastKnownPlayerPos = GameManager.Instance.PlayerObject.transform.position;
                    senses.DetectedPlayer     = true;
                }
                else
                {
                    // Enemy didn't notice the player
                    mobile.ChangeEnemyState(MobileStates.Idle);
                    senses.DetectedPlayer = false;
                    return;
                }
            }

            // As long as the player is directly seen/heard,
            // giveUpTimer is reset to full
            if (senses.PlayerInSight || senses.PlayerInEarshot)
            {
                giveUpTimer = 200;
            }
            else if (giveUpTimer == 0)
            {
                // Player lost for too long, or wasn't in sight/earshot to begin with. Time to give up
                senses.LastKnownPlayerPos = EnemySenses.ResetPlayerPos;
                return;
            }

            // GiveUpTimer value is from classic, so decrease at the speed of classic's update loop
            if (!senses.PlayerInSight && !senses.PlayerInEarshot &&
                giveUpTimer > 0 && classicUpdate)
            {
                giveUpTimer--;
            }

            // Enemy will keep moving towards last known player position
            targetPos = senses.LastKnownPlayerPos;

            // Flying enemies aim for player face
            if (flies)
            {
                targetPos.y += 0.9f;
            }
            else
            {
                // Ground enemies target at their own height
                // This avoids short enemies from stepping on each other as they approach the player
                // Otherwise, their target vector aims up towards the player
                var playerController = GameManager.Instance.PlayerController;
                var deltaHeight      = (playerController.height - controller.height) / 2;
                targetPos.y -= deltaHeight;
            }

            // Get direction & distance and face target.
            // If attacking, randomly do not do so so player has a chance to see
            // attack animations other than those directly facing the player
            var   direction = targetPos - transform.position;
            float distance  = direction.magnitude;

            if (mobile.IsPlayingOneShot() && !isAttackFollowsPlayerSet)
            {
                attackFollowsPlayer      = (Random.Range(0f, 1f) > 0.5f);
                isAttackFollowsPlayerSet = true;
            }
            else if (!mobile.IsPlayingOneShot())
            {
                isAttackFollowsPlayerSet = false;
            }

            if (!mobile.IsPlayingOneShot() || !attackFollowsPlayer)
            {
                transform.forward = direction.normalized;
            }

            // Bow attack for enemies that have the appropriate animation
            if (senses.PlayerInSight && 360 * MeshReader.GlobalScale < distance && distance < 2048 * MeshReader.GlobalScale &&
                mobile.Summary.Enemy.HasRangedAttack1 && mobile.Summary.Enemy.ID > 129 && mobile.Summary.Enemy.ID != 132)
            {
                if (classicUpdate)
                {
                    // Random chance to shoot bow
                    if (DFRandom.rand() < 1000)
                    {
                        if (mobile.Summary.Enemy.HasRangedAttack1 && !mobile.Summary.Enemy.HasRangedAttack2 &&
                            mobile.Summary.EnemyState != MobileStates.RangedAttack1)
                        {
                            mobile.ChangeEnemyState(MobileStates.RangedAttack1);
                        }
                        else if (mobile.Summary.Enemy.HasRangedAttack2 && mobile.Summary.EnemyState != MobileStates.RangedAttack2)
                        {
                            mobile.ChangeEnemyState(MobileStates.RangedAttack2);
                        }
                    }
                    // Otherwise hold ground
                    else if (!mobile.IsPlayingOneShot())
                    {
                        mobile.ChangeEnemyState(MobileStates.Idle);
                    }
                }
            }
            // Move towards target
            else if (distance > stopDistance)
            {
                if (!mobile.IsPlayingOneShot())
                {
                    mobile.ChangeEnemyState(MobileStates.Move);
                }
                var motion = transform.forward * moveSpeed;

                // Prevent rat stacks (enemies don't stand on shorter enemies)
                AvoidEnemies(ref motion);

                if (flies)
                {
                    controller.Move(motion * Time.deltaTime);
                }
                else
                {
                    controller.SimpleMove(motion);
                }
            }
            else
            {
                // We have reached target, is player nearby?
                if (!senses.PlayerInSight && !senses.PlayerInEarshot)
                {
                    mobile.ChangeEnemyState(MobileStates.Idle);
                    senses.LastKnownPlayerPos = EnemySenses.ResetPlayerPos;
                }
            }
        }