2016-10-20 15:01:51 +08:00
using System ;
using System.Collections.Generic ;
2017-07-28 08:28:39 +08:00
using System.IO ;
2016-10-20 15:01:51 +08:00
using System.Linq ;
2018-09-19 09:04:38 +08:00
using Microsoft.Xna.Framework ;
using Microsoft.Xna.Framework.Graphics ;
using Newtonsoft.Json ;
2017-07-31 11:07:07 +08:00
using Omegasis.HappyBirthday.Framework ;
2016-10-20 15:01:51 +08:00
using StardewModdingAPI ;
2017-07-30 06:02:49 +08:00
using StardewModdingAPI.Events ;
2016-10-20 15:01:51 +08:00
using StardewValley ;
2017-07-30 06:02:49 +08:00
using StardewValley.Characters ;
2018-09-19 09:04:38 +08:00
using StardewValley.Menus ;
2017-07-30 06:02:49 +08:00
using StardewValley.Monsters ;
using SObject = StardewValley . Object ;
2016-10-20 15:01:51 +08:00
2017-07-28 08:28:39 +08:00
namespace Omegasis.HappyBirthday
2016-10-20 15:01:51 +08:00
{
2017-07-30 06:02:49 +08:00
/// <summary>The mod entry point.</summary>
2018-09-19 09:04:38 +08:00
public class HappyBirthday : Mod , IAssetEditor
2016-10-20 15:01:51 +08:00
{
2017-07-30 06:02:49 +08:00
/ * * * * * * * * *
* * Properties
* * * * * * * * * /
2017-08-06 03:51:44 +08:00
/// <summary>The relative path for the current player's data file.</summary>
2018-05-10 05:23:42 +08:00
private string DataFilePath ;
2017-08-06 03:51:44 +08:00
/// <summary>The absolute path for the current player's legacy data file.</summary>
2018-05-01 09:21:31 +08:00
private string LegacyDataFilePath = > Path . Combine ( this . Helper . DirectoryPath , "Player_Birthdays" , $"HappyBirthday_{Game1.player.Name}.txt" ) ;
2017-08-06 03:51:44 +08:00
/// <summary>The mod configuration.</summary>
2018-09-19 09:04:38 +08:00
public static ModConfig Config ;
2017-08-06 03:51:44 +08:00
/// <summary>The data for the current player.</summary>
2018-12-10 11:57:12 +08:00
public static PlayerData PlayerBirthdayData ;
/// <summary>
/// Wrapper for static field PlayerBirthdayData;
/// </summary>
public PlayerData PlayerData
{
get
{
return PlayerBirthdayData ;
}
set
{
PlayerBirthdayData = value ;
}
}
2016-10-20 15:01:51 +08:00
2017-07-30 06:02:49 +08:00
/// <summary>Whether the player has chosen a birthday.</summary>
2017-08-06 03:51:44 +08:00
private bool HasChosenBirthday = > ! string . IsNullOrEmpty ( this . PlayerData . BirthdaySeason ) & & this . PlayerData . BirthdayDay ! = 0 ;
2016-11-08 17:19:56 +08:00
2017-07-30 06:02:49 +08:00
/// <summary>The queue of villagers who haven't given a gift yet.</summary>
private List < string > VillagerQueue ;
2016-10-20 15:01:51 +08:00
2017-07-30 06:02:49 +08:00
/// <summary>Whether we've already checked for and (if applicable) set up the player's birthday today.</summary>
private bool CheckedForBirthday ;
//private Dictionary<string, Dialogue> Dialogue;
//private bool SeenEvent;
2018-03-04 11:24:36 +08:00
public bool CanEdit < T > ( IAssetInfo asset )
{
return asset . AssetNameEquals ( @"Data\mail" ) ;
}
public void Edit < T > ( IAssetData asset )
{
asset
. AsDictionary < string , string > ( )
. Set ( "birthdayMom" , "Dear @,^ Happy birthday sweetheart. It's been amazing watching you grow into the kind, hard working person that I've always dreamed that you would become. I hope you continue to make many more fond memories with the ones you love. ^ Love, Mom ^ P.S. Here's a little something that I made for you. %item object 221 1 %%" ) ;
asset
. AsDictionary < string , string > ( )
. Set ( "birthdayDad" , "Dear @,^ Happy birthday kiddo. It's been a little quiet around here on your birthday since you aren't around, but your mother and I know that you are making both your grandpa and us proud. We both know that living on your own can be tough but we believe in you one hundred percent, just keep following your dreams.^ Love, Dad ^ P.S. Here's some spending money to help you out on the farm. Good luck! %item money 5000 5001 %%" ) ;
}
2017-07-30 06:02:49 +08:00
2018-09-19 09:04:38 +08:00
public static IModHelper ModHelper ;
2018-12-06 10:06:11 +08:00
public static IMonitor ModMonitor ;
/// <summary>
/// Class to handle all birthday messages for this mod.
/// </summary>
2018-09-19 13:35:36 +08:00
public BirthdayMessages messages ;
2018-09-19 09:04:38 +08:00
2018-12-06 10:06:11 +08:00
/// <summary>
/// Class to handle all birthday gifts for this mod.
/// </summary>
2018-12-06 09:16:28 +08:00
public GiftManager giftManager ;
2017-07-30 06:02:49 +08:00
2018-12-07 07:06:26 +08:00
/// <summary>
/// Checks if the current billboard is the daily quest screen or not.
/// </summary>
bool isDailyQuestBoard ;
2018-12-10 11:57:12 +08:00
2018-12-10 13:04:41 +08:00
Dictionary < long , PlayerData > othersBirthdays ;
2018-12-10 11:57:12 +08:00
2017-07-30 06:02:49 +08:00
/ * * * * * * * * *
* * Public methods
* * * * * * * * * /
/// <summary>The mod entry point, called after the mod is first loaded.</summary>
/// <param name="helper">Provides simplified APIs for writing mods.</param>
2016-12-09 08:34:28 +08:00
public override void Entry ( IModHelper helper )
2016-10-20 15:01:51 +08:00
{
2018-09-19 16:37:51 +08:00
//helper.Content.AssetLoaders.Add(new PossibleGifts());
2018-09-19 13:35:36 +08:00
Config = helper . ReadConfig < ModConfig > ( ) ;
2017-08-06 03:51:44 +08:00
2017-08-06 03:20:46 +08:00
TimeEvents . AfterDayStarted + = this . TimeEvents_AfterDayStarted ;
2017-07-30 06:02:49 +08:00
GameEvents . UpdateTick + = this . GameEvents_UpdateTick ;
SaveEvents . AfterLoad + = this . SaveEvents_AfterLoad ;
2017-08-06 03:51:44 +08:00
SaveEvents . BeforeSave + = this . SaveEvents_BeforeSave ;
2017-07-30 06:02:49 +08:00
ControlEvents . KeyPressed + = this . ControlEvents_KeyPressed ;
2018-09-19 09:04:38 +08:00
MenuEvents . MenuChanged + = MenuEvents_MenuChanged ;
2018-12-07 07:06:26 +08:00
MenuEvents . MenuClosed + = MenuEvents_MenuClosed ;
2018-05-10 05:23:42 +08:00
2018-12-10 11:57:12 +08:00
2018-09-19 09:04:38 +08:00
GraphicsEvents . OnPostRenderGuiEvent + = GraphicsEvents_OnPostRenderGuiEvent ;
2018-12-10 13:04:41 +08:00
StardewModdingAPI . Events . GraphicsEvents . OnPostRenderHudEvent + = GraphicsEvents_OnPostRenderHudEvent ;
2018-05-19 05:24:59 +08:00
//MultiplayerSupport.initializeMultiplayerSupport();
2018-09-19 09:04:38 +08:00
ModHelper = Helper ;
2018-12-06 10:06:11 +08:00
ModMonitor = Monitor ;
2018-09-19 13:35:36 +08:00
messages = new BirthdayMessages ( ) ;
2018-12-06 09:16:28 +08:00
giftManager = new GiftManager ( ) ;
2018-12-07 07:06:26 +08:00
isDailyQuestBoard = false ;
2018-12-10 11:57:12 +08:00
ModHelper . Events . Multiplayer . ModMessageReceived + = Multiplayer_ModMessageReceived ;
2018-12-10 13:04:41 +08:00
ModHelper . Events . Multiplayer . PeerDisconnected + = Multiplayer_PeerDisconnected ;
this . othersBirthdays = new Dictionary < long , PlayerData > ( ) ;
2018-12-10 11:57:12 +08:00
}
2018-12-10 13:04:41 +08:00
/// <summary>
/// Used to check for player disconnections.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Multiplayer_PeerDisconnected ( object sender , PeerDisconnectedEventArgs e )
{
this . othersBirthdays . Remove ( e . Peer . PlayerID ) ;
}
2018-12-10 11:57:12 +08:00
private void Multiplayer_ModMessageReceived ( object sender , ModMessageReceivedEventArgs e )
{
if ( e . FromModID = = ModHelper . Multiplayer . ModID & & e . Type = = MultiplayerSupport . FSTRING_SendBirthdayMessageToOthers )
{
string message = e . ReadAs < string > ( ) ;
Game1 . hudMessages . Add ( new HUDMessage ( message , 1 ) ) ;
}
2018-12-10 13:04:41 +08:00
if ( e . FromModID = = ModHelper . Multiplayer . ModID & & e . Type = = MultiplayerSupport . FSTRING_SendBirthdayInfoToOthers )
2018-12-10 11:57:12 +08:00
{
2018-12-10 13:04:41 +08:00
KeyValuePair < long , PlayerData > message = e . ReadAs < KeyValuePair < long , PlayerData > > ( ) ;
if ( ! this . othersBirthdays . ContainsKey ( message . Key ) )
{
this . othersBirthdays . Add ( message . Key , message . Value ) ;
MultiplayerSupport . SendBirthdayInfoToConnectingPlayer ( e . FromPlayerID ) ;
Monitor . Log ( "Got other player's birthday data from: " + Game1 . getFarmer ( e . FromPlayerID ) . name ) ;
}
else
{
//Brute force update birthday info if it has already been recevived but dont send birthday info again.
this . othersBirthdays . Remove ( message . Key ) ;
this . othersBirthdays . Add ( message . Key , message . Value ) ;
Monitor . Log ( "Got other player's birthday data from: " + Game1 . getFarmer ( e . FromPlayerID ) . name ) ;
}
2018-12-10 11:57:12 +08:00
}
2018-09-19 09:04:38 +08:00
}
2018-12-07 08:13:41 +08:00
/// <summary>
/// Used to check when a menu is closed.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
2018-12-07 07:06:26 +08:00
private void MenuEvents_MenuClosed ( object sender , EventArgsClickableMenuClosed e )
{
this . isDailyQuestBoard = false ;
}
2018-09-19 09:04:38 +08:00
/// <summary>
/// Used to properly display hovertext for all events happening on a calendar day.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void GraphicsEvents_OnPostRenderHudEvent ( object sender , EventArgs e )
{
if ( Game1 . activeClickableMenu = = null ) return ;
2018-12-06 16:41:28 +08:00
if ( PlayerData = = null ) return ;
if ( PlayerData . BirthdaySeason = = null ) return ;
2018-09-19 09:04:38 +08:00
if ( PlayerData . BirthdaySeason . ToLower ( ) ! = Game1 . currentSeason . ToLower ( ) ) return ;
if ( Game1 . activeClickableMenu is Billboard )
{
2018-12-07 07:06:26 +08:00
if ( isDailyQuestBoard ) return ;
if ( ( Game1 . activeClickableMenu as Billboard ) . calendarDays = = null ) return ;
2018-09-19 09:04:38 +08:00
//Game1.player.FarmerRenderer.drawMiniPortrat(Game1.spriteBatch, new Vector2(Game1.activeClickableMenu.xPositionOnScreen + 152 + (index - 1) % 7 * 32 * 4, Game1.activeClickableMenu.yPositionOnScreen + 230 + (index - 1) / 7 * 32 * 4), 1f, 4f, 2, Game1.player);
string hoverText = "" ;
2018-12-06 16:54:12 +08:00
List < string > texts = new List < string > ( ) ;
2018-12-07 07:06:26 +08:00
2018-09-19 09:04:38 +08:00
foreach ( var clicky in ( Game1 . activeClickableMenu as Billboard ) . calendarDays )
{
if ( clicky . containsPoint ( Game1 . getMouseX ( ) , Game1 . getMouseY ( ) ) )
{
2018-12-06 16:54:12 +08:00
if ( ! String . IsNullOrEmpty ( clicky . hoverText ) )
{
texts . Add ( clicky . hoverText ) ; //catches npc birhday names.
}
else if ( ! String . IsNullOrEmpty ( clicky . name ) )
{
texts . Add ( clicky . name ) ; //catches festival dates.
}
2018-09-19 09:04:38 +08:00
}
2018-12-06 16:54:12 +08:00
}
for ( int i = 0 ; i < texts . Count ; i + + )
{
hoverText + = texts [ i ] ; //Append text.
if ( i = = texts . Count - 1 ) continue ;
2018-12-06 16:41:28 +08:00
else
{
2018-12-06 16:54:12 +08:00
hoverText + = Environment . NewLine ; //Append new line.
2018-12-06 16:41:28 +08:00
}
2018-09-19 09:04:38 +08:00
}
2018-12-06 16:54:12 +08:00
2018-09-19 09:04:38 +08:00
if ( ! String . IsNullOrEmpty ( hoverText ) )
{
var oldText = Helper . Reflection . GetField < string > ( Game1 . activeClickableMenu , "hoverText" , true ) ;
oldText . SetValue ( hoverText ) ;
}
}
}
/// <summary>
/// Used to show the farmer's portrait on the billboard menu.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void GraphicsEvents_OnPostRenderGuiEvent ( object sender , EventArgs e )
{
if ( Game1 . activeClickableMenu = = null ) return ;
2018-12-06 10:06:11 +08:00
//Don't do anything if birthday has not been chosen yet.
if ( PlayerData = = null ) return ;
2018-12-10 13:04:41 +08:00
2018-12-06 10:06:11 +08:00
2018-09-19 09:04:38 +08:00
if ( Game1 . activeClickableMenu is Billboard )
{
2018-12-07 07:06:26 +08:00
if ( isDailyQuestBoard ) return ;
2018-12-10 13:04:41 +08:00
if ( ! String . IsNullOrEmpty ( PlayerData . BirthdaySeason ) )
{
if ( PlayerData . BirthdaySeason . ToLower ( ) = = Game1 . currentSeason . ToLower ( ) )
{
int index = PlayerData . BirthdayDay ;
Game1 . player . FarmerRenderer . drawMiniPortrat ( Game1 . spriteBatch , new Vector2 ( Game1 . activeClickableMenu . xPositionOnScreen + 152 + ( index - 1 ) % 7 * 32 * 4 , Game1 . activeClickableMenu . yPositionOnScreen + 230 + ( index - 1 ) / 7 * 32 * 4 ) , 0.5f , 4f , 2 , Game1 . player ) ;
}
}
foreach ( var pair in this . othersBirthdays )
{
int index = pair . Value . BirthdayDay ;
if ( pair . Value . BirthdaySeason ! = Game1 . currentSeason . ToLower ( ) ) continue ; //Hide out of season birthdays.
index = pair . Value . BirthdayDay ;
Game1 . player . FarmerRenderer . drawMiniPortrat ( Game1 . spriteBatch , new Vector2 ( Game1 . activeClickableMenu . xPositionOnScreen + 152 + ( index - 1 ) % 7 * 32 * 4 , Game1 . activeClickableMenu . yPositionOnScreen + 230 + ( index - 1 ) / 7 * 32 * 4 ) , 0.5f , 4f , 2 , Game1 . getFarmer ( pair . Key ) ) ;
}
2018-09-19 09:04:38 +08:00
}
}
/// <summary>
/// Functionality to display the player's birthday on the billboard.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void MenuEvents_MenuChanged ( object sender , EventArgsClickableMenuChanged e )
{
2018-12-07 07:06:26 +08:00
if ( Game1 . activeClickableMenu = = null )
{
isDailyQuestBoard = false ;
return ;
}
2018-09-19 09:04:38 +08:00
if ( Game1 . activeClickableMenu is Billboard )
{
2018-12-07 07:06:26 +08:00
isDailyQuestBoard = ModHelper . Reflection . GetField < bool > ( ( Game1 . activeClickableMenu as Billboard ) , "dailyQuestBoard" , true ) . GetValue ( ) ;
if ( isDailyQuestBoard ) return ;
2018-12-10 13:04:41 +08:00
2018-12-07 07:06:26 +08:00
2018-09-19 09:04:38 +08:00
Texture2D text = new Texture2D ( Game1 . graphics . GraphicsDevice , 1 , 1 ) ;
Color [ ] col = new Color [ 1 ] ;
col [ 0 ] = new Color ( 0 , 0 , 0 , 1 ) ;
text . SetData < Color > ( col ) ;
//players birthdy position rect=new ....
2018-12-10 13:04:41 +08:00
if ( ! String . IsNullOrEmpty ( PlayerData . BirthdaySeason ) )
{
if ( PlayerData . BirthdaySeason . ToLower ( ) = = Game1 . currentSeason . ToLower ( ) )
{
int index = PlayerData . BirthdayDay ;
Rectangle birthdayRect = new Rectangle ( Game1 . activeClickableMenu . xPositionOnScreen + 152 + ( index - 1 ) % 7 * 32 * 4 , Game1 . activeClickableMenu . yPositionOnScreen + 200 + ( index - 1 ) / 7 * 32 * 4 , 124 , 124 ) ;
( Game1 . activeClickableMenu as Billboard ) . calendarDays . Add ( new ClickableTextureComponent ( "" , birthdayRect , "" , Game1 . player . name + "'s Birthday" , text , new Rectangle ( 0 , 0 , 124 , 124 ) , 1f , false ) ) ;
}
}
foreach ( var pair in this . othersBirthdays )
{
if ( pair . Value . BirthdaySeason ! = Game1 . currentSeason . ToLower ( ) ) continue ;
int index = pair . Value . BirthdayDay ;
Rectangle otherBirthdayRect = new Rectangle ( Game1 . activeClickableMenu . xPositionOnScreen + 152 + ( index - 1 ) % 7 * 32 * 4 , Game1 . activeClickableMenu . yPositionOnScreen + 200 + ( index - 1 ) / 7 * 32 * 4 , 124 , 124 ) ;
( Game1 . activeClickableMenu as Billboard ) . calendarDays . Add ( new ClickableTextureComponent ( "" , otherBirthdayRect , "" , Game1 . getFarmer ( pair . Key ) . name + "'s Birthday" , text , new Rectangle ( 0 , 0 , 124 , 124 ) , 1f , false ) ) ;
}
2018-09-19 09:04:38 +08:00
}
2017-02-22 15:29:00 +08:00
}
2017-07-30 06:02:49 +08:00
/ * * * * * * * * *
* * Private methods
* * * * * * * * * /
2017-08-06 03:20:46 +08:00
/// <summary>The method invoked after a new day starts.</summary>
2017-07-30 06:02:49 +08:00
/// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param>
2017-08-06 03:20:46 +08:00
private void TimeEvents_AfterDayStarted ( object sender , EventArgs e )
2016-10-20 15:01:51 +08:00
{
2017-07-30 06:02:49 +08:00
this . CheckedForBirthday = false ;
2016-10-20 15:01:51 +08:00
}
2017-07-30 06:02:49 +08:00
/// <summary>The method invoked when the presses a keyboard button.</summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param>
private void ControlEvents_KeyPressed ( object sender , EventArgsKeyPressed e )
2016-10-20 15:01:51 +08:00
{
2017-07-30 06:02:49 +08:00
// show birthday selection menu
2018-06-26 12:13:40 +08:00
if ( Game1 . activeClickableMenu ! = null ) return ;
2018-09-19 13:35:36 +08:00
if ( Context . IsPlayerFree & & ! this . HasChosenBirthday & & e . KeyPressed . ToString ( ) = = Config . KeyBinding )
2017-08-06 03:51:44 +08:00
Game1 . activeClickableMenu = new BirthdayMenu ( this . PlayerData . BirthdaySeason , this . PlayerData . BirthdayDay , this . SetBirthday ) ;
2016-10-20 15:01:51 +08:00
}
2017-07-30 06:02:49 +08:00
/// <summary>The method invoked after the player loads a save.</summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param>
private void SaveEvents_AfterLoad ( object sender , EventArgs e )
2016-10-20 15:01:51 +08:00
{
2018-05-10 05:23:42 +08:00
this . DataFilePath = Path . Combine ( "data" , Game1 . player . Name + "_" + Game1 . player . UniqueMultiplayerID + ".json" ) ;
2017-08-06 11:00:37 +08:00
// reset state
this . VillagerQueue = new List < string > ( ) ;
this . CheckedForBirthday = false ;
// load settings
2017-08-06 03:51:44 +08:00
this . MigrateLegacyData ( ) ;
2018-12-06 09:16:28 +08:00
this . PlayerData = this . Helper . Data . ReadJsonFile < PlayerData > ( this . DataFilePath ) ? ? new PlayerData ( ) ;
2018-09-19 09:04:38 +08:00
2018-09-19 13:35:36 +08:00
messages . createBirthdayGreetings ( ) ;
2018-12-10 13:04:41 +08:00
if ( PlayerBirthdayData ! = null )
{
MultiplayerSupport . SendBirthdayInfoToOtherPlayers ( ) ;
}
2017-07-30 06:02:49 +08:00
//this.SeenEvent = false;
//this.Dialogue = new Dictionary<string, Dialogue>();
2016-10-20 15:01:51 +08:00
}
2017-08-06 03:51:44 +08:00
/// <summary>The method invoked just before the game updates the saves.</summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param>
private void SaveEvents_BeforeSave ( object sender , EventArgs e )
{
if ( this . HasChosenBirthday )
2018-12-06 09:16:28 +08:00
this . Helper . Data . WriteJsonFile ( this . DataFilePath , this . PlayerData ) ;
2017-08-06 03:51:44 +08:00
}
2017-07-30 06:02:49 +08:00
/// <summary>The method invoked when the game updates (roughly 60 times per second).</summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param>
private void GameEvents_UpdateTick ( object sender , EventArgs e )
2016-10-20 15:01:51 +08:00
{
2017-08-06 03:23:10 +08:00
if ( ! Context . IsWorldReady | | Game1 . eventUp | | Game1 . isFestival ( ) )
2017-07-30 06:02:49 +08:00
return ;
2018-08-07 05:01:44 +08:00
if ( ! this . HasChosenBirthday & & Game1 . activeClickableMenu = = null & & Game1 . player . Name . ToLower ( ) ! = "unnamed farmhand" )
2018-08-06 00:33:00 +08:00
{
Game1 . activeClickableMenu = new BirthdayMenu ( this . PlayerData . BirthdaySeason , this . PlayerData . BirthdayDay , this . SetBirthday ) ;
this . CheckedForBirthday = false ;
}
2017-02-22 15:29:00 +08:00
2018-08-06 00:33:00 +08:00
if ( ! this . CheckedForBirthday & & Game1 . activeClickableMenu = = null )
2016-10-20 15:01:51 +08:00
{
2017-07-30 06:02:49 +08:00
this . CheckedForBirthday = true ;
// set up birthday
if ( this . IsBirthday ( ) )
2016-10-20 15:01:51 +08:00
{
2017-07-30 06:02:49 +08:00
Messages . ShowStarMessage ( "It's your birthday today! Happy birthday!" ) ;
2018-12-10 11:57:12 +08:00
MultiplayerSupport . SendBirthdayMessageToOtherPlayers ( ) ;
2018-05-10 05:23:42 +08:00
2018-05-01 09:21:31 +08:00
Game1 . player . mailbox . Add ( "birthdayMom" ) ;
Game1 . player . mailbox . Add ( "birthdayDad" ) ;
2017-02-22 15:29:00 +08:00
try
{
2017-07-30 06:02:49 +08:00
this . ResetVillagerQueue ( ) ;
2017-02-22 15:29:00 +08:00
}
2017-07-30 06:02:49 +08:00
catch ( Exception ex )
2017-02-22 15:29:00 +08:00
{
2017-07-30 06:02:49 +08:00
this . Monitor . Log ( ex . ToString ( ) , LogLevel . Error ) ;
2017-02-22 15:29:00 +08:00
}
2017-07-30 06:02:49 +08:00
foreach ( GameLocation location in Game1 . locations )
2016-10-20 15:01:51 +08:00
{
foreach ( NPC npc in location . characters )
{
2017-07-30 06:02:49 +08:00
if ( npc is Child | | npc is Horse | | npc is Junimo | | npc is Monster | | npc is Pet )
continue ;
2018-12-07 08:13:41 +08:00
//Add in birthday dialogues for npc.
2016-10-20 15:01:51 +08:00
try
{
2018-09-19 09:04:38 +08:00
if ( Game1 . player . getFriendshipHeartLevelForNPC ( npc . Name ) > = Config . minimumFriendshipLevelForBirthdayWish )
{
2018-12-07 08:13:41 +08:00
bool spouseMessage = false ; //Used to determine if there is a valid spouse message for the player. If false load in the generic birthday wish.
//Check if npc name is spouse's name. If no spouse then add in generic dialogue.
if ( messages . spouseBirthdayWishes . ContainsKey ( npc . Name ) & & Game1 . player . isMarried ( ) )
{
Monitor . Log ( "Spouse Checks out" ) ;
//Check to see if spouse message exists.
if ( ! String . IsNullOrEmpty ( messages . spouseBirthdayWishes [ npc . Name ] ) )
{
spouseMessage = true ;
Dialogue d = new Dialogue ( messages . spouseBirthdayWishes [ npc . Name ] , npc ) ;
npc . CurrentDialogue . Push ( d ) ;
if ( npc . CurrentDialogue . ElementAt ( 0 ) ! = d ) npc . setNewDialogue ( messages . spouseBirthdayWishes [ npc . Name ] ) ;
}
else
{
Monitor . Log ( "No spouse message???" , LogLevel . Warn ) ;
}
}
if ( spouseMessage = = false )
{
//Load in
Dialogue d = new Dialogue ( messages . birthdayWishes [ npc . Name ] , npc ) ;
npc . CurrentDialogue . Push ( d ) ;
if ( npc . CurrentDialogue . ElementAt ( 0 ) ! = d ) npc . setNewDialogue ( messages . birthdayWishes [ npc . Name ] ) ;
}
2018-09-19 09:04:38 +08:00
}
2016-10-20 15:01:51 +08:00
}
catch
{
2018-09-19 09:04:38 +08:00
if ( Game1 . player . getFriendshipHeartLevelForNPC ( npc . Name ) > = Config . minimumFriendshipLevelForBirthdayWish )
{
Dialogue d = new Dialogue ( "Happy Birthday @!" , npc ) ;
npc . CurrentDialogue . Push ( d ) ;
if ( npc . CurrentDialogue . ElementAt ( 0 ) ! = d )
npc . setNewDialogue ( "Happy Birthday @!" ) ;
}
2016-10-20 15:01:51 +08:00
}
}
}
}
2016-11-08 17:19:56 +08:00
2018-12-06 09:16:28 +08:00
//Don't constantly set the birthday menu.
2018-03-04 19:02:54 +08:00
if ( Game1 . activeClickableMenu ! = null )
{
if ( Game1 . activeClickableMenu . GetType ( ) = = typeof ( BirthdayMenu ) ) return ;
}
2017-07-30 06:02:49 +08:00
// ask for birthday date
2018-06-26 12:13:40 +08:00
if ( ! this . HasChosenBirthday & & Game1 . activeClickableMenu = = null )
2016-11-08 17:19:56 +08:00
{
2017-08-06 03:51:44 +08:00
Game1 . activeClickableMenu = new BirthdayMenu ( this . PlayerData . BirthdaySeason , this . PlayerData . BirthdayDay , this . SetBirthday ) ;
2017-07-30 06:02:49 +08:00
this . CheckedForBirthday = false ;
2016-11-08 17:19:56 +08:00
}
}
2018-12-06 09:16:28 +08:00
// Set birthday gift for the player to recieve from the npc they are currently talking with.
2016-10-20 15:01:51 +08:00
if ( Game1 . currentSpeaker ! = null )
{
2018-05-01 09:21:31 +08:00
string name = Game1 . currentSpeaker . Name ;
2017-07-30 06:02:49 +08:00
if ( this . IsBirthday ( ) & & this . VillagerQueue . Contains ( name ) )
2016-10-20 15:01:51 +08:00
{
try
{
2018-12-06 09:16:28 +08:00
giftManager . SetNextBirthdayGift ( Game1 . currentSpeaker . Name ) ;
2018-05-01 09:21:31 +08:00
this . VillagerQueue . Remove ( Game1 . currentSpeaker . Name ) ;
2016-10-20 15:01:51 +08:00
}
2017-07-30 06:02:49 +08:00
catch ( Exception ex )
2016-10-20 15:01:51 +08:00
{
2017-07-30 06:02:49 +08:00
this . Monitor . Log ( ex . ToString ( ) , LogLevel . Error ) ;
2016-10-20 15:01:51 +08:00
}
}
2018-12-06 09:16:28 +08:00
//Validate the gift and give it to the player.
if ( giftManager . BirthdayGiftToReceive ! = null )
{
while ( giftManager . BirthdayGiftToReceive . Name = = "Error Item" | | giftManager . BirthdayGiftToReceive . Name = = "Rock" | | giftManager . BirthdayGiftToReceive . Name = = "???" )
giftManager . SetNextBirthdayGift ( Game1 . currentSpeaker . Name ) ;
Game1 . player . addItemByMenuIfNecessaryElseHoldUp ( giftManager . BirthdayGiftToReceive ) ;
giftManager . BirthdayGiftToReceive = null ;
}
2016-10-20 15:01:51 +08:00
}
2018-12-06 09:16:28 +08:00
2016-10-20 15:01:51 +08:00
}
2018-12-06 09:16:28 +08:00
/// <summary>Set the player's birthday/</summary>
2017-07-30 06:02:49 +08:00
/// <param name="season">The birthday season.</param>
/// <param name="day">The birthday day.</param>
private void SetBirthday ( string season , int day )
2016-10-20 15:01:51 +08:00
{
2017-08-06 03:51:44 +08:00
this . PlayerData . BirthdaySeason = season ;
this . PlayerData . BirthdayDay = day ;
2017-02-22 15:29:00 +08:00
}
2017-07-30 06:02:49 +08:00
/// <summary>Reset the queue of villager names.</summary>
private void ResetVillagerQueue ( )
2017-02-22 15:29:00 +08:00
{
2017-07-30 06:02:49 +08:00
this . VillagerQueue . Clear ( ) ;
foreach ( GameLocation location in Game1 . locations )
2016-10-20 15:01:51 +08:00
{
2017-07-30 06:02:49 +08:00
foreach ( NPC npc in location . characters )
2016-10-20 15:01:51 +08:00
{
2017-07-30 06:02:49 +08:00
if ( npc is Child | | npc is Horse | | npc is Junimo | | npc is Monster | | npc is Pet )
2017-02-22 15:29:00 +08:00
continue ;
2018-05-01 09:21:31 +08:00
if ( this . VillagerQueue . Contains ( npc . Name ) )
2017-07-30 06:02:49 +08:00
continue ;
2018-05-01 09:21:31 +08:00
this . VillagerQueue . Add ( npc . Name ) ;
2017-02-22 15:29:00 +08:00
}
2016-10-20 15:01:51 +08:00
}
}
2017-07-30 06:02:49 +08:00
/// <summary>Get whether today is the player's birthday.</summary>
private bool IsBirthday ( )
{
return
2017-08-06 03:51:44 +08:00
this . PlayerData . BirthdayDay = = Game1 . dayOfMonth
& & this . PlayerData . BirthdaySeason = = Game1 . currentSeason ;
2017-07-30 06:02:49 +08:00
}
2016-10-20 15:01:51 +08:00
2017-08-06 03:51:44 +08:00
/// <summary>Migrate the legacy settings for the current player.</summary>
private void MigrateLegacyData ( )
2017-07-30 06:02:49 +08:00
{
2017-08-06 03:51:44 +08:00
// skip if no legacy data or new data already exists
try
2016-10-20 15:01:51 +08:00
{
2018-01-31 04:46:04 +08:00
if ( ! File . Exists ( this . LegacyDataFilePath ) | | File . Exists ( this . DataFilePath ) )
if ( this . PlayerData = = null ) this . PlayerData = new PlayerData ( ) ;
return ;
2016-10-20 15:01:51 +08:00
}
2018-01-31 04:46:04 +08:00
catch ( Exception err )
2016-10-20 15:01:51 +08:00
{
2018-05-01 09:21:31 +08:00
err . ToString ( ) ;
2018-01-31 04:46:04 +08:00
// migrate to new file
try
{
string [ ] text = File . ReadAllLines ( this . LegacyDataFilePath ) ;
2018-12-06 09:16:28 +08:00
this . Helper . Data . WriteJsonFile ( this . DataFilePath , new PlayerData
2018-01-31 04:46:04 +08:00
{
BirthdaySeason = text [ 3 ] ,
BirthdayDay = Convert . ToInt32 ( text [ 5 ] )
} ) ;
FileInfo file = new FileInfo ( this . LegacyDataFilePath ) ;
file . Delete ( ) ;
if ( ! file . Directory . EnumerateFiles ( ) . Any ( ) )
file . Directory . Delete ( ) ;
}
catch ( Exception ex )
{
this . Monitor . Log ( $"Error migrating data from the legacy 'Player_Birthdays' folder for the current player. Technical details:\n {ex}" , LogLevel . Error ) ;
}
2016-10-20 15:01:51 +08:00
}
2018-01-31 04:46:04 +08:00
2016-10-20 15:01:51 +08:00
}
2018-05-10 05:23:42 +08:00
2018-12-10 11:57:12 +08:00
2016-10-20 15:01:51 +08:00
}
}