using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Graphics; using StardewModdingAPI; using StardewModdingAPI.Events; using StardewValley; using StardewValley.Menus; using StardewValley.Tools; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Media; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Timers; using UIInfoSuite.Extensions; namespace UIInfoSuite.UIElements { class ExperienceBar : IDisposable { private const int MaxBarWidth = 175; //private float _currentExperience = 0; private int[] _currentExperience = new int[5]; private readonly List _experiencePointDisplays = new List(); private GameLocation _currentLocation = new GameLocation(); private readonly TimeSpan _levelUpPauseTime = TimeSpan.FromSeconds(2); private Color _iconColor = Color.White; private Color _experienceFillColor = Color.Blue; private Item _previousItem = null; private bool _experienceBarShouldBeVisible = false; private bool _shouldDrawLevelUp = false; private System.Timers.Timer _timeToDisappear = new System.Timers.Timer(); private readonly TimeSpan _timeBeforeExperienceBarFades = TimeSpan.FromSeconds(8); //private SoundEffectInstance _soundEffect; private Rectangle _levelUpIconRectangle = new Rectangle(120, 428, 10, 10); private bool _allowExperienceBarToFadeOut = true; private bool _showExperienceGain = true; private bool _showLevelUpAnimation = true; private bool _showExperienceBar = true; private readonly IModHelper _helper; private SoundPlayer _player; public ExperienceBar(IModHelper helper) { _helper = helper; String path = string.Empty; try { path = Path.Combine(_helper.DirectoryPath, "LevelUp.wav"); _player = new SoundPlayer(path); //path = path.Replace(Environment.CurrentDirectory, ""); //path = path.TrimStart(Path.DirectorySeparatorChar); //_soundEffect = SoundEffect.FromStream(TitleContainer.OpenStream(path)).CreateInstance(); //_soundEffect.Volume = 1f; } catch (Exception ex) { ModEntry.MonitorObject.Log("Error loading sound file from " + path + ": " + ex.Message + Environment.NewLine + ex.StackTrace, LogLevel.Error); } _timeToDisappear.Elapsed += StopTimerAndFadeBarOut; GraphicsEvents.OnPreRenderHudEvent += OnPreRenderHudEvent; PlayerEvents.Warped += RemoveAllExperiencePointDisplays; } public void Dispose() { PlayerEvents.LeveledUp -= OnLevelUp; GraphicsEvents.OnPreRenderHudEvent -= OnPreRenderHudEvent; PlayerEvents.Warped -= RemoveAllExperiencePointDisplays; _timeToDisappear.Stop(); _timeToDisappear.Dispose(); } public void ToggleLevelUpAnimation(bool showLevelUpAnimation) { _showLevelUpAnimation = showLevelUpAnimation; PlayerEvents.LeveledUp -= OnLevelUp; if (_showLevelUpAnimation) { PlayerEvents.LeveledUp += OnLevelUp; } } public void ToggleExperienceBarFade(bool allowExperienceBarToFadeOut) { _allowExperienceBarToFadeOut = allowExperienceBarToFadeOut; } public void ToggleShowExperienceGain(bool showExperienceGain) { for (int i = 0; i < _currentExperience.Length; ++i) _currentExperience[i] = Game1.player.experiencePoints[i]; _showExperienceGain = showExperienceGain; } public void ToggleShowExperienceBar(bool showExperienceBar) { //GraphicsEvents.OnPreRenderHudEvent -= OnPreRenderHudEvent; //PlayerEvents.Warped -= RemoveAllExperiencePointDisplays; _showExperienceBar = showExperienceBar; //if (showExperienceBar) //{ // GraphicsEvents.OnPreRenderHudEvent += OnPreRenderHudEvent; // PlayerEvents.Warped += RemoveAllExperiencePointDisplays; //} } private void OnLevelUp(object sender, EventArgsLevelUp e) { if (_showLevelUpAnimation) { switch (e.Type) { case EventArgsLevelUp.LevelType.Combat: _levelUpIconRectangle.X = 120; break; case EventArgsLevelUp.LevelType.Farming: _levelUpIconRectangle.X = 10; break; case EventArgsLevelUp.LevelType.Fishing: _levelUpIconRectangle.X = 20; break; case EventArgsLevelUp.LevelType.Foraging: _levelUpIconRectangle.X = 60; break; case EventArgsLevelUp.LevelType.Mining: _levelUpIconRectangle.X = 30; break; } _shouldDrawLevelUp = true; _timeToDisappear.Interval = _timeBeforeExperienceBarFades.TotalMilliseconds; _timeToDisappear.Start(); _experienceBarShouldBeVisible = true; float previousAmbientVolume = Game1.options.ambientVolumeLevel; float previousMusicVolume = Game1.options.musicVolumeLevel; //if (_soundEffect != null) // _soundEffect.Volume = previousMusicVolume <= 0.01f ? 0 : Math.Min(1, previousMusicVolume + 0.3f); //Task.Factory.StartNew(() => //{ // Thread.Sleep(100); // Game1.musicCategory.SetVolume((float)Math.Max(0, Game1.options.musicVolumeLevel - 0.3)); // Game1.ambientCategory.SetVolume((float)Math.Max(0, Game1.options.ambientVolumeLevel - 0.3)); // if (_soundEffect != null) // _soundEffect.Play(); //}); Task.Factory.StartNew(() => { Thread.Sleep(100); _player.Play(); }); Task.Factory.StartNew(() => { Thread.Sleep(_levelUpPauseTime); _shouldDrawLevelUp = false; //Game1.musicCategory.SetVolume(previousMusicVolume); //Game1.ambientCategory.SetVolume(previousAmbientVolume); }); } } private void StopTimerAndFadeBarOut(object sender, ElapsedEventArgs e) { _timeToDisappear.Stop(); _experienceBarShouldBeVisible = false; } private void RemoveAllExperiencePointDisplays(object sender, EventArgsPlayerWarped e) { _experiencePointDisplays.Clear(); } private void OnPreRenderHudEvent(object sender, EventArgs e) { if (!Game1.eventUp) { Item currentItem = Game1.player.CurrentItem; Rectangle rectangle1 = new Rectangle(10, 428, 10, 10); int experienceLevel = 0; int currentLevelIndex = -1; int experienceRequiredToLevel = -1; int experienceFromPreviousLevels = -1; int experienceEarnedThisLevel = -1; for (int i = 0; i < _currentExperience.Length; ++i) { if (_currentExperience[i] != Game1.player.experiencePoints[i]) { currentLevelIndex = i; break; } } if (currentLevelIndex > -1) { switch ((EventArgsLevelUp.LevelType)currentLevelIndex) { case EventArgsLevelUp.LevelType.Combat: { _experienceFillColor = new Color(204, 0, 3, 0.63f); rectangle1.X = 120; experienceLevel = Game1.player.combatLevel.Value; break; } case EventArgsLevelUp.LevelType.Farming: { _experienceFillColor = new Color(255, 251, 35, 0.38f); rectangle1.X = 10; experienceLevel = Game1.player.farmingLevel.Value; break; } case EventArgsLevelUp.LevelType.Fishing: { _experienceFillColor = new Color(17, 84, 252, 0.63f); rectangle1.X = 20; experienceLevel = Game1.player.fishingLevel.Value; break; } case EventArgsLevelUp.LevelType.Foraging: { _experienceFillColor = new Color(0, 234, 0, 0.63f); rectangle1.X = 60; experienceLevel = Game1.player.foragingLevel.Value; break; } case EventArgsLevelUp.LevelType.Mining: { _experienceFillColor = new Color(145, 104, 63, 0.63f); rectangle1.X = 30; experienceLevel = Game1.player.miningLevel.Value; break; } } experienceRequiredToLevel = GetExperienceRequiredToLevel(experienceLevel); experienceFromPreviousLevels = GetExperienceRequiredToLevel(experienceLevel - 1); experienceEarnedThisLevel = Game1.player.experiencePoints[currentLevelIndex] - experienceFromPreviousLevels; int experiencePreviouslyEarnedThisLevel = _currentExperience[currentLevelIndex] - experienceFromPreviousLevels; _currentExperience[currentLevelIndex] = Game1.player.experiencePoints[currentLevelIndex]; ShowExperienceBar(); if (_showExperienceGain) { _experiencePointDisplays.Add( new ExperiencePointDisplay( experienceEarnedThisLevel - experiencePreviouslyEarnedThisLevel, Game1.player.getLocalPosition(Game1.viewport))); } } else { if (currentItem is FishingRod) { _experienceFillColor = new Color(17, 84, 252, 0.63f); currentLevelIndex = 1; rectangle1.X = 20; experienceLevel = Game1.player.fishingLevel.Value; } else if (currentItem is Pickaxe) { _experienceFillColor = new Color(145, 104, 63, 0.63f); currentLevelIndex = 3; rectangle1.X = 30; experienceLevel = Game1.player.miningLevel.Value; } else if (currentItem is MeleeWeapon && currentItem.Name != "Scythe") { _experienceFillColor = new Color(204, 0, 3, 0.63f); currentLevelIndex = 4; rectangle1.X = 120; experienceLevel = Game1.player.combatLevel.Value; } else if (Game1.currentLocation is Farm && !(currentItem is Axe)) { _experienceFillColor = new Color(255, 251, 35, 0.38f); currentLevelIndex = 0; rectangle1.X = 10; experienceLevel = Game1.player.farmingLevel.Value; } else { _experienceFillColor = new Color(0, 234, 0, 0.63f); currentLevelIndex = 2; rectangle1.X = 60; experienceLevel = Game1.player.foragingLevel.Value; } experienceRequiredToLevel = GetExperienceRequiredToLevel(experienceLevel); experienceFromPreviousLevels = GetExperienceRequiredToLevel(experienceLevel - 1); experienceEarnedThisLevel = Game1.player.experiencePoints[currentLevelIndex] - experienceFromPreviousLevels; if (_previousItem != currentItem) ShowExperienceBar(); } _previousItem = currentItem; if (_shouldDrawLevelUp) { Vector2 playerLocalPosition = Game1.player.getLocalPosition(Game1.viewport); Game1.spriteBatch.Draw( Game1.mouseCursors, new Vector2( playerLocalPosition.X - 74, playerLocalPosition.Y - 130), _levelUpIconRectangle, _iconColor, 0, Vector2.Zero, Game1.pixelZoom, SpriteEffects.None, 0.85f); Game1.drawWithBorder( _helper.SafeGetString( LanguageKeys.LevelUp), Color.DarkSlateGray, Color.PaleTurquoise, new Vector2( playerLocalPosition.X - 28, playerLocalPosition.Y - 130)); } for (int i = _experiencePointDisplays.Count - 1; i >= 0; --i) { if (_experiencePointDisplays[i].IsInvisible) { _experiencePointDisplays.RemoveAt(i); } else { _experiencePointDisplays[i].Draw(); } } if (_experienceBarShouldBeVisible && _showExperienceBar) { int experienceDifferenceBetweenLevels = experienceRequiredToLevel - experienceFromPreviousLevels; int barWidth = (int)((double)experienceEarnedThisLevel / experienceDifferenceBetweenLevels * MaxBarWidth); DrawExperienceBar(barWidth, experienceEarnedThisLevel, experienceDifferenceBetweenLevels, experienceLevel, rectangle1); } } } private int GetExperienceRequiredToLevel(int currentLevel) { int amount = 0; switch (currentLevel) { case 0: amount = 100; break; case 1: amount = 380; break; case 2: amount = 770; break; case 3: amount = 1300; break; case 4: amount = 2150; break; case 5: amount = 3300; break; case 6: amount = 4800; break; case 7: amount = 6900; break; case 8: amount = 10000; break; case 9: amount = 15000; break; } return amount; } private void ShowExperienceBar() { if (_allowExperienceBarToFadeOut) { _timeToDisappear.Interval = _timeBeforeExperienceBarFades.TotalMilliseconds; _timeToDisappear.Start(); } else { _timeToDisappear.Stop(); } _experienceBarShouldBeVisible = true; } private void DrawExperienceBar(int barWidth, int experienceGainedThisLevel, int experienceRequiredForNextLevel, int currentLevel, Rectangle iconPosition) { float leftSide = Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Left; if (Game1.isOutdoorMapSmallerThanViewport()) { int num3 = Game1.currentLocation.map.Layers[0].LayerWidth * Game1.tileSize; leftSide += (Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Right - num3) / 2; } Game1.drawDialogueBox( (int)leftSide, Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Bottom - 160, 240, 160, false, true); Game1.spriteBatch.Draw( Game1.staminaRect, new Rectangle( (int)leftSide + 32, Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Bottom - 63, barWidth, 31), _experienceFillColor); Game1.spriteBatch.Draw( Game1.staminaRect, new Rectangle( (int)leftSide + 32, Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Bottom - 63, Math.Min(4, barWidth), 31), _experienceFillColor); Game1.spriteBatch.Draw( Game1.staminaRect, new Rectangle( (int)leftSide + 32, Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Bottom - 63, barWidth, 4), _experienceFillColor); Game1.spriteBatch.Draw( Game1.staminaRect, new Rectangle( (int)leftSide + 32, Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Bottom - 36, barWidth, 4), _experienceFillColor); ClickableTextureComponent textureComponent = new ClickableTextureComponent( "", new Rectangle( (int)leftSide - 36, Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Bottom - 80, 260, 100), "", "", Game1.mouseCursors, new Rectangle(0, 0, 0, 0), Game1.pixelZoom); if (textureComponent.containsPoint(Game1.getMouseX(), Game1.getMouseY())) { Game1.drawWithBorder( experienceGainedThisLevel + "/" + experienceRequiredForNextLevel, Color.Black, Color.Black, new Vector2( leftSide + 33, Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Bottom - 70)); } else { Game1.spriteBatch.Draw( Game1.mouseCursors, new Vector2( leftSide + 54, Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Bottom - 62), iconPosition, _iconColor, 0, Vector2.Zero, 2.9f, SpriteEffects.None, 0.85f); Game1.drawWithBorder( currentLevel.ToString(), Color.Black * 0.6f, Color.Black, new Vector2( leftSide + 33, Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Bottom - 70)); } } } }