/// <summary>
        /// Sets a new enemy state and restarts frame counter.
        /// Certain states are one-shot only (such as attack and hurt) and return to idle when completed.
        /// Continuous states (such as move) will keep looping until changed.
        /// </summary>
        /// <param name="state">New state.</param>
        /// <returns>Frames per second of new state.</returns>
        public float ChangeEnemyState(MobileStates state)
        {
            // Don't change state during animation freeze
            if (freezeAnims)
                return 0;

            // Don't reset frame to 0 for idle/move switches for enemies without idle animations
            bool resetFrame = true;

            if (!summary.Enemy.HasIdle &&
                ((summary.EnemyState == MobileStates.Idle && state == MobileStates.Move) ||
                (summary.EnemyState == MobileStates.Move && state == MobileStates.Idle)))
                resetFrame = false;

            // Only change if in a different state
            if (summary.EnemyState != state)
            {
                summary.EnemyState = state;
                if (resetFrame)
                    currentFrame = 0;
                ApplyEnemyState();
            }

            // Cannot set anims is not setup
            if (!summary.IsSetup)
                return 0;

            return summary.StateAnims[(int)summary.EnemyState].FramePerSecond;
        }
Esempio n. 2
0
 /// <summary>
 /// Initialise motor when activating.
 /// </summary>
 public void InitMotor()
 {
     seekCount = 0;
     SetFacing(MobileDirection.Random);
     currentNavPosition  = new DFPosition(-1, -1);
     targetNavPosition   = new DFPosition(-1, -1);
     targetScenePosition = transform.position;
     currentMobileState  = MobileStates.SeekingTile;
 }
        /// <summary>
        /// Sets a new enemy state and restarts frame counter.
        /// Certain states are one-shot only (such as attack and hurt) and return to idle when completed.
        /// Continuous states (such as move) will keep looping until changed.
        /// </summary>
        /// <param name="state">New state.</param>
        /// <returns>Frames per second of new state.</returns>
        public float ChangeEnemyState(MobileStates state)
        {
            // Only change if in a different state
            if (summary.EnemyState != state)
            {
                summary.EnemyState = state;
                currentFrame       = 0;
                ApplyEnemyState();
            }

            return(summary.StateAnims[(int)summary.EnemyState].FramePerSecond);
        }
        /// <summary>
        /// Gets cloned animation set for specified state.
        /// </summary>
        /// <param name="state">Enemy state.</param>
        /// <returns>Array of mobile animations.</returns>
        private MobileAnimation[] GetStateAnims(MobileStates state)
        {
            // Clone static animation state
            MobileAnimation[] anims;
            switch (state)
            {
            case MobileStates.Move:
                anims = (MobileAnimation[])EnemyBasics.MoveAnims.Clone();
                break;

            case MobileStates.PrimaryAttack:
                anims = (MobileAnimation[])EnemyBasics.PrimaryAttackAnims.Clone();
                break;

            case MobileStates.Hurt:
                anims = (MobileAnimation[])EnemyBasics.HurtAnims.Clone();
                break;

            case MobileStates.Idle:
                anims = (summary.Enemy.HasIdle) ? (MobileAnimation[])EnemyBasics.IdleAnims.Clone() : (MobileAnimation[])EnemyBasics.MoveAnims.Clone();
                break;

            case MobileStates.RangedAttack1:
                anims = (summary.Enemy.HasRangedAttack1) ? (MobileAnimation[])EnemyBasics.RangedAttack1Anims.Clone() : null;
                break;

            case MobileStates.RangedAttack2:
                anims = (summary.Enemy.HasRangedAttack2) ? (MobileAnimation[])EnemyBasics.RangedAttack2Anims.Clone() : null;
                break;

            default:
                return(null);
            }

            // Assign number number of frames per anim
            for (int i = 0; i < anims.Length; i++)
            {
                anims[i].NumFrames = summary.RecordFrames[anims[i].Record];
            }

            // If flying, set to faster flying animation speed
            if ((state == MobileStates.Move || state == MobileStates.Idle) && summary.Enemy.Behaviour == MobileBehaviour.Flying)
            {
                for (int i = 0; i < anims.Length; i++)
                {
                    anims[i].FramePerSecond = EnemyBasics.FlyAnimSpeed;
                }
            }

            return(anims);
        }
        /// <summary>
        /// Sets a new enemy state and restarts frame counter, if not freezed.
        /// Certain states are one-shot only (such as attack and hurt) and return to idle when completed.
        /// Continuous states (such as move) will keep looping until changed.
        /// </summary>
        /// <param name="newState">New state.</param>
        public void ChangeEnemyState(MobileStates newState)
        {
            // Don't change state during animation freeze
            if (FreezeAnims)
            {
                return;
            }

            // Only change if in a different state
            MobileStates currentState = EnemyState;

            if (currentState != newState)
            {
                ApplyEnemyStateChange(currentState, EnemyState = newState);
            }
        }
        /// <summary>
        /// Gets cloned animation set for specified state.
        /// </summary>
        /// <param name="state">Enemy state.</param>
        /// <returns>Array of mobile animations.</returns>
        private MobileAnimation[] GetStateAnims(MobileStates state)
        {
            // Clone static animation state
            MobileAnimation[] anims;
            switch (state)
            {
            case MobileStates.Move:
                anims = (MobileAnimation[])EnemyBasics.MoveAnims.Clone();
                break;

            case MobileStates.PrimaryAttack:
                anims = (MobileAnimation[])EnemyBasics.PrimaryAttackAnims.Clone();
                break;

            case MobileStates.Hurt:
                anims = (MobileAnimation[])EnemyBasics.HurtAnims.Clone();
                break;

            case MobileStates.Idle:
                anims = (summary.Enemy.HasIdle) ? (MobileAnimation[])EnemyBasics.IdleAnims.Clone() : (MobileAnimation[])EnemyBasics.MoveAnims.Clone();
                break;

            case MobileStates.RangedAttack1:
                anims = (summary.Enemy.HasRangedAttack1) ? (MobileAnimation[])EnemyBasics.RangedAttack1Anims.Clone() : null;
                break;

            case MobileStates.RangedAttack2:
                anims = (summary.Enemy.HasRangedAttack2) ? (MobileAnimation[])EnemyBasics.RangedAttack2Anims.Clone() : null;
                break;

            default:
                return(null);
            }

            // Assign number number of frames per anim
            for (int i = 0; i < anims.Length; i++)
            {
                anims[i].NumFrames = summary.RecordFrames[anims[i].Record];
            }

            return(anims);
        }
        protected override void ApplyEnemyStateChange(MobileStates currentState, MobileStates newState)
        {
            // Don't reset frame to 0 for idle/move switches for enemies without idle animations
            bool resetFrame = true;

            if (!summary.Enemy.HasIdle &&
                ((currentState == MobileStates.Idle && newState == MobileStates.Move) ||
                 (currentState == MobileStates.Move && newState == MobileStates.Idle)))
            {
                resetFrame = false;
            }

            if (resetFrame)
            {
                currentFrame = 0;
                animReversed = false;
            }

            ApplyEnemyState();
        }
Esempio n. 8
0
        /// <summary>
        /// Sets a new enemy state and restarts frame counter.
        /// Certain states are one-shot only (such as attack and hurt) and return to idle when completed.
        /// Continuous states (such as move) will keep looping until changed.
        /// </summary>
        /// <param name="state">New state.</param>
        /// <returns>Frames per second of new state.</returns>
        public float ChangeEnemyState(MobileStates state)
        {
            // Don't change state during animation freeze
            if (freezeAnims)
            {
                return(0);
            }

            // Only change if in a different state
            if (summary.EnemyState != state)
            {
                summary.EnemyState = state;
                currentFrame       = 0;
                ApplyEnemyState();
            }

            // Cannot set anims is not setup
            if (!summary.IsSetup)
            {
                return(0);
            }

            return(summary.StateAnims[(int)summary.EnemyState].FramePerSecond);
        }
        /// <summary>
        /// Gets cloned animation set for specified state.
        /// </summary>
        /// <param name="state">Enemy state.</param>
        /// <returns>Array of mobile animations.</returns>
        private MobileAnimation[] GetStateAnims(MobileStates state)
        {
            // Clone static animation state
            MobileAnimation[] anims;
            switch (state)
            {
            case MobileStates.Move:
                if ((MobileTypes)summary.Enemy.ID == MobileTypes.Ghost ||
                    (MobileTypes)summary.Enemy.ID == MobileTypes.Wraith)
                {
                    anims = (MobileAnimation[])EnemyBasics.GhostWraithMoveAnims.Clone();
                }
                else if ((MobileTypes)summary.Enemy.ID == MobileTypes.DaedraSeducer && summary.specialTransformationCompleted)
                {
                    anims = (MobileAnimation[])EnemyBasics.SeducerIdleMoveAnims.Clone();
                }
                else if ((MobileTypes)summary.Enemy.ID == MobileTypes.Slaughterfish)
                {
                    anims = (MobileAnimation[])EnemyBasics.SlaughterfishMoveAnims.Clone();
                }
                else
                {
                    anims = (MobileAnimation[])EnemyBasics.MoveAnims.Clone();
                }
                break;

            case MobileStates.PrimaryAttack:
                if ((MobileTypes)summary.Enemy.ID == MobileTypes.Ghost ||
                    (MobileTypes)summary.Enemy.ID == MobileTypes.Wraith)
                {
                    anims = (MobileAnimation[])EnemyBasics.GhostWraithAttackAnims.Clone();
                }
                else if ((MobileTypes)summary.Enemy.ID == MobileTypes.DaedraSeducer && summary.specialTransformationCompleted)
                {
                    anims = (MobileAnimation[])EnemyBasics.SeducerAttackAnims.Clone();
                }
                else
                {
                    anims = (MobileAnimation[])EnemyBasics.PrimaryAttackAnims.Clone();
                }
                break;

            case MobileStates.Hurt:
                if ((MobileTypes)summary.Enemy.ID == MobileTypes.DaedraSeducer && summary.specialTransformationCompleted)
                {
                    anims = (MobileAnimation[])EnemyBasics.SeducerIdleMoveAnims.Clone();
                }
                else
                {
                    anims = (MobileAnimation[])EnemyBasics.HurtAnims.Clone();
                }
                break;

            case MobileStates.Idle:
                if ((MobileTypes)summary.Enemy.ID == MobileTypes.Ghost ||
                    (MobileTypes)summary.Enemy.ID == MobileTypes.Wraith)
                {
                    anims = (MobileAnimation[])EnemyBasics.GhostWraithMoveAnims.Clone();
                }
                else if ((MobileTypes)summary.Enemy.ID == MobileTypes.DaedraSeducer && summary.specialTransformationCompleted)
                {
                    anims = (MobileAnimation[])EnemyBasics.SeducerIdleMoveAnims.Clone();
                }
                else if (summary.Enemy.FemaleTexture == 483 &&
                         summary.Enemy.Gender == MobileGender.Female)
                {
                    anims = (MobileAnimation[])EnemyBasics.FemaleThiefIdleAnims.Clone();
                }
                else if ((MobileTypes)summary.Enemy.ID == MobileTypes.Rat)
                {
                    anims = (MobileAnimation[])EnemyBasics.RatIdleAnims.Clone();
                }
                else if ((MobileTypes)summary.Enemy.ID == MobileTypes.Slaughterfish)
                {
                    anims = (MobileAnimation[])EnemyBasics.SlaughterfishMoveAnims.Clone();
                }
                else if (!summary.Enemy.HasIdle)
                {
                    anims = (MobileAnimation[])EnemyBasics.MoveAnims.Clone();
                }
                else
                {
                    anims = (MobileAnimation[])EnemyBasics.IdleAnims.Clone();
                }
                break;

            case MobileStates.RangedAttack1:
                anims = (summary.Enemy.HasRangedAttack1) ? (MobileAnimation[])EnemyBasics.RangedAttack1Anims.Clone() : null;
                break;

            case MobileStates.RangedAttack2:
                anims = (summary.Enemy.HasRangedAttack2) ? (MobileAnimation[])EnemyBasics.RangedAttack2Anims.Clone() : null;
                break;

            case MobileStates.Spell:
                if ((MobileTypes)summary.Enemy.ID == MobileTypes.DaedraSeducer && summary.specialTransformationCompleted)
                {
                    anims = (MobileAnimation[])EnemyBasics.SeducerAttackAnims.Clone();
                }
                else
                {
                    anims = (summary.Enemy.HasSpellAnimation) ? (MobileAnimation[])EnemyBasics.RangedAttack1Anims.Clone() : (MobileAnimation[])EnemyBasics.PrimaryAttackAnims.Clone();
                }
                break;

            case MobileStates.SeducerTransform1:
                anims = (summary.Enemy.HasSeducerTransform1) ? (MobileAnimation[])EnemyBasics.SeducerTransform1Anims.Clone() : null;
                break;

            case MobileStates.SeducerTransform2:
                anims = (summary.Enemy.HasSeducerTransform2) ? (MobileAnimation[])EnemyBasics.SeducerTransform2Anims.Clone() : null;
                break;

            default:
                return(null);
            }

            // Assign number of frames per anim
            for (int i = 0; i < anims.Length; i++)
            {
                anims[i].NumFrames = summary.RecordFrames[anims[i].Record];
            }

            // If flying, set to faster flying animation speed
            if ((state == MobileStates.Move || state == MobileStates.Idle) && summary.Enemy.Behaviour == MobileBehaviour.Flying)
            {
                for (int i = 0; i < anims.Length; i++)
                {
                    anims[i].FramePerSecond = EnemyBasics.FlyAnimSpeed;
                }
            }

            return(anims);
        }
Esempio n. 10
0
 void ChangeState(MobileStates newState)
 {
     lastMobileState    = currentMobileState;
     currentMobileState = newState;
 }
Esempio n. 11
0
        private void Update()
        {
            // Do nothing if game paused
            if (GameManager.IsGamePaused)
            {
                return;
            }

            // Do nothing if paralyzed
            if (entityBehaviour.Entity.IsParalyzed)
            {
                mobileBillboard.IsIdle = false;
                return;
            }

            // Must have a navgrid assigned
            if (!cityNavigation)
            {
                // Try to get navgrid from current player location
                // This is for mobiles dropped directly into world from editor
                // May be removed once fully runtime as intended
                if (!triedPlayerLocation)
                {
                    DaggerfallLocation playerLocation = GameManager.Instance.StreamingWorld.CurrentPlayerLocationObject;
                    if (playerLocation)
                    {
                        cityNavigation   = playerLocation.GetComponent <CityNavigation>();
                        transform.parent = playerLocation.transform;
                        ChangeState(MobileStates.SeekingTile);
                    }
                    triedPlayerLocation = true;
                }

                return;
            }

            // Go idle if near player
            distanceToPlayer = GameManager.Instance.PlayerMotor.DistanceToPlayer(transform.position);
            bool playerStandingStill = GameManager.Instance.PlayerMotor.IsStandingStill;

            if (!playerStandingStill && mobileBillboard.IsIdle)
            {
                // Switch animation state back to moving
                mobileBillboard.IsIdle = false;
                currentMobileState     = MobileStates.MovingForward;
            }
            else if (playerStandingStill && !mobileBillboard.IsIdle && distanceToPlayer < idleDistance)
            {
                // Switch animation state to idle
                mobileBillboard.IsIdle = true;
                currentMobileState     = MobileStates.Idle;
            }

            // Update based on current state
            switch (currentMobileState)
            {
            case MobileStates.SeekingTile:
                SeekingTile();
                break;

            case MobileStates.MovingForward:
                MovingForward();
                break;

            case MobileStates.Idle:
                // Do nothing for now
                break;
            }
        }
Esempio n. 12
0
        private void Update()
        {
            // Do nothing if game paused
            if (GameManager.IsGamePaused)
            {
                return;
            }

            // Do nothing if paralyzed
            if (entityBehaviour.Entity.IsParalyzed)
            {
                mobileBillboard.IsIdle = false;
                return;
            }

            // Must have a navgrid assigned
            if (!cityNavigation)
            {
                // Try to get navgrid from current player location
                // This is for mobiles dropped directly into world from editor
                // May be removed once fully runtime as intended
                if (!triedPlayerLocation)
                {
                    DaggerfallLocation playerLocation = GameManager.Instance.StreamingWorld.CurrentPlayerLocationObject;
                    if (playerLocation)
                    {
                        cityNavigation   = playerLocation.GetComponent <CityNavigation>();
                        transform.parent = playerLocation.transform;
                        ChangeState(MobileStates.SeekingTile);
                    }
                    triedPlayerLocation = true;
                }

                return;
            }

            // Go idle if near player
            distanceToPlayer = GameManager.Instance.PlayerMotor.DistanceToPlayer(transform.position);
            bool withinIdleDistance  = (distanceToPlayer < idleDistance);
            bool playerStandingStill = GameManager.Instance.PlayerMotor.IsStandingStill;
            bool sheathed            = GameManager.Instance.WeaponManager.Sheathed;
            bool invisible           = GameManager.Instance.PlayerEntity.IsInvisible;
            bool inBeastForm         = GameManager.Instance.PlayerEntity.IsInBeastForm;

            bool wantsToStop = playerStandingStill && withinIdleDistance && sheathed && !invisible && !inBeastForm;

            // greatly reduce # of calls to AreEnemiesNearby() by short-circuit evaluation
            if (wantsToStop && !GameManager.Instance.AreEnemiesNearby())
            {
                wantsToStop = true;
            }
            else
            {
                wantsToStop = false;
            }

            if (!wantsToStop && mobileBillboard.IsIdle)
            {
                // Switch animation state back to moving
                mobileBillboard.IsIdle = false;
                currentMobileState     = MobileStates.MovingForward;
            }
            else if (wantsToStop && !mobileBillboard.IsIdle)
            {
                // Switch animation state to idle
                mobileBillboard.IsIdle = true;
                currentMobileState     = MobileStates.Idle;
            }

            // Update based on current state
            switch (currentMobileState)
            {
            case MobileStates.SeekingTile:
                SeekingTile();
                break;

            case MobileStates.MovingForward:
                MovingForward();
                break;

            case MobileStates.Idle:
                // Do nothing for now
                break;
            }
        }
Esempio n. 13
0
 /// <summary>
 /// Applies change to enemy state. Implementation should perform transition to
 /// new animation (already assigned to <see cref="EnemyState"/> by caller).
 /// </summary>
 /// <param name="currentState">Enemy state before the change.</param>
 /// <param name="newState">Enemy state after the change.</param>
 protected abstract void ApplyEnemyStateChange(MobileStates currentState, MobileStates newState);
        /// <summary>
        /// Gets cloned animation set for specified state.
        /// </summary>
        /// <param name="state">Enemy state.</param>
        /// <returns>Array of mobile animations.</returns>
        private MobileAnimation[] GetStateAnims(MobileStates state)
        {
            // Clone static animation state
            MobileAnimation[] anims;
            switch (state)
            {
                case MobileStates.Move:
                    if ((MobileTypes)summary.Enemy.ID == MobileTypes.Ghost ||
                        (MobileTypes)summary.Enemy.ID == MobileTypes.Wraith)
                        anims = (MobileAnimation[])EnemyBasics.GhostWraithMoveAnims.Clone();
                    else
                        anims = (MobileAnimation[])EnemyBasics.MoveAnims.Clone();
                    break;
                case MobileStates.PrimaryAttack:
                    if ((MobileTypes)summary.Enemy.ID == MobileTypes.Ghost ||
                        (MobileTypes)summary.Enemy.ID == MobileTypes.Wraith)
                        anims = (MobileAnimation[])EnemyBasics.GhostWraithAttackAnims.Clone();
                    else
                        anims = (MobileAnimation[])EnemyBasics.PrimaryAttackAnims.Clone();
                    break;
                case MobileStates.Hurt:
                    anims = (MobileAnimation[])EnemyBasics.HurtAnims.Clone();
                    break;
                case MobileStates.Idle:
                    if ((MobileTypes)summary.Enemy.ID == MobileTypes.Ghost ||
                        (MobileTypes)summary.Enemy.ID == MobileTypes.Wraith)
                        anims = (MobileAnimation[])EnemyBasics.GhostWraithMoveAnims.Clone();
                    else if (summary.Enemy.FemaleTexture == 483 &&
                        summary.Enemy.Gender == MobileGender.Female)
                        anims = (MobileAnimation[])EnemyBasics.FemaleThiefIdleAnims.Clone();
                    else if ((MobileTypes)summary.Enemy.ID == MobileTypes.Rat)
                        anims = (MobileAnimation[])EnemyBasics.RatIdleAnims.Clone();
                    else if (!summary.Enemy.HasIdle)
                        anims = (MobileAnimation[])EnemyBasics.MoveAnims.Clone();
                    else
                        anims = (MobileAnimation[])EnemyBasics.IdleAnims.Clone();
                    break;
                case MobileStates.RangedAttack1:
                    anims = (summary.Enemy.HasRangedAttack1) ? (MobileAnimation[])EnemyBasics.RangedAttack1Anims.Clone() : null;
                    break;
                case MobileStates.RangedAttack2:
                    anims = (summary.Enemy.HasRangedAttack2) ? (MobileAnimation[])EnemyBasics.RangedAttack2Anims.Clone() : null;
                    break;
                case MobileStates.Spell:
                    anims = (summary.Enemy.HasSpellAnimation) ? (MobileAnimation[])EnemyBasics.RangedAttack1Anims.Clone() : (MobileAnimation[])EnemyBasics.PrimaryAttackAnims.Clone();
                    break;
                default:
                    return null;
            }

            // Assign number number of frames per anim
            for (int i = 0; i < anims.Length; i++)
                anims[i].NumFrames = summary.RecordFrames[anims[i].Record];

            // If flying, set to faster flying animation speed
            if ((state == MobileStates.Move || state == MobileStates.Idle) && summary.Enemy.Behaviour == MobileBehaviour.Flying)
                for (int i = 0; i < anims.Length; i++)
                    anims[i].FramePerSecond = EnemyBasics.FlyAnimSpeed;

            return anims;
        }
        /// <summary>
        /// Gets cloned animation set for specified state.
        /// </summary>
        /// <param name="state">Enemy state.</param>
        /// <returns>Array of mobile animations.</returns>
        private MobileAnimation[] GetStateAnims(MobileStates state)
        {
            // Clone static animation state
            MobileAnimation[] anims;
            switch (state)
            {
                case MobileStates.Move:
                    anims = (MobileAnimation[])EnemyBasics.MoveAnims.Clone();
                    break;
                case MobileStates.PrimaryAttack:
                    anims = (MobileAnimation[])EnemyBasics.PrimaryAttackAnims.Clone();
                    break;
                case MobileStates.Hurt:
                    anims = (MobileAnimation[])EnemyBasics.HurtAnims.Clone();
                    break;
                case MobileStates.Idle:
                    anims = (summary.Enemy.HasIdle) ? (MobileAnimation[])EnemyBasics.IdleAnims.Clone() : (MobileAnimation[])EnemyBasics.MoveAnims.Clone();
                    break;
                case MobileStates.RangedAttack1:
                    anims = (summary.Enemy.HasRangedAttack1) ? (MobileAnimation[])EnemyBasics.RangedAttack1Anims.Clone() : null;
                    break;
                case MobileStates.RangedAttack2:
                    anims = (summary.Enemy.HasRangedAttack2) ? (MobileAnimation[])EnemyBasics.RangedAttack2Anims.Clone() : null;
                    break;
                default:
                    return null;
            }

            // Assign number number of frames per anim
            for (int i = 0; i < anims.Length; i++)
                anims[i].NumFrames = summary.RecordFrames[anims[i].Record];
            
            return anims;
        }
        /// <summary>
        /// Sets a new enemy state and restarts frame counter.
        /// Certain states are one-shot only (such as attack and hurt) and return to idle when completed.
        /// Continuous states (such as move) will keep looping until changed.
        /// </summary>
        /// <param name="state">New state.</param>
        /// <returns>Frames per second of new state.</returns>
        public float ChangeEnemyState(MobileStates state)
        {
            // Only change if in a different state
            if (summary.EnemyState != state)
            {
                summary.EnemyState = state;
                currentFrame = 0;
                ApplyEnemyState();
            }

            // Cannot set anims is not setup
            if (!summary.IsSetup)
                return 0;

            return summary.StateAnims[(int)summary.EnemyState].FramePerSecond;
        }