/// <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; }
/// <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(); }
/// <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); }
void ChangeState(MobileStates newState) { lastMobileState = currentMobileState; currentMobileState = newState; }
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; } }
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; } }
/// <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; }