Rewriting the Stardew Symphony to just be more user friendly. Everything seems to work but it can't be tested until I finish the menu.

This commit is contained in:
JoshuaNavarro 2019-06-18 15:06:18 -07:00
parent c1509c9371
commit 824486d3b8
22 changed files with 2355 additions and 59 deletions

View File

@ -84,6 +84,7 @@
<Compile Include="Framework\Objects\InformationFiles\ObjectGUIDInfo.cs" />
<Compile Include="Framework\Objects\MultiTiledComponent.cs" />
<Compile Include="Framework\Objects\MultiTiledObject.cs" />
<Compile Include="Framework\Objects\ObjectManager.cs" />
<Compile Include="Framework\Player\Managers\MagicManager.cs" />
<Compile Include="Framework\Player\Managers\SittingInfo.cs" />
<Compile Include="Framework\Player\PlayerInfo.cs" />

View File

@ -152,6 +152,8 @@ namespace StardewSymphonyRemastered.Framework.Menus
Vector2 backPos = new Vector2(this.width * .1f + 64, this.height * .05f); //Put it to the right of the music disk
this.backButton = new Button("BackButton", new Rectangle((int)backPos.X, (int)backPos.Y, 64, 64), StardewSymphony.textureManager.getTexture("BackButton"), "", new Rectangle(0, 0, 16, 16), 4f, new Animation(new Rectangle(0, 0, 16, 16)), Color.White, Color.White, new ButtonFunctionality(null, null, null));
}
/// <summary>Runs every game tick to check for stuff.</summary>
@ -576,7 +578,7 @@ namespace StardewSymphonyRemastered.Framework.Menus
Rectangle menuSrcRectangle = new Rectangle(0, 0, menuTexture.getTexture().Width, menuTexture.getTexture().Height);
this.fancyButtons.Add(new Button("MenuIcon", new Rectangle((int)menuPlacement.X, (int)menuPlacement.Y, 64, 64), menuTexture, "Menu Music", menuSrcRectangle, menuScale, new Animation(menuSrcRectangle), Color.White, Color.White, new ButtonFunctionality(null, null, null)));
//Menu Icon placement.
//Location Icon placement.
Texture2DExtended locationTexture = StardewSymphony.textureManager.getTexture("HouseIcon");
float locationScale = 1.00f / (locationTexture.getTexture().Width / 64f);
Rectangle locationRect = new Rectangle(0, 0, locationTexture.getTexture().Width, locationTexture.getTexture().Height);
@ -606,19 +608,19 @@ namespace StardewSymphonyRemastered.Framework.Menus
Rectangle srcRect = new Rectangle(0, 0, springTexture.getTexture().Width, springTexture.getTexture().Height);
this.fancyButtons.Add(new Button("SpringButton", new Rectangle((int)springPlacement.X, (int)springPlacement.Y, 64, 64), springTexture, "Spring Music", srcRect, scale, new Animation(srcRect), Color.White, Color.White, new ButtonFunctionality(null, null, null)));
//Festival Icon placement.
//Summer Icon placement.
Texture2DExtended festivalTexture = StardewSymphony.textureManager.getTexture("SummerIcon");
float festivalScale = 1.00f / (festivalTexture.getTexture().Width / 64f);
Rectangle festivalSrcRect = new Rectangle(0, 0, festivalTexture.getTexture().Width, festivalTexture.getTexture().Height);
this.fancyButtons.Add(new Button("SummerButton", new Rectangle((int)summerPlacement.X, (int)summerPlacement.Y, 64, 64), festivalTexture, "Summer Music", festivalSrcRect, festivalScale, new Animation(festivalSrcRect), Color.White, Color.White, new ButtonFunctionality(null, null, null)));
//Event Icon placement.
//Fall Icon placement.
Texture2DExtended eventTexture = StardewSymphony.textureManager.getTexture("FallIcon");
float eventScale = 1.00f / (eventTexture.getTexture().Width / 64f);
Rectangle eventSrcRectangle = new Rectangle(0, 0, eventTexture.getTexture().Width, eventTexture.getTexture().Height);
this.fancyButtons.Add(new Button("FallButton", new Rectangle((int)fallPlacement.X, (int)fallPlacement.Y, 64, 64), eventTexture, "Fall Music", eventSrcRectangle, eventScale, new Animation(eventSrcRectangle), Color.White, Color.White, new ButtonFunctionality(null, null, null)));
//Menu Icon placement.
//Winter Icon placement.
Texture2DExtended menuTexture = StardewSymphony.textureManager.getTexture("WinterIcon");
float menuScale = 1.00f / (menuTexture.getTexture().Width / 64f);
Rectangle menuSrcRectangle = new Rectangle(0, 0, menuTexture.getTexture().Width, menuTexture.getTexture().Height);
@ -1466,7 +1468,7 @@ namespace StardewSymphonyRemastered.Framework.Menus
}
//Check for seasonal music triggers.
var songList = musicPack.SongInformation.getSongList(this.generateSongTriggerKeyFromSelection());
return songList.Value != null && songList.Value.Contains(musicPack.SongInformation.getSongFromList(songList.Value, this.currentSelectedSong.name));
return songList != null && songList.Contains(musicPack.SongInformation.getSongFromList(songList, this.currentSelectedSong.name));
}
/// <summary>Draws the menu and it's respective components depending on the drawmode that is currently set.</summary>

View File

@ -0,0 +1,644 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using StardewSymphonyRemastered.Framework.V2;
using StardewValley;
using StardewValley.Menus;
using StardustCore.Animations;
using StardustCore.UIUtilities;
using StardustCore.UIUtilities.MenuComponents;
using StardustCore.UIUtilities.MenuComponents.Delegates;
using StardustCore.UIUtilities.MenuComponents.Delegates.Functionality;
using StardustCore.UIUtilities.SpriteFonts;
namespace StardewSymphonyRemastered.Framework.Menus
{
public class MusicManagerMenuV2 : IClickableMenuExtended
{ /// <summary>Interface for the menu for selection music.</summary>
/// <summary>The different displays for this menu.</summary>
///
///Weather, time, day
public enum DrawMode
{
AlbumSelection,
AlbumFancySelection,
SongSelectionMode,
DifferentSelectionTypesModePage1, //Used for locations, events, festivals, menus (house, exclamation mark, star, and list/book icons respectively)
DifferentSelectionTypesModePage2, //Used for seasons
WeatherSelection,
FestivalSelection,
EventSelection,
MenuSelection,
TimeSelection,
LocationSelection,
DaySelection,
NothingElseToDisplay,
SelectedEvent,
SelectedFestival,
SelectedMenu,
SeasonSelection,
}
public List<Button> musicAlbumButtons;
public Button currentMusicPackAlbum;
public Button currentSelectedSong;
public Button currentlySelectedOption; //The big button for season, menu, event, and festivals
public Button currentlySelectedWeather; //Used to display what weather the user selected
public Button currentlySelectedTime;
public Button currentlySelectedLocation;
public Button currentlySelectedDay;
public Button currentlySelectedFestival;
public Button currentlySelectedEvent;
public Button currentlySelectedMenu;
public Button addButton;
public Button deleteButton;
public Button playButton;
public Button stopButton;
public Button backButton;
public bool selectedJustLocation;
public DrawMode drawMode;
public int currentAlbumIndex;
public int currentSongPageIndex;
public int locationPageIndex;
public int festivalPageIndex;
public int eventPageIndex;
public int menuPageIndex;
public int timePageIndex;
public List<Button> fancyButtons; //List that holds all of the buttons for the fancy album menu.
public int framesSinceLastUpdate; //Used to control how fast we can cycle through the menu.
public bool searchBoxSelected;
public MusicManagerMenuV2(float width, float height)
{
this.width = (int)width;
this.height = (int)height;
this.texturedStrings = new List<StardustCore.UIUtilities.SpriteFonts.Components.TexturedString>();
this.musicAlbumButtons = new List<Button>();
//thismusicAlbumButtons.Add(new Button("myButton", new Rectangle(100, 100, 64, 64), StardewSymphony.textureManager.getTexture("MusicNote").Copy(StardewSymphony.ModHelper), "mynote", new Rectangle(0, 0, 16, 16), 4f, new Animation(new Rectangle(0, 0, 16, 16)), Color.White, Color.White,new ButtonFunctionality(new DelegatePairing(hello,null),null,null),false)); //A button that does nothing on the left click.
this.fancyButtons = new List<Button>();
//Initialize music album icons.
int numOfButtons = 0;
int rows = 0;
foreach (MusicPackV2 musicPack in StardewSymphony.musicManager.MusicPacks.Values)
{
var sortedQuery = musicPack.SongInformation.songs.OrderBy(name => name);
//musicPack.SongInformation.listOfSongsWithoutTriggers = sortedQuery.ToList(); //Alphabetize.
if (musicPack.Icon == null)
{
Texture2DExtended texture = StardewSymphony.textureManager.getTexture("MusicDisk");
float scale = 1.00f / (texture.Width / 64f);
this.musicAlbumButtons.Add(new Button(musicPack.Name, new Rectangle(100 + (numOfButtons * 100), 125 + (rows * 100), 64, 64), texture, "", new Rectangle(0, 0, 16, 16), scale, new Animation(new Rectangle(0, 0, 16, 16)), StardustCore.IlluminateFramework.Colors.randomColor(), Color.White, new ButtonFunctionality(new DelegatePairing(null, new List<object> { musicPack }), null, new DelegatePairing(null, new List<object> { musicPack })), false));
}
else
{
float scale = 1.00f / (musicPack.Icon.Width / 64f);
this.musicAlbumButtons.Add(new Button(musicPack.Name, new Rectangle(100 + (numOfButtons * 100), 125 + (rows * 100), 64, 64), musicPack.Icon, "", new Rectangle(0, 0, musicPack.Icon.Width, musicPack.Icon.Height), scale, new Animation(new Rectangle(0, 0, 16, 16)), StardustCore.IlluminateFramework.LightColorsList.Black, StardustCore.IlluminateFramework.LightColorsList.Black, new ButtonFunctionality(new DelegatePairing(null, new List<object> { musicPack }), null, new DelegatePairing(null, new List<object> { musicPack })), false));
}
numOfButtons++;
if (numOfButtons > 8)
{
numOfButtons = 0;
rows++;
}
}
//determine background color
if (Game1.timeOfDay < 1200) this.dialogueBoxBackgroundColor = Color.SpringGreen;
if (Game1.timeOfDay >= 1200 && Game1.timeOfDay < 1800) this.dialogueBoxBackgroundColor = Color.White;
if (Game1.timeOfDay >= 1800) this.dialogueBoxBackgroundColor = Color.DarkViolet;
this.currentAlbumIndex = 0;
this.locationPageIndex = 0;
this.menuPageIndex = 0;
this.festivalPageIndex = 0;
this.eventPageIndex = 0;
this.timePageIndex = 0;
this.drawMode = DrawMode.AlbumFancySelection;
this.updateFancyButtons();
this.framesSinceLastUpdate = 0;
this.searchBoxSelected = false;
this.menuTextures = new List<Texture2DExtended>();
Vector2 playPos = new Vector2(this.width * .1f + 128 + 32, this.height * .05f + 128); //Put it to the right of the music disk
this.playButton = new Button("PlayButton", new Rectangle((int)playPos.X, (int)playPos.Y, 64, 64), StardewSymphony.textureManager.getTexture("PlayButton"), "", new Rectangle(0, 0, 16, 16), 4f, new Animation(new Rectangle(0, 0, 16, 16)), Color.White, Color.White, new ButtonFunctionality(null, null, null));
Vector2 stopPos = new Vector2(this.width * .1f + 192 + 32, this.height * .05f + 128); //Put it to the right of the music disk
this.stopButton = new Button("StopButton", new Rectangle((int)stopPos.X, (int)stopPos.Y, 64, 64), StardewSymphony.textureManager.getTexture("StopButton"), "", new Rectangle(0, 0, 16, 16), 4f, new Animation(new Rectangle(0, 0, 16, 16)), Color.White, Color.White, new ButtonFunctionality(null, null, null));
Vector2 addPos = new Vector2(this.width * .1f + 256 + 32, this.height * .05f + 128); //Put it to the right of the music disk
this.addButton = new Button("AddIcon", new Rectangle((int)addPos.X, (int)addPos.Y, 64, 64), StardewSymphony.textureManager.getTexture("AddIcon"), "", new Rectangle(0, 0, 32, 32), 2f, new Animation(new Rectangle(0, 0, 32, 32)), Color.White, Color.White, new ButtonFunctionality(null, null, null));
Vector2 delPos = new Vector2(this.width * .1f + 320 + 32, this.height * .05f + 128); //Put it to the right of the music disk
this.deleteButton = new Button("DeleteIcon", new Rectangle((int)delPos.X, (int)delPos.Y, 64, 64), StardewSymphony.textureManager.getTexture("DeleteIcon"), "", new Rectangle(0, 0, 32, 32), 2f, new Animation(new Rectangle(0, 0, 32, 32)), Color.White, Color.White, new ButtonFunctionality(null, null, null));
Vector2 backPos = new Vector2(this.width * .1f + 64, this.height * .05f); //Put it to the right of the music disk
this.backButton = new Button("BackButton", new Rectangle((int)backPos.X, (int)backPos.Y, 64, 64), StardewSymphony.textureManager.getTexture("BackButton"), "", new Rectangle(0, 0, 16, 16), 4f, new Animation(new Rectangle(0, 0, 16, 16)), Color.White, Color.White, new ButtonFunctionality(null, null, null));
}
public override void receiveLeftClick(int x, int y, bool playSound = true)
{
bool buttonSelected = false;
if (this.currentSelectedSong != null && this.currentMusicPackAlbum != null && this.playButton.containsPoint(x, y))
{
Game1.playSound("coin");
this.playSong();
return;
}
if (this.currentSelectedSong != null && this.currentMusicPackAlbum != null && this.stopButton.containsPoint(x, y))
{
Game1.playSound("coin");
this.stopSong();
return;
}
if (this.currentSelectedSong != null && this.currentMusicPackAlbum != null && this.addButton.containsPoint(x, y))
{
Game1.playSound("coin");
this.addSong();
return;
}
if (this.currentSelectedSong != null && this.currentMusicPackAlbum != null && this.deleteButton.containsPoint(x, y))
{
Game1.playSound("coin");
this.deleteSong();
return;
}
if (this.backButton.containsPoint(x, y))
{
Game1.playSound("coin");
this.goBack();
return;
}
if (this.drawMode == DrawMode.AlbumFancySelection)
{
int count = 0;
Button ok = Button.Empty();
foreach (var button in this.fancyButtons)
{
if (button.containsPoint(x, y) && button.buttonFunctionality.leftClick != null)
{
Game1.playSound("coin");
button.onLeftClick();
this.currentAlbumIndex += count - 3;
while (this.currentAlbumIndex < 0)
this.currentAlbumIndex = (this.musicAlbumButtons.Count - (this.currentAlbumIndex * -1));
ok = button;
}
if (button.buttonFunctionality.leftClick != null)
count++;
}
this.selectAlbum(ok);
this.updateFancyButtons();
return;
}
if (this.drawMode == DrawMode.SongSelectionMode)
{
int amountToShow = 6;
this.updateFancyButtons();
int amount;
if (0 + ((this.currentSongPageIndex + 1) * amountToShow) >= this.fancyButtons.Count)
{
amount = (0 + ((this.currentSongPageIndex + 1) * (amountToShow)) - this.fancyButtons.Count);
amount = amountToShow - amount;
if (amount < 0) amount = 0;
}
else if (this.fancyButtons.Count < amountToShow)
amount = this.fancyButtons.Count;
else
amount = amountToShow;
if (amount == 0 && this.currentSongPageIndex > 1)
this.currentSongPageIndex--;
var drawList = this.fancyButtons.GetRange(0 + (this.currentSongPageIndex * (amountToShow)), amount);
bool songSelected = false;
//Get a list of components to draw. And if I click one select the song.
foreach (var component in drawList)
{
if (component.containsPoint(x, y))
{
Game1.playSound("coin");
this.selectSong(component);
songSelected = true;
}
}
if (songSelected)
this.updateFancyButtons();
return;
}
}
/// <summary>
/// Update all of the buttons for the menu.
/// </summary>
public void updateFancyButtons()
{
//Album selection mode.
if (this.drawMode == DrawMode.AlbumFancySelection)
{
this.fancyButtons.Clear();
Vector4 placement = new Vector4((Game1.viewport.Width / 3), (Game1.viewport.Height / 4) + 128, this.width, this.height / 2);
//generate buttons
int offsetX = 200;
if (this.musicAlbumButtons.Count > 0)
{
for (int i = -3; i < 4; i++)
{
try
{
Button button = this.musicAlbumButtons.ElementAt(Math.Abs((this.currentAlbumIndex + i) % this.musicAlbumButtons.Count)).clone();
button.bounds = new Rectangle((int)placement.X + (i * 100) + offsetX, (int)placement.Y, 64, 64);
this.fancyButtons.Add(button);
}
catch
{
if (this.currentAlbumIndex + i == 0)
{
Button button = this.musicAlbumButtons.ElementAt(Math.Abs(0 % this.musicAlbumButtons.Count)).clone();
button.bounds = new Rectangle((int)placement.X + (i * 100) + offsetX, (int)placement.Y, 64, 64);
this.fancyButtons.Add(button);
}
else
{
try
{
Button button = this.musicAlbumButtons.ElementAt(Math.Abs(((this.currentAlbumIndex + i) - this.musicAlbumButtons.Count) % this.musicAlbumButtons.Count)).clone();
button.bounds = new Rectangle((int)placement.X + (i * 100) + offsetX, (int)placement.Y, 64, 64);
this.fancyButtons.Add(button);
}
catch
{
Button button = this.musicAlbumButtons.ElementAt(Math.Abs((this.currentAlbumIndex + i) + this.musicAlbumButtons.Count) % this.musicAlbumButtons.Count).clone();
button.bounds = new Rectangle((int)placement.X + (i * 100) + offsetX, (int)placement.Y, 64, 64);
this.fancyButtons.Add(button);
}
}
}
}
this.fancyButtons.Add(new Button("Outline", new Rectangle((int)placement.X + offsetX - 16, (int)placement.Y - 16, 64, 64), StardewSymphony.textureManager.getTexture("OutlineBox"), "", new Rectangle(0, 0, 16, 16), 6f, new Animation(new Rectangle(0, 0, 16, 16)), Color.White, Color.White, new ButtonFunctionality(null, null, new DelegatePairing(null, new List<object>())), false));
int count = 0;
foreach (var button in this.fancyButtons)
{
if (count == 3)
{
MusicPackV2 musicPack = (MusicPackV2)this.fancyButtons.ElementAt(count).buttonFunctionality.hover.paramaters[0];
this.texturedStrings.Clear();
this.texturedStrings.Add(SpriteFonts.vanillaFont.ParseString($"Current Album Name: {musicPack.Name}", new Vector2(button.bounds.X / 2, button.bounds.Y + 128), button.textColor));
button.hoverText = "";
}
count++;
}
}
}
//Song selection mode.
if (this.drawMode == DrawMode.SongSelectionMode)
{
this.fancyButtons.Clear();
//Vector4 placement = new Vector4((Game1.viewport.Width / 3), (Game1.viewport.Height / 4) + 128, this.width, this.height / 2);
MusicPackV2 musicPack = (MusicPackV2)this.currentMusicPackAlbum.buttonFunctionality.leftClick.paramaters[0];
Vector4 placement2 = new Vector4(this.width * .2f + 400, this.height * .05f, 5 * 100, this.height * .9f);
for (int i = 0; i < musicPack.SongInformation.songs.Count; i++)
{
//Allow 8 songs to be displayed per page.
Texture2DExtended texture = StardewSymphony.textureManager.getTexture("MusicNote");
float scale = 1.00f / (texture.getTexture().Width / 64f);
string songName = musicPack.SongInformation.songs.ElementAt(i).Key;
Rectangle srcRect = new Rectangle(0, 0, texture.getTexture().Width, texture.getTexture().Height);
this.fancyButtons.Add(new Button(songName, new Rectangle((int)placement2.X + 25, (int)placement2.Y + ((i % 6) * 100) + 100, 64, 64), texture, songName, srcRect, scale, new Animation(srcRect), Color.White, Color.White, new ButtonFunctionality(null, null, null)));
}
}
if(this.drawMode== DrawMode.DifferentSelectionTypesModePage1)
{
this.fancyButtons.Clear();
int buttonXPosition = 450;
//Season Icon placement.
Vector4 seasonPlacement = new Vector4(this.width * .2f + buttonXPosition, this.getFixedPositionFromMenu(0,64*2).Y, 5 * 100, this.height * .9f);
switch (Game1.currentSeason)
{
case "spring":
{
Texture2DExtended springTexture = StardewSymphony.textureManager.getTexture("SpringIcon");
if (springTexture == null)
{
if (StardewSymphony.Config.EnableDebugLog)
StardewSymphony.ModMonitor.Log("SPRING TEXTURE NULL!");
return;
}
float scale = 1.00f / (springTexture.getTexture().Width / 64f);
Rectangle srcRect = new Rectangle(0, 0, springTexture.getTexture().Width, springTexture.getTexture().Height);
this.fancyButtons.Add(new Button("SeasonIcon", new Rectangle((int)seasonPlacement.X, (int)seasonPlacement.Y, 64, 64), springTexture, "Seasonal Music", srcRect, scale, new Animation(srcRect), Color.White, Color.White, new ButtonFunctionality(null, null, null)));
}
break;
case "summer":
{
Texture2DExtended summerTexture = StardewSymphony.textureManager.getTexture("SummerIcon");
if (summerTexture == null)
{
if (StardewSymphony.Config.EnableDebugLog)
StardewSymphony.ModMonitor.Log("SUMMER TEXTURE NULL!");
return;
}
float scale = 1.00f / (summerTexture.getTexture().Width / 64f);
Rectangle srcRect = new Rectangle(0, 0, summerTexture.getTexture().Width, summerTexture.getTexture().Height);
this.fancyButtons.Add(new Button("SeasonIcon", new Rectangle((int)seasonPlacement.X, (int)seasonPlacement.Y, 64, 64), summerTexture, "Seasonal Music", srcRect, scale, new Animation(srcRect), Color.White, Color.White, new ButtonFunctionality(null, null, null)));
}
break;
case "fall":
{
Texture2DExtended fallTexture = StardewSymphony.textureManager.getTexture("FallIcon");
if (fallTexture == null)
{
if (StardewSymphony.Config.EnableDebugLog)
StardewSymphony.ModMonitor.Log("FALL TEXTURE NULL!");
return;
}
float scale = 1.00f / (fallTexture.getTexture().Width / 64f);
Rectangle srcRect = new Rectangle(0, 0, fallTexture.getTexture().Width, fallTexture.getTexture().Height);
this.fancyButtons.Add(new Button("SeasonIcon", new Rectangle((int)seasonPlacement.X, (int)seasonPlacement.Y, 64, 64), fallTexture, "Seasonal Music", srcRect, scale, new Animation(srcRect), Color.White, Color.White, new ButtonFunctionality(null, null, null)));
}
break;
case "winter":
{
Texture2DExtended winterTexture = StardewSymphony.textureManager.getTexture("WinterIcon");
if (winterTexture == null)
{
if (StardewSymphony.Config.EnableDebugLog)
StardewSymphony.ModMonitor.Log("WINTER TEXTURE NULL!");
return;
}
float scale = 1.00f / (winterTexture.getTexture().Width / 64f);
Rectangle srcRect = new Rectangle(0, 0, winterTexture.getTexture().Width, winterTexture.getTexture().Height);
this.fancyButtons.Add(new Button("SeasonIcon", new Rectangle((int)seasonPlacement.X, (int)seasonPlacement.Y, 64, 64), winterTexture, "Seasonal Music", srcRect, scale, new Animation(srcRect), Color.White, Color.White, new ButtonFunctionality(null, null, null)));
}
break;
}
Vector4 festivalPlacement = new Vector4(this.width * .2f + buttonXPosition, this.getFixedPositionFromMenu(0,64*3+16).Y, 6 * 100, this.height * .9f);
Vector4 eventPlacement = new Vector4(this.width * .2f + buttonXPosition, this.getFixedPositionFromMenu(0, 64*4+(16*2)).Y, 7 * 100, this.height * .9f);
Vector4 menuPlacement = new Vector4(this.width * .2f + buttonXPosition, this.getFixedPositionFromMenu(0, 64*5+(16*3)).Y, 8 * 100, this.height * .9f);
Vector4 locationPlacement = new Vector4(this.width * .2f + buttonXPosition, this.getFixedPositionFromMenu(0, 64*6+(16*4)).Y, 9 * 100, this.height * .9f);
Vector4 weatherPlacement = new Vector4(this.width * .2f + buttonXPosition, this.getFixedPositionFromMenu(0, 64 * 7 + (16 * 5)).Y, 9 * 100, this.height * .9f);
//Festival Icon placement.
Texture2DExtended festivalTexture = StardewSymphony.textureManager.getTexture("FestivalIcon");
float festivalScale = 1.00f / (festivalTexture.getTexture().Width / 64f);
Rectangle festivalSrcRect = new Rectangle(0, 0, festivalTexture.getTexture().Width, festivalTexture.getTexture().Height);
this.fancyButtons.Add(new Button("FestivalIcon", new Rectangle((int)festivalPlacement.X, (int)festivalPlacement.Y, 64, 64), festivalTexture, "Festival Music", festivalSrcRect, festivalScale, new Animation(festivalSrcRect), Color.White, Color.White, new ButtonFunctionality(null, null, null)));
//Event Icon placement.
Texture2DExtended eventTexture = StardewSymphony.textureManager.getTexture("EventIcon");
float eventScale = 1.00f / (eventTexture.getTexture().Width / 64f);
Rectangle eventSrcRectangle = new Rectangle(0, 0, eventTexture.getTexture().Width, eventTexture.getTexture().Height);
this.fancyButtons.Add(new Button("EventIcon", new Rectangle((int)eventPlacement.X, (int)eventPlacement.Y, 64, 64), eventTexture, "Event Music", eventSrcRectangle, eventScale, new Animation(eventSrcRectangle), Color.White, Color.White, new ButtonFunctionality(null, null, null)));
//Menu Icon placement.
Texture2DExtended menuTexture = StardewSymphony.textureManager.getTexture("MenuIcon");
float menuScale = 1.00f / (menuTexture.getTexture().Width / 64f);
Rectangle menuSrcRectangle = new Rectangle(0, 0, menuTexture.getTexture().Width, menuTexture.getTexture().Height);
this.fancyButtons.Add(new Button("MenuIcon", new Rectangle((int)menuPlacement.X, (int)menuPlacement.Y, 64, 64), menuTexture, "Menu Music", menuSrcRectangle, menuScale, new Animation(menuSrcRectangle), Color.White, Color.White, new ButtonFunctionality(null, null, null)));
//Location Icon placement.
Texture2DExtended locationTexture = StardewSymphony.textureManager.getTexture("HouseIcon");
float locationScale = 1.00f / (locationTexture.getTexture().Width / 64f);
Rectangle locationRect = new Rectangle(0, 0, locationTexture.getTexture().Width, locationTexture.getTexture().Height);
this.fancyButtons.Add(new Button("LocationButton", new Rectangle((int)locationPlacement.X, (int)locationPlacement.Y, 64, 64), locationTexture, "Location Music", locationRect, locationScale, new Animation(locationRect), Color.White, Color.White, new ButtonFunctionality(null, null, null)));
Texture2DExtended weatherTexture = StardewSymphony.textureManager.getTexture("WeatherIcon");
float weatherScale = 1.00f / (weatherTexture.getTexture().Width / 64f);
Rectangle weatherRect = new Rectangle(0, 0, weatherTexture.getTexture().Width, weatherTexture.getTexture().Height);
this.fancyButtons.Add(new Button("WeatherButton", new Rectangle((int)weatherPlacement.X, (int)weatherPlacement.Y, 64, 64), weatherTexture, "Weather Music", weatherRect, weatherScale, new Animation(weatherRect), Color.White, Color.White, new ButtonFunctionality(null, null, null)));
}
}
public override void update(GameTime time)
{
int updateNumber = 20;
//Used for updating the album select screen.
if (this.drawMode == DrawMode.AlbumFancySelection)
{
if (this.framesSinceLastUpdate == updateNumber)
{
var state = Keyboard.GetState();
if (state.IsKeyDown(Keys.Left) || state.IsKeyDown(Keys.A))
{
this.currentAlbumIndex--;
if (this.currentAlbumIndex < 0) this.currentAlbumIndex = this.musicAlbumButtons.Count - 1;
this.updateFancyButtons();
this.framesSinceLastUpdate = 0;
Game1.playSound("shwip");
}
if (state.IsKeyDown(Keys.Right) || state.IsKeyDown(Keys.D))
{
this.currentAlbumIndex++;
if (this.currentAlbumIndex == this.musicAlbumButtons.Count) this.currentAlbumIndex = 0;
this.updateFancyButtons();
this.framesSinceLastUpdate = 0;
Game1.playSound("shwip");
}
}
else
{
this.framesSinceLastUpdate++;
}
}
//Used for updating the song selection screen.
if (this.drawMode == DrawMode.SongSelectionMode)
{
if (this.framesSinceLastUpdate == updateNumber)
{
var state = Keyboard.GetState();
if (state.IsKeyDown(Keys.Left) || state.IsKeyDown(Keys.A))
{
if (this.currentSongPageIndex > 0)
this.currentSongPageIndex--;
this.updateFancyButtons();
this.framesSinceLastUpdate = 0;
Game1.playSound("shwip");
}
if (state.IsKeyDown(Keys.Right) || state.IsKeyDown(Keys.D))
{
this.currentSongPageIndex++;
this.updateFancyButtons();
this.framesSinceLastUpdate = 0;
Game1.playSound("shwip");
}
}
else
this.framesSinceLastUpdate++;
}
}
public void playSong()
{
}
public void stopSong()
{
}
public void addSong()
{
}
public void deleteSong()
{
}
public void goBack()
{
}
public void selectAlbum(Button b)
{
if (b.label == "Null")
return;
this.currentMusicPackAlbum = b.clone(new Vector2(this.width * .1f + 64, this.height * .05f + 128));
this.texturedStrings.Clear();
this.texturedStrings.Add(SpriteFonts.vanillaFont.ParseString("Name:" + b.name, new Vector2(this.width * .1f, this.height * .05f + 256), b.textColor, false));
this.drawMode = DrawMode.SongSelectionMode;
}
/// <summary>Select a given song from the menu.</summary>
public void selectSong(Button b)
{
if (b.label == "Null")
return;
this.currentSelectedSong = b.clone(new Vector2(this.width * .1f + 64, this.height * .05f + 256));
this.drawMode = DrawMode.DifferentSelectionTypesModePage1;
}
/// <summary>
/// Draw the menu.
/// </summary>
/// <param name="b"></param>
public override void draw(SpriteBatch b)
{
Vector4 placement = new Vector4(this.width * .1f, this.height * .05f - 96, 4 * 100 + 50, this.height + 32);
Vector4 placement2 = new Vector4(this.width * .2f + 400, this.height * .05f - 96, 5 * 100, this.height + 32);
if (this.drawMode == DrawMode.AlbumSelection)
{
this.drawDialogueBoxBackground();
foreach (var button in this.musicAlbumButtons)
button.draw(b);
}
if (this.drawMode == DrawMode.AlbumFancySelection)
{
Vector4 placement3 = new Vector4(Game1.viewport.Width / 4 - 50, Game1.viewport.Height / 4, 8 * 100, 128 * 2);
this.drawDialogueBoxBackground((int)placement3.X, (int)placement3.Y, (int)placement3.Z, (int)placement3.W, new Color(new Vector4(this.dialogueBoxBackgroundColor.ToVector3(), 0)));
foreach (var button in this.fancyButtons)
button.draw(b);
foreach (var str in this.texturedStrings)
str.draw(b);
}
if (this.drawMode == DrawMode.SongSelectionMode)
{
this.drawDialogueBoxBackground((int)placement.X, (int)placement.Y, (int)placement.Z, (int)placement.W, new Color(new Vector4(this.dialogueBoxBackgroundColor.ToVector3(), 255)));
this.drawDialogueBoxBackground((int)placement2.X, (int)placement2.Y, (int)placement2.Z, (int)placement2.W, new Color(new Vector4(this.dialogueBoxBackgroundColor.ToVector3(), 255)));
int amountToShow = 6;
this.currentMusicPackAlbum.draw(b);
int amount;
if (0 + ((this.currentSongPageIndex + 1) * amountToShow) >= this.fancyButtons.Count)
{
amount = (0 + ((this.currentSongPageIndex + 1) * (amountToShow)) - this.fancyButtons.Count);
amount = amountToShow - amount;
if (amount < 0) amount = 0;
}
else if (this.fancyButtons.Count < amountToShow)
amount = this.fancyButtons.Count;
else
amount = amountToShow;
if (amount == 0 && this.currentSongPageIndex > 1)
this.currentSongPageIndex--;
var drawList = this.fancyButtons.GetRange(0 + (this.currentSongPageIndex * (amountToShow)), amount);
foreach (var button in drawList)
button.draw(b);
foreach (var str in this.texturedStrings)
str.draw(b);
}
if (this.drawMode == DrawMode.DifferentSelectionTypesModePage1)
{
this.drawDialogueBoxBackground((int)placement.X, (int)placement.Y, (int)placement.Z, (int)placement.W, new Color(new Vector4(this.dialogueBoxBackgroundColor.ToVector3(), 255)));
this.drawDialogueBoxBackground((int)placement2.X, (int)placement2.Y, (int)placement2.Z, (int)placement2.W, new Color(new Vector4(this.dialogueBoxBackgroundColor.ToVector3(), 255)));
this.currentMusicPackAlbum.draw(b);
this.currentSelectedSong.draw(b);
foreach (Button button in this.fancyButtons)
button.draw(b);
foreach (var str in this.texturedStrings)
str.draw(b);
//draw election buttons here???
}
this.drawMouse(b);
}
}
}

View File

@ -105,7 +105,7 @@ namespace StardewSymphonyRemastered.Framework
{
try
{
var songList = v.Value.SongInformation.getSongList(songListKey).Value;
var songList = v.Value.SongInformation.getSongList(songListKey);
if (songList.Count > 0)
listOfValidDictionaries.Add(v.Value, songList);
}
@ -170,8 +170,32 @@ namespace StardewSymphonyRemastered.Framework
}
/// <summary>Select the actual song to be played right now based on the selector key. The selector key should be called when the player's location changes.</summary>
public void selectMusic(string songListKey)
public void selectMusic(string songListKey,bool warpCheck=false)
{
StardewSymphony.DebugLog(SongSpecifics.GetKeySpecificity(songListKey).ToString());
StardewSymphony.DebugLog(songListKey);
//Prevent generic song changes when running about.
if (SongSpecifics.GetKeySpecificity(songListKey) == SongSpecifics.SongKeyType.None) return;
if (SongSpecifics.IsKeyGeneric(songListKey))
{
if(this.CurrentMusicPack != null)
{
if (this.CurrentMusicPack.IsPlaying()) return;
}
}
//If I have warped and the key only is to be played when time changes prevent a new song from playing.
//If the key is more specific (I.E has a location associated with it) then music will change.
if (warpCheck==true && SongSpecifics.IsKeyTimeSpecific(songListKey)) {
if (this.CurrentMusicPack != null)
{
if (this.CurrentMusicPack.IsPlaying()) return;
}
}
// stop timer timer when music is selected
this.Timer.Enabled = false;
@ -327,7 +351,7 @@ namespace StardewSymphonyRemastered.Framework
{
try
{
var songList = v.Value.SongInformation.getSongList(SongSpecifics.getCurrentConditionalString(true)).Value;
var songList = v.Value.SongInformation.getSongList(SongSpecifics.getCurrentConditionalString(true));
if (songList == null) return null;
if (songList.Count > 0)
{

View File

@ -29,6 +29,16 @@ namespace StardewSymphonyRemastered.Framework
private readonly string[] timesOfDay;
public static char seperator = '_';
public enum SongKeyType
{
None,
Seasonal,
Weather,
Time,
Location,
DayOfWeek
}
public string[] TimesOfDay
{
get
@ -149,7 +159,6 @@ namespace StardewSymphonyRemastered.Framework
if (name == menuNamespaceName)
{
key = name;
StardewSymphony.menuChangedMusic = true;
return key;
}
}
@ -385,7 +394,7 @@ namespace StardewSymphonyRemastered.Framework
}
if (locName.Contains("Cabin") || Game1.currentLocation.isFarmBuildingInterior())
locName = Game1.currentLocation.uniqueName;
locName = Game1.currentLocation.uniqueName.Value;
return locName;
}
@ -398,6 +407,57 @@ namespace StardewSymphonyRemastered.Framework
#endregion
public static SongKeyType GetKeySpecificity(string key)
{
string[] splits = key.Split(seperator);
if (splits.Length == 5) return SongKeyType.DayOfWeek;
if (splits.Length == 4) return SongKeyType.Location;
if (splits.Length == 3) return SongKeyType.Time;
if (splits.Length == 2) return SongKeyType.Weather;
if (splits.Length == 1) return SongKeyType.Seasonal;
return SongKeyType.None;
}
public static bool IsKeyLocationSpecific(string key)
{
SongKeyType type=GetKeySpecificity(key);
if (type == SongKeyType.Location || type == SongKeyType.DayOfWeek) return true;
return false;
}
/// <summary>
/// Checks if the key used is associated with playing at certain times.
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static bool IsKeyTimeSensitive(string key)
{
SongKeyType type = GetKeySpecificity(key);
if (type == SongKeyType.Location || type == SongKeyType.DayOfWeek || type== SongKeyType.Time) return true;
return false;
}
/// <summary>
/// Checks if the key is only as specific as having a time set. (i.e not location or day specific)
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static bool IsKeyTimeSpecific(string key)
{
SongKeyType type = GetKeySpecificity(key);
if (type == SongKeyType.Time) return true;
return false;
}
public static bool IsKeyGeneric(string key)
{
SongKeyType type = GetKeySpecificity(key);
if (type == SongKeyType.Weather || type == SongKeyType.Seasonal) return true;
return false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// Non-Static Methods //
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
@ -512,21 +572,12 @@ namespace StardewSymphonyRemastered.Framework
}
}
/// <summary>Used to access the master list of songs this music pack contains.</summary>
public KeyValuePair<string, List<string>> getSongList(string key)
public List<string> getSongList(string key)
{
if (!this.listOfSongsWithTriggers.ContainsKey(key))
return new KeyValuePair<string, List<string>>("", null);
return null;
//This is just the plain song name with no extra info.
foreach (KeyValuePair<string, List<string>> pair in this.listOfSongsWithTriggers)
{
//StardewSymphony.ModMonitor.Log(pair.Key);
if (pair.Key == key)
return pair;
}
return new KeyValuePair<string, List<string>>("", null);
return this.listOfSongsWithTriggers[key];
}
public List<string> getFestivalMusic()
@ -546,7 +597,7 @@ namespace StardewSymphonyRemastered.Framework
StardewSymphony.ModMonitor.Log(songListKey);
var songKeyPair = this.getSongList(songListKey); //Get the trigger list
if (songKeyPair.Value == null)
if (songKeyPair == null)
{
if (StardewSymphony.Config.EnableDebugLog)
StardewSymphony.ModMonitor.Log("For some reason you are trying to add a song to a list that is null. The name of the song list is " + songListKey);
@ -559,7 +610,7 @@ namespace StardewSymphonyRemastered.Framework
StardewSymphony.ModMonitor.Log("For some reason you are trying to add a song that is null. The name of the song is " + songName);
return;
}
songKeyPair.Value.Add(song); //add the song from master pool to the trigger list
songKeyPair.Add(song); //add the song from master pool to the trigger list
}
public void addSongToFestivalList(string songName)
@ -592,8 +643,8 @@ namespace StardewSymphonyRemastered.Framework
public void removeSongFromTriggerList(string songListKey, string songName)
{
var songKeyPair = this.getSongList(songListKey);
string song = this.getSongFromList(songKeyPair.Value, songName);
songKeyPair.Value.Remove(song);
string song = this.getSongFromList(songKeyPair, songName);
songKeyPair.Remove(song);
}
/// <summary>Remove a song from the event list.</summary>

View File

@ -0,0 +1,297 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using StardewValley;
namespace StardewSymphonyRemastered.Framework.V2
{
/// <summary>Manages all music for the mod.</summary>
public class MusicManagerV2
{
/*********
** Fields
*********/
/// <summary>The RNG used to select music packs and songs.</summary>
private readonly Random Random = new Random();
/// <summary>The delay timer between songs.</summary>
private readonly Timer Timer = new Timer();
private bool lastSongWasLocationSpecific;
/*********
** Accessors
*********/
/// <summary>The loaded music packs.</summary>
public IDictionary<string, MusicPackV2> MusicPacks { get; } = new Dictionary<string, MusicPackV2>();
/// <summary>The current music pack playing music, if any.</summary>
public MusicPackV2 CurrentMusicPack { get; private set; }
/*********
** Public methods
*********/
/// <summary>Construct an instance.</summary>
public MusicManagerV2()
{
this.Timer.Elapsed += this.OnTimerFinished;
}
/// <summary>Swap between referenced music packs and stop the current song.</summary>
/// <param name="nameOfNewMusicPack">The name of the new music pack to select.</param>
public void SwapMusicPacks(string nameOfNewMusicPack)
{
if (!this.MusicPacks.TryGetValue(nameOfNewMusicPack, out MusicPackV2 musicPack))
{
if (StardewSymphony.Config.EnableDebugLog)
StardewSymphony.ModMonitor.Log($"ERROR: Music Pack '{nameOfNewMusicPack}' isn't valid for some reason.", StardewModdingAPI.LogLevel.Alert);
return;
}
this.CurrentMusicPack?.StopSong();
this.CurrentMusicPack = musicPack;
}
/// <summary>Updates the timer every second to check whether a song is playing.</summary>
public void UpdateTimer()
{
if (this.CurrentMusicPack == null)
return;
if (StardewSymphony.Config.DisableStardewMusic)
{
if (this.CurrentMusicPack.IsPlaying())
return;
}
else if (this.CurrentMusicPack.IsPlaying() || (Game1.currentSong?.IsPlaying == true && !Game1.currentSong.Name.ToLower().Contains("ambient")))
return;
if (!this.Timer.Enabled)
{
this.Timer.Interval = this.Random.Next(StardewSymphony.Config.MinimumDelayBetweenSongsInMilliseconds, StardewSymphony.Config.MaximumDelayBetweenSongsInMilliseconds + 1);
this.Timer.Enabled = true;
}
}
/// <summary>Choose a new song when a delay runs out.</summary>
private void OnTimerFinished(object source, ElapsedEventArgs e)
{
this.Timer.Enabled = false;
if (!this.CurrentMusicPack.IsPlaying())
this.selectMusic(SongSpecificsV2.getCurrentConditionalString());
}
/// <summary>Play a song from the current music pack.</summary>
/// <param name="songName">The song to play.</param>
public void PlaySongFromCurrentPack(string songName)
{
this.CurrentMusicPack?.PlaySong(songName);
}
/// <summary>Stop the current song being played.</summary>
public void stopSongFromCurrentMusicPack()
{
this.CurrentMusicPack?.StopSong();
}
/// <summary>Get all music packs which contain songs that can be played right now.</summary>
public Dictionary<MusicPackV2, List<string>> GetApplicableMusicPacks(string songListKey)
{
Dictionary<MusicPackV2, List<string>> listOfValidDictionaries = new Dictionary<MusicPackV2, List<string>>();
foreach (var v in this.MusicPacks)
{
try
{
var songList = v.Value.SongInformation.getSongList(songListKey);
if (songList.Count > 0)
listOfValidDictionaries.Add(v.Value, songList);
}
catch { }
}
return listOfValidDictionaries;
}
/*
public Dictionary<MusicPackV2, List<string>> GetListOfApplicableMusicPacksForFestivals()
{
Dictionary<MusicPackV2, List<string>> listOfValidDictionaries = new Dictionary<MusicPackV2, List<string>>();
foreach (var v in this.MusicPacks)
{
try
{
var songList = v.Value.SongInformation.getFestivalMusic();
if (songList.Count > 0)
listOfValidDictionaries.Add(v.Value, songList);
}
catch { }
}
return listOfValidDictionaries;
}
public Dictionary<MusicPackV2, List<string>> GetListOfApplicableMusicPacksForEvents()
{
Dictionary<MusicPackV2, List<string>> listOfValidDictionaries = new Dictionary<MusicPackV2, List<string>>();
foreach (var v in this.MusicPacks)
{
try
{
var songList = v.Value.SongInformation.getEventMusic();
if (songList.Count > 0)
listOfValidDictionaries.Add(v.Value, songList);
}
catch { }
}
return listOfValidDictionaries;
}
*/
/// <summary>
/// Get a list of applicable songs to play in the given menu and find one to play.
/// </summary>
/// <param name="songListKey"></param>
public void SelectMenuMusic(string songListKey)
{
// stop timer when new music is selected
this.Timer.Enabled = false;
// get applicable music packs
var listOfValidMusicPacks = this.GetApplicableMusicPacks(songListKey);
if (listOfValidMusicPacks.Count == 0)
return;
// swap to new music pack
var pair = listOfValidMusicPacks.ElementAt(this.Random.Next(0, listOfValidMusicPacks.Count - 1));
this.SwapMusicPacks(pair.Key.Name);
string songName = pair.Value.ElementAt(this.Random.Next(0, pair.Value.Count));
this.CurrentMusicPack.PlaySong(songName);
StardewSymphony.menuChangedMusic = true;
}
/// <summary>Select the actual song to be played right now based on the selector key. The selector key should be called when the player's location changes.</summary>
public void selectMusic(string songListKey, bool warpCheck = false)
{
//Prevent generic song changes when running about.
if (SongSpecificsV2.IsKeyGeneric(songListKey))
{
if (this.CurrentMusicPack != null)
{
if (this.CurrentMusicPack.IsPlaying()) return;
}
}
//If I have warped and the key only is to be played when time changes prevent a new song from playing.
//If the key is more specific (I.E has a location associated with it) then music will change.
if (warpCheck == true && SongSpecificsV2.IsKeyTimeSpecific(songListKey))
{
if (this.CurrentMusicPack != null)
{
if (this.CurrentMusicPack.IsPlaying()) return;
}
}
// stop timer timer when music is selected
this.Timer.Enabled = false;
// get applicable music packs
var listOfValidMusicPacks = this.GetApplicableMusicPacks(songListKey);
//If the list of valid packs are 0, check if I'm currently at an event or festival or get some location specific music and try to play a generalized song from there.
if (listOfValidMusicPacks.Count == 0)
{
//No valid songs to play at this time.
if (StardewSymphony.Config.EnableDebugLog)
StardewSymphony.ModMonitor.Log("Error: There are no songs to play across any music pack for the song key: " + songListKey + ".7 Are you sure you did this properly?");
StardewSymphony.menuChangedMusic = false;
return;
}
SongConditionals conditional = new SongConditionals(songListKey);
if (this.CurrentMusicPack != null)
{
//If I am trying to play a generic song and a generic song is playing don't change the music.
//If I am trying to play a generic song and a non-generic song is playing, then play my generic song since I don't want to play the specific music anymore.
if ((conditional.isLocationSpecific()==false&&conditional.isTimeSpecific()==false) && (this.CurrentMusicPack.IsPlaying() && !this.lastSongWasLocationSpecific))
{
if (StardewSymphony.Config.EnableDebugLog)
StardewSymphony.ModMonitor.Log("Non specific music change detected. Not going to change the music this time");
return;
}
}
this.lastSongWasLocationSpecific = conditional.isLocationSpecific();
//If there is a valid key for the place/time/event/festival I am at, play it!
int randInt = this.Random.Next(0, listOfValidMusicPacks.Count - 1);
var musicPackPair = listOfValidMusicPacks.ElementAt(randInt);
//used to swap the music packs and stop the last playing song.
this.SwapMusicPacks(musicPackPair.Key.Name);
string songName = musicPackPair.Value.ElementAt(this.Random.Next(0, musicPackPair.Value.Count));
this.CurrentMusicPack.PlaySong(songName);
}
public Dictionary<MusicPackV2, List<string>> getLocationSpecificMusic()
{
Dictionary<MusicPackV2, List<string>> listOfValidDictionaries = new Dictionary<MusicPackV2, List<string>>();
//StardewSymphony.ModMonitor.Log(SongSpecificsV2.getCurrentConditionalString(true));
foreach (var v in this.MusicPacks)
{
try
{
var songList = v.Value.SongInformation.getSongList(SongSpecificsV2.getCurrentConditionalString(true));
if (songList == null) return null;
if (songList.Count > 0)
{
listOfValidDictionaries.Add(v.Value, songList);
}
}
catch { }
}
return listOfValidDictionaries;
}
/// <summary>Adds a valid xwb music pack to the list of music packs available.</summary>
/// <param name="musicPack">The music pack to add.</param>
/// <param name="displayLogInformation">Whether or not to display the process to the console. Will include information from the pack's metadata. Default:False</param>
/// <param name="displaySongs">If displayLogInformation is also true this will display the name of all of the songs in the music pack when it is added in.</param>
public void addMusicPack(MusicPackV2 musicPack, bool displayLogInformation = false, bool displaySongs = false)
{
if (displayLogInformation)
{
if (StardewSymphony.Config.EnableDebugLog)
{
StardewSymphony.ModMonitor.Log("Adding music pack:");
StardewSymphony.ModMonitor.Log($" Name: {musicPack.Name}");
StardewSymphony.ModMonitor.Log($" Author: {musicPack.Manifest.Author}");
StardewSymphony.ModMonitor.Log($" Description: {musicPack.Manifest.Description}");
StardewSymphony.ModMonitor.Log($" Version Info: {musicPack.Manifest.Version}");
}
if (displaySongs && StardewSymphony.Config.EnableDebugLog)
{
StardewSymphony.ModMonitor.Log(" Song List:");
foreach (string song in musicPack.SongInformation.songs.Keys)
StardewSymphony.ModMonitor.Log($" {song}");
}
}
this.MusicPacks.Add(musicPack.Name, musicPack);
}
}
}

View File

@ -0,0 +1,226 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;
using NAudio.Vorbis;
using NAudio.Wave;
using StardewModdingAPI;
using StardewValley;
using StardustCore.UIUtilities;
namespace StardewSymphonyRemastered.Framework.V2
{
/// <summary>A content pack which can provide music and sounds.</summary>
public class MusicPackV2
{
/*********
** Fields
*********/
/// <summary>The name of the folder which contains the saved player settings.</summary>
private readonly string DataFolderName = "data";
/// <summary>The name of the folder which contains available music.</summary>
private readonly string MusicFolderName = "songs";
/*********
** Accessors
*********/
/// <summary>The underlying content pack.</summary>
public IContentPack ContentPack { get; }
/// <summary>The songs to play when.</summary>
public SongSpecificsV2 SongInformation { get; }
/// <summary>The music pack icon.</summary>
public Texture2DExtended Icon { get; }
/// <summary>The current song name being played, if any.</summary>
public string CurrentSongName { get; private set; }
/// <summary>The currently sound being played, if any.</summary>
public SoundEffectInstance CurrentSound { get; private set; }
/// <summary>The manifest info.</summary>
public IManifest Manifest => this.ContentPack.Manifest;
/// <summary>The name of the music pack.</summary>
public string Name => this.ContentPack.Manifest.Name;
/// <summary>The available sounds.</summary>
public Dictionary<string, SoundEffectInstance> Sounds { get; } = new Dictionary<string, SoundEffectInstance>();
/*********
** Public methods
*********/
/// <summary>Construct an instance.</summary>
/// <param name="contentPack">The underlying content pack.</param>
public MusicPackV2(IContentPack contentPack)
{
this.ContentPack = contentPack;
this.SongInformation = new SongSpecificsV2();
this.Icon = this.LoadIcon();
this.LoadMusicFiles();
}
/// <summary>Play a song.</summary>
/// <param name="name">The song name to play.</param>
public void PlaySong(string name)
{
// get sound
if (!this.Sounds.TryGetValue(name, out SoundEffectInstance sound))
{
StardewSymphony.ModMonitor.Log("An error occured where we can't find the song anymore. Weird. Please contact Omegasis with a SMAPI Log and describe when/how the event occured.");
return;
}
// play sound
this.CurrentSongName = name;
this.CurrentSound = sound;
this.CurrentSound.Play();
}
/// <summary>Stop the currently playing song.</summary>
public void StopSong()
{
Game1.currentSong?.Stop(AudioStopOptions.Immediate);
this.CurrentSound?.Stop(true);
this.CurrentSongName = null;
}
/// <summary>Get whether the content pack is currently playing a song.</summary>
public bool IsPlaying()
{
return this.CurrentSound?.State == SoundState.Playing;
}
/// <summary>Write the song conditions to disk.</summary>
public virtual void SaveSettings()
{
if (StardewSymphony.Config.EnableDebugLog)
StardewSymphony.ModMonitor.Log($"Saving music for {this.Name}...");
foreach (var list in this.SongInformation.songs)
{
if (StardewSymphony.Config.EnableDebugLog)
StardewSymphony.ModMonitor.Log($" Saving song: {list.Key}...");
this.ContentPack.WriteJsonFile($"{this.DataFolderName}/{list.Value.name}.json", list.Value);
}
}
/// <summary>Read the song conditions from disk.</summary>
public virtual void LoadSettings()
{
DirectoryInfo dataFolder = new DirectoryInfo(Path.Combine(this.ContentPack.DirectoryPath, this.DataFolderName));
if (dataFolder.Exists)
{
if (StardewSymphony.Config.EnableDebugLog)
StardewSymphony.ModMonitor.Log($"Loading music for {this.Name}. This may take quite some time.");
foreach (FileInfo file in dataFolder.GetFiles())
{
SongInformation node = this.ContentPack.ReadJsonFile<SongInformation>($"{this.DataFolderName}/{file.Name}");
try
{
this.SongInformation.songs.Add(file.Name, node);
}
catch { }
}
}
}
/*********
** Private methods
*********/
/// <summary>Load the icon from the content pack.</summary>
private Texture2DExtended LoadIcon()
{
try
{
Texture2D texture = this.ContentPack.LoadAsset<Texture2D>("icon.png");
return new Texture2DExtended(texture);
}
catch (Exception err)
{
if (StardewSymphony.Config.EnableDebugLog)
StardewSymphony.ModMonitor.Log(err.ToString());
return null;
}
}
/// <summary>Load in the music files from the pack's respective Directory/Songs folder. Typically Content/Music/Wav/FolderName/Songs</summary>
private void LoadMusicFiles()
{
DateTime startTime = DateTime.Now;
DirectoryInfo songFolder = new DirectoryInfo(Path.Combine(this.ContentPack.DirectoryPath, this.MusicFolderName));
foreach (FileInfo file in songFolder.GetFiles())
{
// get name
string name = Path.GetFileNameWithoutExtension(file.Name);
if (this.Sounds.ContainsKey(name))
continue;
// load data
SoundEffect effect = null;
using (Stream waveFileStream = File.OpenRead(file.FullName))
{
switch (file.Extension)
{
case ".wav":
effect = SoundEffect.FromStream(waveFileStream);
break;
case ".mp3":
using (Mp3FileReader reader = new Mp3FileReader(waveFileStream))
using (WaveStream pcmStream = WaveFormatConversionStream.CreatePcmStream(reader))
{
string tempPath = Path.Combine(songFolder.FullName, $"{name}.wav");
StardewSymphony.ModMonitor.Log($"Converting: {tempPath}");
WaveFileWriter.CreateWaveFile(tempPath, pcmStream);
using (Stream tempStream = File.OpenRead(tempPath))
effect = SoundEffect.FromStream(tempStream);
File.Delete(tempPath);
}
break;
case ".ogg":
// Credits: https://social.msdn.microsoft.com/Forums/vstudio/en-US/100a97af-2a1c-4b28-b464-d43611b9b5d6/converting-multichannel-ogg-to-stereo-wav-file?forum=csharpgeneral
using (VorbisWaveReader vorbisStream = new VorbisWaveReader(file.FullName))
{
string tempPath = Path.Combine(songFolder.FullName, $"{name}.wav");
StardewSymphony.DebugLog($"Converting: {tempPath}");
WaveFileWriter.CreateWaveFile(tempPath, vorbisStream.ToWaveProvider16());
using (Stream tempStream = File.OpenRead(tempPath))
effect = SoundEffect.FromStream(tempStream);
File.Delete(tempPath);
}
break;
default:
StardewSymphony.ModMonitor.Log($"Unsupported file extension {file.Extension}.", LogLevel.Warn);
break;
}
}
if (effect == null)
continue;
// add sound
SoundEffectInstance instance = effect.CreateInstance();
this.Sounds.Add(name, instance);
//this.SongInformation.listOfSongsWithoutTriggers.Add(name);
this.SongInformation.songs.Add(name, new V2.SongInformation(name));
}
// log loading time
if (StardewSymphony.Config.EnableDebugLog)
StardewSymphony.ModMonitor.Log($"Time to load WAV music pack {this.Name}: {startTime.Subtract(DateTime.Now)}");
}
}
}

View File

@ -0,0 +1,325 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using StardewValley;
namespace StardewSymphonyRemastered.Framework.V2
{
public class SongConditionals
{
string season;
string weather;
string time;
string location;
string dayOfWeek;
string eventKey;
string festival;
string menu;
private readonly string[] seasons;
private readonly string[] weathers;
private readonly string[] daysOfWeek;
private readonly string[] timesOfDay;
public static char seperator = '_';
public SongConditionals()
{
this.seasons = new[]
{
"spring",
"summer",
"fall",
"winter"
};
this.weathers = new[]
{
"sunny",
"rain",
"debris",
"lightning",
"snow",
"festival",
"wedding"
};
this.daysOfWeek = new[]
{
"sunday",
"monday",
"tuesday",
"wednesday",
"thursday",
"friday",
"saturday"
};
this.timesOfDay = new[]
{
"day",
"night",
"12A.M.",
"1A.M.",
"2A.M.",
"3A.M.",
"4A.M.",
"5A.M.",
"6A.M.",
"7A.M.",
"8A.M.",
"9A.M.",
"10A.M.",
"11A.M.",
"12P.M.",
"1P.M.",
"2P.M.",
"3P.M.",
"4P.M.",
"5P.M.",
"6P.M.",
"7P.M.",
"8P.M.",
"9P.M.",
"10P.M.",
"11P.M.",
};
}
public SongConditionals(string key) : this()
{
this.setConditionalsFromKey(key);
}
/// <summary>
/// Parse a given key and figure out when a song can play.
/// </summary>
/// <param name="key"></param>
public void setConditionalsFromKey(string key)
{
string[] splits = key.Split(seperator);
foreach (string split in splits)
{
//Parse key into conditionals.
if (this.seasons.Contains(split))
{
this.season = split;
}
else if (this.weathers.Contains(split))
{
this.weather = split;
}
else if (this.daysOfWeek.Contains(split))
{
this.dayOfWeek = split;
}
else if (this.timesOfDay.Contains(split))
{
this.time = split;
}
else if (SongSpecificsV2.menus.Contains(split))
{
this.menu = split;
}
else if (SongSpecificsV2.locations.Contains(split))
{
this.location = split;
}
else if (SongSpecificsV2.events.Contains(split))
{
this.eventKey = split;
}
else if (SongSpecificsV2.festivals.Contains(split))
{
this.festival = split;
}
}
}
/// <summary>
/// Checks if a song can be played provided a given key.
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public bool canBePlayed(string key)
{
string tempSeason = "";
string tempWeather = "";
string tempTime = "";
string tempLocation = "";
string tempDayOfWeek = "";
string tempMenu = "";
string tempFestival = "";
string tempEvent = "";
string[] splits = key.Split(seperator);
foreach (string split in splits)
{
//Parse key into conditionals.
if (this.seasons.Contains(split))
{
tempSeason = split;
}
else if (this.weathers.Contains(split))
{
tempWeather = split;
}
else if (this.daysOfWeek.Contains(split))
{
tempDayOfWeek = split;
}
else if (this.timesOfDay.Contains(split))
{
tempTime = split;
}
else if (SongSpecificsV2.menus.Contains(split))
{
tempMenu = split;
}
else if (SongSpecificsV2.locations.Contains(split))
{
tempLocation = split;
}
else if (SongSpecificsV2.events.Contains(split))
{
tempEvent = split;
}
else if (SongSpecificsV2.festivals.Contains(split))
{
tempFestival = split;
}
}
if (this.isLocationSpecific())
{
if (!string.IsNullOrEmpty(tempLocation))
{
if (this.dayOfWeek != tempDayOfWeek) return false; //If there is a check but not the right location return false
}
else
{
return false; //If there is no check against this then return false;
}
}
if (this.isTimeSpecific())
{
if (!string.IsNullOrEmpty(tempTime))
{
if (this.time != tempTime) return false; //If the two times don't match return false
}
else
{
return false; //If there is no check against this and this is time specific don't allow it.
}
}
if (this.isDaySpecific())
{
//condition specific check
if (!string.IsNullOrEmpty(tempDayOfWeek))
{
if (this.dayOfWeek != tempDayOfWeek) return false;
}
else
{
return false; //There is no check against this day of the week. Don't allow it.
}
}
//Check for season.
if (this.isSeasonSpecific())
{
if (!string.IsNullOrEmpty(tempSeason))
{
if (this.season != tempSeason) return false;
}
else
{
return false;
}
}
//Check for weather.
if (this.isWeatherSpecific())
{
if (!string.IsNullOrEmpty(tempWeather))
{
if (this.weather != tempWeather) return false;
}
else
{
return false;
}
}
if (!string.IsNullOrEmpty(this.menu))
{
if (!string.IsNullOrEmpty(tempMenu))
{
if (this.menu != tempMenu) return false;
}
}
if (!string.IsNullOrEmpty(this.festival))
{
if (!string.IsNullOrEmpty(tempFestival))
{
if (this.festival != tempFestival) return false;
}
}
if (!string.IsNullOrEmpty(this.eventKey))
{
if (!string.IsNullOrEmpty(tempEvent))
{
if (this.eventKey != tempEvent) return false;
}
}
return true;
}
public bool isLocationSpecific()
{
return !string.IsNullOrEmpty(this.location);
}
public bool isTimeSpecific()
{
return !string.IsNullOrEmpty(this.time);
}
public bool isSeasonSpecific()
{
return !string.IsNullOrEmpty(this.season);
}
public bool isWeatherSpecific()
{
return !string.IsNullOrEmpty(this.weather);
}
public bool isDaySpecific()
{
return !string.IsNullOrEmpty(this.dayOfWeek);
}
public override bool Equals(object obj)
{
if (obj.GetType() != typeof(SongConditionals)) return false;
SongConditionals other = (SongConditionals)obj;
if (this.season != other.season) return false;
if (this.weather != other.weather) return false;
if (this.dayOfWeek != other.dayOfWeek) return false;
if (this.location != other.location) return false;
if (this.time != other.time) return false;
if (this.menu != other.menu) return false;
if (this.eventKey != other.eventKey) return false;
if (this.festival != other.festival) return false;
return true;
}
}
}

View File

@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StardewSymphonyRemastered.Framework.V2
{
public class SongInformation
{
public string name;
public Dictionary<string,SongConditionals> songConditionals;
public SongInformation()
{
this.songConditionals = new Dictionary<string, SongConditionals>();
}
public SongInformation(string name):this()
{
this.name = name;
}
public SongInformation(string name,string key):this()
{
}
public void AddSongConditional(string key)
{
if (this.songConditionals.ContainsKey(key)) return;
else
{
this.songConditionals.Add(key, new SongConditionals(key));
}
}
public void RemoveSongConditional(string key)
{
if (!this.songConditionals.ContainsKey(key)) return;
else
{
this.songConditionals.Remove(key);
}
}
/// <summary>
/// Checks to see if a song can be played given a set of conditionals.
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public bool canBePlayed(string key)
{
foreach(KeyValuePair<string,SongConditionals> pair in this.songConditionals)
{
if (pair.Value.canBePlayed(key) == true) return true;
}
return false;
}
}
}

View File

@ -0,0 +1,501 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using StardewValley;
namespace StardewSymphonyRemastered.Framework.V2
{
public class SongSpecificsV2
{
public SortedDictionary<string, SongInformation> songs; //triggerName, <songs>. Seasonal music
public static List<string> locations = new List<string>();
public static List<string> festivals = new List<string>();
public static List<string> events = new List<string>();
/// <summary>Keeps track of the menus that support custom music with this mod.</summary>
public static List<string> menus = new List<string>();
private readonly string[] seasons;
private readonly string[] weather;
private readonly string[] daysOfWeek;
private readonly string[] timesOfDay;
public static char seperator = '_';
public enum SongKeyType
{
None,
Seasonal,
Weather,
Time,
Location,
DayOfWeek
}
public string[] TimesOfDay
{
get
{
return this.timesOfDay;
}
}
/// <summary>Construct an instance.</summary>
public SongSpecificsV2()
{
this.seasons = new[]
{
"spring",
"summer",
"fall",
"winter"
};
this.weather = new[]
{
"sunny",
"rain",
"debris",
"lightning",
"snow",
"festival",
"wedding"
};
this.daysOfWeek = new[]
{
"sunday",
"monday",
"tuesday",
"wednesday",
"thursday",
"friday",
"saturday"
};
this.timesOfDay = new[]
{
"day",
"night",
"12A.M.",
"1A.M.",
"2A.M.",
"3A.M.",
"4A.M.",
"5A.M.",
"6A.M.",
"7A.M.",
"8A.M.",
"9A.M.",
"10A.M.",
"11A.M.",
"12P.M.",
"1P.M.",
"2P.M.",
"3P.M.",
"4P.M.",
"5P.M.",
"6P.M.",
"7P.M.",
"8P.M.",
"9P.M.",
"10P.M.",
"11P.M.",
};
this.songs = new SortedDictionary<string, SongInformation>();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// Static Methods //
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
#region
/// <summary>Sum up some conditionals to parse the correct string key to access the songs list.</summary>
public static string getCurrentConditionalString(bool getJustLocation = false)
{
string key;
//Event id's are the number found before the : for the event in Content/events/<location>.yaml file where location is the name of the stardew valley location.
if (!getJustLocation)
{
if (Game1.eventUp && !Game1.CurrentEvent.isFestival)
{
//Get the event id an hijack it with some different music
//String key="Event_EventName";
var reflected = StardewSymphony.ModHelper.Reflection.GetField<int>(Game1.CurrentEvent, "id");
int id = reflected.GetValue();
key = id.ToString(); //get the event id. Really really messy.
return key;
}
else if (Game1.isFestival())
{
//hijack the date of the festival and load some different songs
// string s="Festival name"
key = Game1.CurrentEvent.FestivalName;
return key;
}
else if (Game1.activeClickableMenu != null)
{
string name = Game1.activeClickableMenu.GetType().ToString().Replace('.', seperator);
//Iterate through all of the potential menu options and check if it is valid.
foreach (string menuNamespaceName in menus)
{
if (name == menuNamespaceName)
{
key = name;
return key;
}
}
return ""; //No menu found so don't event try to change the music.
}
else
{
key = getCurrentConditionalKey(true, true, true, true, true, true);
int mode = 6;
while (StardewSymphony.musicManager.GetApplicableMusicPacks(key).Count == 0 && mode > 0)
{
mode--;
if (mode == 5)
{
key = getCurrentConditionalKey(true, true, true, true, true, false);
}
if (mode == 4)
{
key = getCurrentConditionalKey(true, true, true, true, false, false);
}
if (mode == 3)
{
key = getCurrentConditionalKey(true, true, true, false, false, false);
}
if (mode == 2)
{
key = getCurrentConditionalKey(true, true, false, false, false, false);
}
if (mode == 1)
{
key = getCurrentConditionalKey(true, false, false, false, false, false);
}
if (mode == 0)
{
key = getCurrentConditionalKey(true, true, true, true, true, true);
}
}
}
}
else
key = getLocationString();
return key;
}
/// <summary>
/// Gets an appropriate key combination from for selecting music
/// </summary>
/// <param name="season"></param>
/// <param name="weather"></param>
/// <param name="time"></param>
/// <param name="hourly"></param>
/// <param name="location"></param>
/// <param name="dayOfWeek"></param>
/// <returns></returns>
public static string getCurrentConditionalKey(bool season = true, bool weather = true, bool time = true, bool hourly = true, bool location = true, bool dayOfWeek = true)
{
string key = "";
if (season == true) key += getSeasonNameString();
if (weather == true) key += seperator + getWeatherString();
if (time == true) key += seperator + getTimeOfDayString(hourly);
if (location == true) key += seperator + getLocationString();
if (dayOfWeek == true) key += seperator + getDayOfWeekString();
return key;
}
/// <summary>Initialize the location lists with the names of all of the major locations in the game.</summary>
public static void initializeLocationsList()
{
//Give stardew symphony access to have unique music at any game location.
foreach (var v in Game1.locations)
{
locations.Add(v.Name);
if (StardewSymphony.Config.EnableDebugLog)
StardewSymphony.ModMonitor.Log("Adding in song triggers for location: " + v.Name);
}
locations.Add("UndergroundMine Floors 1-39");
locations.Add("UndergroundMine Floors 40-69");
locations.Add("UndergroundMine Floors 70-79");
locations.Add("UndergroundMine Floors 80-120");
//Try to get stardew symphony to recognize builds on the farm and try to give those buildings unique soundtracks as well.
try
{
var farm = (Farm)Game1.getLocationFromName("Farm");
foreach (var building in farm.buildings)
{
if (string.IsNullOrEmpty(building.nameOfIndoors) || locations.Contains(building.nameOfIndoors))
continue;
locations.Add(building.nameOfIndoors);
if (StardewSymphony.Config.EnableDebugLog)
StardewSymphony.ModMonitor.Log("Adding in song triggers for location: " + building.nameOfIndoors);
}
}
catch (Exception err)
{
if (StardewSymphony.Config.EnableDebugLog)
StardewSymphony.ModMonitor.Log(err.ToString());
}
}
/// <summary>Initializes a list of the festivals included in vanilla stardew valley to be allowed to have custom music options. Initialized by festival name.</summary>
public static void initializeFestivalsList()
{
addFestival("Egg Festival"); //Egg festival
addFestival("Flower Dance"); //Flower dance
addFestival("Luau"); //luau
addFestival("Dance Of The Moonlight Jellies"); //moonlight jellies
addFestival("Stardew Valley Fair"); //fall fair
addFestival("Spirit's Eve"); //spirits eve
addFestival("Festival of Ice"); //festival of ice
addFestival("Feast of the Winter Star"); //festival of winter star
}
/// <summary>Add a specific new festival to the list. Must be in the format seasonDay. For example, spring13 or fall27.</summary>
public static void addFestival(string name)
{
festivals.Add(name);
}
/// <summary>Custom way to add in event to hijack music.</summary>
public static void addEvent(string id)
{
events.Add(id);
//Do some logic here
}
/// <summary>Add a location to the loctaion list.</summary>
public static void addLocation(string name)
{
locations.Add(name);
}
/// <summary>Get the name of the day of the week from what game day it is.</summary>
public static string getDayOfWeekString()
{
int dayOfWeek = Game1.dayOfMonth % 7;
switch (dayOfWeek)
{
case 0:
return "sunday";
case 1:
return "monday";
case 2:
return "tuesday";
case 3:
return "wednesday";
case 4:
return "thursday";
case 5:
return "friday";
case 6:
return "saturday";
default:
return "";
}
}
/// <summary>Get the name of the current season</summary>
public static string getSeasonNameString()
{
return Game1.currentSeason.ToLower();
}
/// <summary>Get the name for the current weather outside.</summary>
public static string getWeatherString()
{
if (Game1.isRaining && !Game1.isLightning)
return "rain";
if (Game1.isLightning)
return "lightning";
if (Game1.isDebrisWeather)
return "debris"; //????
if (Game1.isSnowing)
return "snow";
if (Game1.weddingToday)
return "wedding";
return "sunny"; //If none of the other weathers, make it sunny.
}
/// <summary>Get the name for the time of day that it currently is.</summary>
public static string getTimeOfDayString(bool hourly)
{
if (!hourly)
{
return Game1.timeOfDay < Game1.getModeratelyDarkTime()
? "day"
: "night";
}
else
{
int hour = Game1.timeOfDay / 100;
string suffix = "";
if (hour < 12 || hour >= 24)
{
suffix = "A.M.";
}
if (hour >= 12 && hour < 24)
{
suffix = "P.M";
}
return hour + suffix;
}
}
/// <summary>Get the name of the location of where I am at.</summary>
public static string getLocationString()
{
try
{
string locName = Game1.currentLocation.Name;
if (locName.StartsWith("UndergroundMine"))
{
StardewSymphony.DebugLog("LOC VALUE:" + locName);
string splits = locName.Replace("UndergroundMine", "");
StardewSymphony.DebugLog("DEBUG VALUE:" + splits);
int number = Convert.ToInt32(splits);
if (number >= 1 && number <= 39)
return "UndergroundMine" + " Floors 1-39";
if (number >= 40 && number <= 69)
return "UndergroundMine" + " Floors 40-69";
if (number >= 70 && number <= 79)
return "UndergroundMine" + " Floors 70-79";
if (number >= 80 && number <= 120)
return "UndergroundMine" + " Floors 80-120";
}
if (locName.Contains("Cabin") || Game1.currentLocation.isFarmBuildingInterior())
locName = Game1.currentLocation.uniqueName.Value;
return locName;
}
catch (Exception err)
{
StardewSymphony.ModMonitor.Log(err.ToString());
return "";
}
}
#endregion
public static bool IsKeyLocationSpecific(string key)
{
SongConditionals condition = new SongConditionals(key);
if (condition.isLocationSpecific()) return true;
return false;
}
/// <summary>
/// Checks if the key used is associated with playing at certain times.
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static bool IsKeyTimeSensitive(string key)
{
SongConditionals condition = new SongConditionals(key);
if (condition.isTimeSpecific()) return true;
return false;
}
/// <summary>
/// Checks if the key is only as specific as having a time set. (i.e not location or day specific)
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static bool IsKeyTimeSpecific(string key)
{
SongConditionals condition = new SongConditionals(key);
if (condition.isTimeSpecific()) return true;
return false;
}
public static bool IsKeyGeneric(string key)
{
SongConditionals condition = new SongConditionals(key);
if (condition.isLocationSpecific() == false && condition.isTimeSpecific() == false && condition.isDaySpecific() == false) return true;
return false;
}
/// <summary>Initialize a basic list of menus supported.</summary>
public static void initializeMenuList()
{
addMenu(typeof(StardewValley.Menus.TitleMenu)); //Of course!
addMenu(typeof(StardewValley.Menus.AboutMenu)); //Sure, though I doubt many people look at this menu.
addMenu(typeof(StardewValley.Menus.Billboard)); //The billboard in town.
addMenu(typeof(StardewValley.Menus.BlueprintsMenu)); // the crafting menu.
//addMenu(typeof(StardewValley.Menus.BobberBar)); //Fishing.
addMenu(typeof(StardewValley.Menus.Bundle)); //Definitely could be fun. Custom bundle menu music.
addMenu(typeof(StardewValley.Menus.CarpenterMenu)); //Building a thing with robbin
addMenu(typeof(StardewValley.Menus.CataloguePage)); //???
addMenu(typeof(StardewValley.Menus.CharacterCustomization)); //Yea!
addMenu(typeof(StardewValley.Menus.CollectionsPage));
addMenu(typeof(StardewValley.Menus.CoopMenu));
addMenu(typeof(StardewValley.Menus.CraftingPage));
addMenu(typeof(StardewValley.Menus.Fish)); //Music when fishing
addMenu(typeof(StardewValley.Menus.GameMenu)); //Err default inventory page?
addMenu(typeof(StardewValley.Menus.GeodeMenu)); //Flint
addMenu(typeof(StardewValley.Menus.LoadGameMenu)); //Loading the game.
addMenu(typeof(StardewValley.Menus.LevelUpMenu)); //Leveling up
addMenu(typeof(StardewValley.Menus.LetterViewerMenu)); //Viewing your mail
addMenu(typeof(StardewValley.Menus.MapPage)); //Looking at the map
addMenu(typeof(StardewValley.Menus.MuseumMenu)); //Arranging things in the museum
addMenu(typeof(StardewValley.Menus.NamingMenu)); //Naming an animal
addMenu(typeof(StardewValley.Menus.PurchaseAnimalsMenu)); //Buying an animal.
addMenu(typeof(StardewValley.Menus.SaveGameMenu)); //Saving the game / end of night
addMenu(typeof(StardewValley.Menus.ShippingMenu)); //Shipping screen.
addMenu(typeof(StardewValley.Menus.ShopMenu)); //Buying things
}
/// <summary>Add amenu to stardew symphony so that it may have unique music.</summary>
/// <param name="menuType">The type of menu to add in. Typically this is typeof(MyMenuClass)</param>
public static void addMenu(Type menuType)
{
try
{
string name = menuType.ToString().Replace('.', seperator); //Sanitize the name passed in to use my parsing conventions.
menus.Add(name); //Add the sanitized menu name to the list of menus that have custom music.
}
catch { }
}
/// <summary>
/// Gets the list of songs for the song.
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public List<string> getSongList(string key)
{
List<string> songs = new List<string>();
foreach(var v in this.songs)
{
if (v.Value.canBePlayed(key)) songs.Add(v.Key);
}
return songs;
}
}
}

View File

@ -3,6 +3,7 @@ using Microsoft.Xna.Framework.Graphics;
using StardewModdingAPI;
using StardewModdingAPI.Events;
using StardewSymphonyRemastered.Framework;
using StardewSymphonyRemastered.Framework.V2;
using StardewValley;
using StardustCore.UIUtilities;
@ -29,7 +30,7 @@ namespace StardewSymphonyRemastered
*********/
public static IModHelper ModHelper;
public static IMonitor ModMonitor;
public static MusicManager musicManager;
public static MusicManagerV2 musicManager;
public static bool menuChangedMusic;
public static Config Config;
public static TextureManager textureManager;
@ -58,7 +59,7 @@ namespace StardewSymphonyRemastered
helper.Events.GameLoop.GameLaunched += this.OnGameLaunched;
musicManager = new MusicManager();
musicManager = new MusicManagerV2();
textureManager = new TextureManager();
this.LoadTextures();
@ -66,15 +67,28 @@ namespace StardewSymphonyRemastered
//Initialize all of the lists upon creation during entry.
SongSpecifics.initializeMenuList();
SongSpecifics.initializeFestivalsList();
SongSpecificsV2.initializeMenuList();
SongSpecificsV2.initializeFestivalsList();
this.LoadMusicPacks();
}
private void GameLoop_TimeChanged(object sender, TimeChangedEventArgs e)
{
musicManager.selectMusic(SongSpecifics.getCurrentConditionalString());
if (Game1.timeOfDay % 100 != 0) return; //Only check on the hour.
if (musicManager.CurrentMusicPack != null)
{
//If there isn't another song already playing. Meaning a new song will play only if a different conditional is hit or this currently playing song finishes.
if (musicManager.CurrentMusicPack.IsPlaying() == false)
{
musicManager.selectMusic(SongSpecificsV2.getCurrentConditionalString());
}
}
else
{
musicManager.selectMusic(SongSpecificsV2.getCurrentConditionalString());
}
}
/// <summary>Raised after a player warps to a new location.</summary>
@ -83,7 +97,7 @@ namespace StardewSymphonyRemastered
private void OnPlayerWarped(object sender, WarpedEventArgs e)
{
if (e.IsLocalPlayer)
musicManager.selectMusic(SongSpecifics.getCurrentConditionalString());
musicManager.selectMusic(SongSpecificsV2.getCurrentConditionalString(), true);
}
/// <summary>Raised after the game is launched, right before the first update tick. This happens once per game session (unrelated to loading saves). All mods are loaded and initialised at this point, so this is a good time to set up mod integrations.</summary>
@ -93,9 +107,7 @@ namespace StardewSymphonyRemastered
{
// Ran once all of the entry methods are ran. This will ensure that all custom music from other mods has been properly loaded in.
musicManager.initializeMenuMusic(); //Initialize menu music that has been added to SongSpecifics.menus from all other mods during their Entry function.
musicManager.initializeFestivalMusic(); //Initialize festival music that has been added to SongSpecifics.menus from all other mods during their Entry function.
musicManager.initializeEventMusic(); //Initialize event music that has been added to SongSpecifics.menus from all other mods during their Entry function.
}
/// <summary>Raised after the player loads a save slot and the world is initialised.</summary>
@ -104,21 +116,17 @@ namespace StardewSymphonyRemastered
private void OnSaveLoaded(object sender, SaveLoadedEventArgs e)
{
//Locaion initialization MUST occur after load. Anything else can occur before.
SongSpecifics.initializeLocationsList(); //Gets all Game locations once the player has loaded the game, and all buildings on the player's farm and adds them to a location list.
musicManager.initializeSeasonalMusic(); //Initialize the seasonal music using all locations gathered in the location list.
musicManager.initializeMenuMusic();
musicManager.initializeFestivalMusic();
musicManager.initializeEventMusic();
SongSpecificsV2.initializeLocationsList(); //Gets all Game locations once the player has loaded the game, and all buildings on the player's farm and adds them to a location list.
foreach (var musicPack in musicManager.MusicPacks)
musicPack.Value.LoadSettings();
SongSpecifics.menus.Sort();
SongSpecifics.locations.Sort();
SongSpecifics.festivals.Sort();
SongSpecifics.events.Sort();
SongSpecificsV2.menus.Sort();
SongSpecificsV2.locations.Sort();
SongSpecificsV2.festivals.Sort();
SongSpecificsV2.events.Sort();
musicManager.selectMusic(SongSpecifics.getCurrentConditionalString());
musicManager.selectMusic(SongSpecificsV2.getCurrentConditionalString());
}
/// <summary>Raised after a game menu is opened, closed, or replaced.</summary>
@ -130,12 +138,15 @@ namespace StardewSymphonyRemastered
if (e.NewMenu == null)
{
if (menuChangedMusic)
musicManager.selectMusic(SongSpecifics.getCurrentConditionalString());
{
musicManager.selectMusic(SongSpecificsV2.getCurrentConditionalString());
menuChangedMusic = false;
}
}
// menu changed
else
musicManager.SelectMenuMusic(SongSpecifics.getCurrentConditionalString());
musicManager.SelectMenuMusic(SongSpecificsV2.getCurrentConditionalString());
}
/// <summary>Raised before the game begins writes data to the save file (except the initial save creation).</summary>
@ -154,7 +165,7 @@ namespace StardewSymphonyRemastered
private void OnButtonPressed(object sender, ButtonPressedEventArgs e)
{
if (e.Button == Config.KeyBinding && Game1.activeClickableMenu == null)
Game1.activeClickableMenu = new Framework.Menus.MusicManagerMenu(Game1.viewport.Width, Game1.viewport.Height);
Game1.activeClickableMenu = new Framework.Menus.MusicManagerMenuV2(Game1.viewport.Width, Game1.viewport.Height);
}
@ -222,6 +233,7 @@ namespace StardewSymphonyRemastered
textureManager.addTexture("FestivalIcon", LoadTexture("FestivalIcon.png"));
//WeatherIcons
textureManager.addTexture("WeatherIcon", LoadTexture("WeatherIcon.png"));
textureManager.addTexture("SunnyIcon", LoadTexture("WeatherIcon_Sunny.png"));
textureManager.addTexture("RainyIcon", LoadTexture("WeatherIcon_Rainy.png"));
textureManager.addTexture("DebrisSpringIcon", LoadTexture("WeatherIcon_DebrisSpring.png"));
@ -284,13 +296,19 @@ namespace StardewSymphonyRemastered
{
foreach (IContentPack contentPack in this.Helper.ContentPacks.GetOwned())
{
MusicPack musicPack = new MusicPack(contentPack);
musicPack.SongInformation.initializeMenuMusic();
MusicPackV2 musicPack = new MusicPackV2(contentPack);
//musicPack.SongInformation.initializeMenuMusic();
musicPack.LoadSettings();
musicManager.addMusicPack(musicPack, true, true);
}
}
/// <summary>
/// Used to print messages to the SMAPI console.
/// </summary>
/// <param name="s"></param>
public static void DebugLog(string s)
{
if (Config.EnableDebugLog)

View File

@ -82,12 +82,13 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Config.cs" />
<Compile Include="Framework\Menus\MusicManagerMenu.cs" />
<Compile Include="Framework\Music\SongListNode.cs" />
<Compile Include="Framework\Menus\MusicManagerMenuV2.cs" />
<Compile Include="Framework\V2\MusicManagerV2.cs" />
<Compile Include="Framework\V2\MusicPackV2.cs" />
<Compile Include="Framework\V2\SongConditionals.cs" />
<Compile Include="Framework\V2\SongInformation.cs" />
<Compile Include="Framework\V2\SongSpecificsV2.cs" />
<Compile Include="StardewSymphony.cs" />
<Compile Include="Framework\Music\MusicManager.cs" />
<Compile Include="Framework\Music\SongSpecifics.cs" />
<Compile Include="Framework\Music\MusicPack.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
@ -241,6 +242,9 @@
<Content Include="assets\TimeIcon_Night.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="assets\WeatherIcon.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="assets\WeatherIcon_DebrisFall.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
@ -289,6 +293,9 @@
<Private>False</Private>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="Framework\Music\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(SolutionDir)\deploy.targets" />
</Project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

View File

@ -1,7 +1,7 @@
{
"Name": "Stardew Symphony Remastered",
"Author": "Alpha_Omegasis",
"Version": "2.5.0",
"Version": "2.5.2",
"Description": "Adding more music to the game one beep at a time. Now with streaming!",
"UniqueID": "Omegasis.StardewSymphonyRemastered",
"EntryDll": "StardewSymphonyRemastered.dll",

View File

@ -9,9 +9,25 @@ namespace StardustCore.UIUtilities
{
public class IClickableMenuExtended : StardewValley.Menus.IClickableMenu
{
/// <summary>
/// All stings to be displayed on this menu.
/// </summary>
public List<SpriteFonts.Components.TexturedString> texturedStrings;
/// <summary>
/// All buttons belonging to this menu.
/// </summary>
public List<MenuComponents.Button> buttons;
/// <summary>
/// The background color of this menu.
/// </summary>
public Color dialogueBoxBackgroundColor;
public Texture2D menuBackgroundTexture;
/// <summary>
/// The textures used for this menu.
/// </summary>
public List<Texture2DExtended> menuTextures;
public bool showRightCloseButton;
@ -24,7 +40,10 @@ namespace StardustCore.UIUtilities
this.showRightCloseButton = showCloseButton;
}
/// <summary>
/// Get a clone of this menu.
/// </summary>
/// <returns></returns>
public virtual IClickableMenuExtended clone()
{
return new IClickableMenuExtended(this.xPositionOnScreen, this.yPositionOnScreen, this.width, this.height, this.showRightCloseButton);
@ -458,5 +477,40 @@ namespace StardustCore.UIUtilities
}
public override void update(GameTime time) { }
/// <summary>
/// Gets a relative position for teh component on the menu.
/// </summary>
/// <param name="relativeOffset">A vector representing a relative offset. (.1,.1) means the new position should be set 10% away from the left and 10% away from the top in respect to teh edges of the menu.</param>
/// <returns></returns>
public Vector2 getRelativePositionToMenu(Vector2 relativeOffset)
{
return new Vector2(this.xPositionOnScreen + ( relativeOffset.X * this.width), this.yPositionOnScreen + (relativeOffset.Y * this.height));
}
public Vector2 getRelativePositionToMenu(float relx, float rely)
{
return new Vector2(this.xPositionOnScreen + (relx * this.width), this.yPositionOnScreen + (rely * this.height));
}
/// <summary>
/// Gets an absolute position away from the edge of the menu.
/// </summary>
/// <param name="relativeOffset"></param>
/// <returns></returns>
public Vector2 getFixedPositionFromMenu(Vector2 relativeOffset)
{
return new Vector2(this.xPositionOnScreen + relativeOffset.X, this.yPositionOnScreen + relativeOffset.Y);
}
/// <summary>
/// Gets an absolute position away from the edge of the menu.
/// </summary>
/// <param name="relx"></param>
/// <param name="rely"></param>
/// <returns></returns>
public Vector2 getFixedPositionFromMenu(float relx, float rely)
{
return new Vector2(this.xPositionOnScreen + relx, this.yPositionOnScreen + rely);
}
}
}

BIN
GeneralMods/UpgradeLog.htm Normal file

Binary file not shown.

BIN
GeneralMods/UpgradeLog2.htm Normal file

Binary file not shown.

BIN
GeneralMods/UpgradeLog3.htm Normal file

Binary file not shown.

View File

@ -137,6 +137,7 @@ namespace Vocalization.Framework
this.dialogueFileNames.Add("MarriageDialogue" + this.name + ".xnb");
this.dataFileNames.Add("EngagementDialogue.xnb");
this.dataFileNames.Add("NPCGiftTastes.xnb");
this.stringsFileNames.Add("StringsFromCSFiles.xnb");
this.stringsFileNames.Add(this.name + ".xnb");

View File

@ -9,6 +9,11 @@ namespace Vocalization.Framework
Japanese,
Russian,
German,
Portuguese
Portuguese,
Italian,
French,
Korean,
Turkish,
Hungarian
}
}

View File

@ -36,6 +36,13 @@ namespace Vocalization.Framework
this.TranslationFileExtensions.Add(LanguageName.Russian, ".ru-RU.xnb");
this.TranslationFileExtensions.Add(LanguageName.German, ".de-DE.xnb");
this.TranslationFileExtensions.Add(LanguageName.Portuguese, ".pt-BR.xnb");
//1.3 languages.
this.TranslationFileExtensions.Add(LanguageName.Italian,".it-IT.xnb");
this.TranslationFileExtensions.Add(LanguageName.French, ".fr-FR.xnb");
this.TranslationFileExtensions.Add(LanguageName.Hungarian, ".hu-HU.xnb");
this.TranslationFileExtensions.Add(LanguageName.Turkish, ".tr-TR.xnb");
this.TranslationFileExtensions.Add(LanguageName.Korean, ".ko-KR.xnb");
this.TranslationCodes.Add(LanguageName.English, LocalizedContentManager.LanguageCode.en);
this.TranslationCodes.Add(LanguageName.Spanish, LocalizedContentManager.LanguageCode.es);
@ -44,6 +51,12 @@ namespace Vocalization.Framework
this.TranslationCodes.Add(LanguageName.Russian, LocalizedContentManager.LanguageCode.ru);
this.TranslationCodes.Add(LanguageName.German, LocalizedContentManager.LanguageCode.de);
this.TranslationCodes.Add(LanguageName.Portuguese, LocalizedContentManager.LanguageCode.pt);
//1.3 languages
this.TranslationCodes.Add(LanguageName.Italian, LocalizedContentManager.LanguageCode.it);
this.TranslationCodes.Add(LanguageName.French, LocalizedContentManager.LanguageCode.fr);
this.TranslationCodes.Add(LanguageName.Hungarian, LocalizedContentManager.LanguageCode.hu);
this.TranslationCodes.Add(LanguageName.Turkish, LocalizedContentManager.LanguageCode.tr);
this.TranslationCodes.Add(LanguageName.Korean, LocalizedContentManager.LanguageCode.ko);
}
/// <summary>Get the language name from a string.</summary>

View File

@ -84,6 +84,9 @@ namespace Vocalization
/// <summary>
/// TODO:
///
/// Update menu to work with new 1.3 languages...
///
///
/// Validate that all paths are loading from proper places.
///
@ -2352,7 +2355,70 @@ namespace Vocalization
}
continue;
}
if (fileName.Contains("NPCGiftTastes"))
{
ModMonitor.Log(" Scraping dialogue file: " + fileName, LogLevel.Info);
if (!File.Exists(Path.Combine(root, dialoguePath2)))
{
ModMonitor.Log("Dialogue file not found for:" + fileName + ". This might not necessarily be a mistake just a safety check.");
continue; //If the file is not found for some reason...
}
if (!dialogueDict.ContainsKey(cue.name)) continue;
string rawDialogue = dialogueDict[cue.name];
string[] strippedRawQuestDialogue = new string[20];
List<string> strippedFreshQuestDialogue = new List<string>();
strippedRawQuestDialogue = rawDialogue.Split(new string[] { "/" }, StringSplitOptions.None);
string prompt1 = strippedRawQuestDialogue.ElementAt(0);
string prompt2 = strippedRawQuestDialogue.ElementAt(2);
string prompt3 = strippedRawQuestDialogue.ElementAt(4);
string prompt4 = strippedRawQuestDialogue.ElementAt(6);
string prompt5 = strippedRawQuestDialogue.ElementAt(8);
strippedFreshQuestDialogue.Add(prompt1);
strippedFreshQuestDialogue.Add(prompt2);
strippedFreshQuestDialogue.Add(prompt3);
strippedFreshQuestDialogue.Add(prompt4);
strippedFreshQuestDialogue.Add(prompt5);
List<string> cleanDialogues = new List<string>();
int count = 0;
foreach (string dia in strippedFreshQuestDialogue)
{
string key = "";
if (count == 0) key = "Love";
if (count == 0) key = "Like";
if (count == 0) key = "Dislike";
if (count == 0) key = "Hate";
if (count == 0) key = "Neutral";
count++;
cleanDialogues = sanitizeDialogueFromDictionaries(dia, cue);
foreach (string str in cleanDialogues)
{
ModMonitor.Log("POST SANITIZARION: "+str);
if (AudioCues.getWavFileReferences(language).ContainsKey(AudioCues.generateKey(language, cue.name, fileName, key)))
{
AudioCues.getWavFileReferences(language).TryGetValue(AudioCues.generateKey(language, cue.name, fileName, key), out VoiceAudioOptions value);
cue.addDialogue(str, new VoiceAudioOptions(value.simple, value.full, value.heartEvents, value.simpleAndHeartEvents));
}
else
{
cue.addDialogue(str, new VoiceAudioOptions());
AudioCues.addWavReference(AudioCues.generateKey(language, cue.name, fileName, key), new VoiceAudioOptions());
}
}
}
continue;
}
}
foreach (string fileName in cue.stringsFileNames)
{
ModMonitor.Log(" Scraping dialogue file: " + fileName, LogLevel.Info);
@ -3151,7 +3217,7 @@ namespace Vocalization
{
dialogue = dialogue.Replace(combine, "");
dialogue = dialogue.Replace(" ", " "); //Remove awkward spacing.
//remove dialogue symbol.
//remove dialogue symbol.
}
}