diff --git a/StardewModdingAPI/Constants.cs b/StardewModdingAPI/Constants.cs index ddd46115..4a01c38a 100644 --- a/StardewModdingAPI/Constants.cs +++ b/StardewModdingAPI/Constants.cs @@ -58,5 +58,10 @@ namespace StardewModdingAPI /// Do not mark as 'const' or else 'if' checks will complain that the expression is always true in ReSharper /// public static bool EnableDrawingIntoRenderTarget => true; + + /// + /// Completely overrides the base game's draw call to the one is SGame + /// + public static bool EnableCompletelyOverridingBaseCalls => true; } } \ No newline at end of file diff --git a/StardewModdingAPI/Events/Controls.cs b/StardewModdingAPI/Events/Controls.cs index 87319f37..6415561a 100644 --- a/StardewModdingAPI/Events/Controls.cs +++ b/StardewModdingAPI/Events/Controls.cs @@ -15,42 +15,42 @@ namespace StardewModdingAPI.Events public static event EventHandler ControllerTriggerPressed = delegate { }; public static event EventHandler ControllerTriggerReleased = delegate { }; - public static void InvokeKeyboardChanged(KeyboardState priorState, KeyboardState newState) + internal static void InvokeKeyboardChanged(KeyboardState priorState, KeyboardState newState) { KeyboardChanged.Invoke(null, new EventArgsKeyboardStateChanged(priorState, newState)); } - public static void InvokeMouseChanged(MouseState priorState, MouseState newState) + internal static void InvokeMouseChanged(MouseState priorState, MouseState newState) { MouseChanged.Invoke(null, new EventArgsMouseStateChanged(priorState, newState)); } - public static void InvokeKeyPressed(Keys key) + internal static void InvokeKeyPressed(Keys key) { KeyPressed.Invoke(null, new EventArgsKeyPressed(key)); } - public static void InvokeKeyReleased(Keys key) + internal static void InvokeKeyReleased(Keys key) { KeyReleased.Invoke(null, new EventArgsKeyPressed(key)); } - public static void InvokeButtonPressed(PlayerIndex playerIndex, Buttons buttons) + internal static void InvokeButtonPressed(PlayerIndex playerIndex, Buttons buttons) { ControllerButtonPressed.Invoke(null, new EventArgsControllerButtonPressed(playerIndex, buttons)); } - public static void InvokeButtonReleased(PlayerIndex playerIndex, Buttons buttons) + internal static void InvokeButtonReleased(PlayerIndex playerIndex, Buttons buttons) { ControllerButtonReleased.Invoke(null, new EventArgsControllerButtonReleased(playerIndex, buttons)); } - public static void InvokeTriggerPressed(PlayerIndex playerIndex, Buttons buttons, float value) + internal static void InvokeTriggerPressed(PlayerIndex playerIndex, Buttons buttons, float value) { ControllerTriggerPressed.Invoke(null, new EventArgsControllerTriggerPressed(playerIndex, buttons, value)); } - public static void InvokeTriggerReleased(PlayerIndex playerIndex, Buttons buttons, float value) + internal static void InvokeTriggerReleased(PlayerIndex playerIndex, Buttons buttons, float value) { ControllerTriggerReleased.Invoke(null, new EventArgsControllerTriggerReleased(playerIndex, buttons, value)); } diff --git a/StardewModdingAPI/Events/EventArgs.cs b/StardewModdingAPI/Events/EventArgs.cs index 91151e86..d057796a 100644 --- a/StardewModdingAPI/Events/EventArgs.cs +++ b/StardewModdingAPI/Events/EventArgs.cs @@ -236,6 +236,19 @@ namespace StardewModdingAPI.Events public bool LoadedGame { get; private set; } } + public class EventArgsNewDay : EventArgs + { + public EventArgsNewDay(int prevDay, int curDay, bool newDay) + { + PreviousDay = prevDay; + CurrentDay = curDay; + IsNewDay = newDay; + } + + public int PreviousDay { get; private set; } + public int CurrentDay { get; private set; } + public bool IsNewDay { get; private set; } + } public class EventArgsCommand : EventArgs { diff --git a/StardewModdingAPI/Events/Game.cs b/StardewModdingAPI/Events/Game.cs index c8052962..8b8042ed 100644 --- a/StardewModdingAPI/Events/Game.cs +++ b/StardewModdingAPI/Events/Game.cs @@ -44,12 +44,12 @@ namespace StardewModdingAPI.Events /// public static event EventHandler OneSecondTick = delegate { }; - public static void InvokeGameLoaded() + internal static void InvokeGameLoaded() { GameLoaded.Invoke(null, EventArgs.Empty); } - public static void InvokeInitialize() + internal static void InvokeInitialize() { try { @@ -61,7 +61,7 @@ namespace StardewModdingAPI.Events } } - public static void InvokeLoadContent() + internal static void InvokeLoadContent() { try { @@ -73,7 +73,7 @@ namespace StardewModdingAPI.Events } } - public static void InvokeUpdateTick() + internal static void InvokeUpdateTick() { try { @@ -85,37 +85,37 @@ namespace StardewModdingAPI.Events } } - public static void InvokeSecondUpdateTick() + internal static void InvokeSecondUpdateTick() { SecondUpdateTick.Invoke(null, EventArgs.Empty); } - public static void InvokeFourthUpdateTick() + internal static void InvokeFourthUpdateTick() { FourthUpdateTick.Invoke(null, EventArgs.Empty); } - public static void InvokeEighthUpdateTick() + internal static void InvokeEighthUpdateTick() { EighthUpdateTick.Invoke(null, EventArgs.Empty); } - public static void InvokeQuarterSecondTick() + internal static void InvokeQuarterSecondTick() { QuarterSecondTick.Invoke(null, EventArgs.Empty); } - public static void InvokeHalfSecondTick() + internal static void InvokeHalfSecondTick() { HalfSecondTick.Invoke(null, EventArgs.Empty); } - public static void InvokeOneSecondTick() + internal static void InvokeOneSecondTick() { OneSecondTick.Invoke(null, EventArgs.Empty); } - public static void InvokeFirstUpdateTick() + internal static void InvokeFirstUpdateTick() { FirstUpdateTick.Invoke(null, EventArgs.Empty); } diff --git a/StardewModdingAPI/Events/Graphics.cs b/StardewModdingAPI/Events/Graphics.cs index 2b91144a..79c5b4aa 100644 --- a/StardewModdingAPI/Events/Graphics.cs +++ b/StardewModdingAPI/Events/Graphics.cs @@ -2,11 +2,47 @@ namespace StardewModdingAPI.Events { + /// + /// + /// public static class GraphicsEvents { + /// + /// Occurs when the form (game) is resized. + /// public static event EventHandler Resize = delegate { }; - public static event EventHandler DrawTick = delegate { }; - public static event EventHandler DrawInRenderTargetTick = delegate { }; + + + + /// + /// Occurs before anything is drawn. + /// + public static event EventHandler OnPreRenderEvent = delegate { }; + + /// + /// Occurs before the GUI is drawn. + /// + public static event EventHandler OnPreRenderGuiEvent = delegate { }; + + /// + /// Occurs after the GUI is drawn. + /// + public static event EventHandler OnPostRenderGuiEvent = delegate { }; + + /// + /// Occurs before the HUD is drawn. + /// + public static event EventHandler OnPreRenderHudEvent = delegate { }; + + /// + /// Occurs after the HUD is drawn. + /// + public static event EventHandler OnPostRenderHudEvent = delegate { }; + + /// + /// Occurs after everything is drawn. + /// + public static event EventHandler OnPostRenderEvent = delegate { }; /// /// Draws when SGame.Debug is true. F3 toggles this. @@ -16,6 +52,52 @@ namespace StardewModdingAPI.Events /// public static event EventHandler DrawDebug = delegate { }; + internal static void InvokeDrawDebug(object sender, EventArgs e) + { + DrawDebug.Invoke(sender, e); + } + + internal static void InvokeOnPreRenderEvent(object sender, EventArgs e) + { + OnPreRenderEvent.Invoke(sender, e); + } + + internal static void InvokeOnPreRenderGuiEvent(object sender, EventArgs e) + { + OnPreRenderGuiEvent.Invoke(sender, e); + } + + internal static void InvokeOnPostRenderGuiEvent(object sender, EventArgs e) + { + OnPostRenderGuiEvent.Invoke(sender, e); + } + + internal static void InvokeOnPreRenderHudEvent(object sender, EventArgs e) + { + OnPreRenderHudEvent.Invoke(sender, e); + } + + internal static void InvokeOnPostRenderHudEvent(object sender, EventArgs e) + { + OnPostRenderHudEvent.Invoke(sender, e); + } + + internal static void InvokeOnPostRenderEvent(object sender, EventArgs e) + { + OnPostRenderEvent.Invoke(sender, e); + } + + + + #region To Remove + + [Obsolete("Use the other Pre/Post render events instead.")] + public static event EventHandler DrawTick = delegate { }; + + [Obsolete("Use the other Pre/Post render events instead. All of them will automatically be drawn into the render target if needed.")] + public static event EventHandler DrawInRenderTargetTick = delegate { }; + + [Obsolete("Should not be used.")] public static void InvokeDrawTick() { try @@ -28,19 +110,18 @@ namespace StardewModdingAPI.Events } } + [Obsolete("Should not be used.")] public static void InvokeDrawInRenderTargetTick() { DrawInRenderTargetTick.Invoke(null, EventArgs.Empty); } + [Obsolete("Should not be used.")] public static void InvokeResize(object sender, EventArgs e) { Resize.Invoke(sender, e); } - public static void InvokeDrawDebug(object sender, EventArgs e) - { - DrawDebug.Invoke(sender, e); - } + #endregion } } \ No newline at end of file diff --git a/StardewModdingAPI/Events/Location.cs b/StardewModdingAPI/Events/Location.cs index d5b6cdec..f951ab95 100644 --- a/StardewModdingAPI/Events/Location.cs +++ b/StardewModdingAPI/Events/Location.cs @@ -12,12 +12,12 @@ namespace StardewModdingAPI.Events public static event EventHandler LocationObjectsChanged = delegate { }; public static event EventHandler CurrentLocationChanged = delegate { }; - public static void InvokeLocationsChanged(List newLocations) + internal static void InvokeLocationsChanged(List newLocations) { LocationsChanged.Invoke(null, new EventArgsGameLocationsChanged(newLocations)); } - public static void InvokeCurrentLocationChanged(GameLocation priorLocation, GameLocation newLocation) + internal static void InvokeCurrentLocationChanged(GameLocation priorLocation, GameLocation newLocation) { CurrentLocationChanged.Invoke(null, new EventArgsCurrentLocationChanged(priorLocation, newLocation)); } diff --git a/StardewModdingAPI/Events/Menu.cs b/StardewModdingAPI/Events/Menu.cs index 8acfc863..466a364e 100644 --- a/StardewModdingAPI/Events/Menu.cs +++ b/StardewModdingAPI/Events/Menu.cs @@ -7,7 +7,7 @@ namespace StardewModdingAPI.Events { public static event EventHandler MenuChanged = delegate { }; - public static void InvokeMenuChanged(IClickableMenu priorMenu, IClickableMenu newMenu) + internal static void InvokeMenuChanged(IClickableMenu priorMenu, IClickableMenu newMenu) { MenuChanged.Invoke(null, new EventArgsClickableMenuChanged(priorMenu, newMenu)); } diff --git a/StardewModdingAPI/Events/Mine.cs b/StardewModdingAPI/Events/Mine.cs index 2f89c91d..55514d42 100644 --- a/StardewModdingAPI/Events/Mine.cs +++ b/StardewModdingAPI/Events/Mine.cs @@ -6,7 +6,7 @@ namespace StardewModdingAPI.Events { public static event EventHandler MineLevelChanged = delegate { }; - public static void InvokeMineLevelChanged(int previousMinelevel, int currentMineLevel) + internal static void InvokeMineLevelChanged(int previousMinelevel, int currentMineLevel) { MineLevelChanged.Invoke(null, new EventArgsMineLevelChanged(previousMinelevel, currentMineLevel)); } diff --git a/StardewModdingAPI/Events/Player.cs b/StardewModdingAPI/Events/Player.cs index a658259e..22f572b7 100644 --- a/StardewModdingAPI/Events/Player.cs +++ b/StardewModdingAPI/Events/Player.cs @@ -12,22 +12,22 @@ namespace StardewModdingAPI.Events public static event EventHandler LeveledUp = delegate { }; public static event EventHandler LoadedGame = delegate { }; - public static void InvokeFarmerChanged(Farmer priorFarmer, Farmer newFarmer) + internal static void InvokeFarmerChanged(Farmer priorFarmer, Farmer newFarmer) { FarmerChanged.Invoke(null, new EventArgsFarmerChanged(priorFarmer, newFarmer)); } - public static void InvokeInventoryChanged(List inventory, List changedItems) + internal static void InvokeInventoryChanged(List inventory, List changedItems) { InventoryChanged.Invoke(null, new EventArgsInventoryChanged(inventory, changedItems)); } - public static void InvokeLeveledUp(EventArgsLevelUp.LevelType type, int newLevel) + internal static void InvokeLeveledUp(EventArgsLevelUp.LevelType type, int newLevel) { LeveledUp.Invoke(null, new EventArgsLevelUp(type, newLevel)); } - public static void InvokeLoadedGame(EventArgsLoadedGameChanged loaded) + internal static void InvokeLoadedGame(EventArgsLoadedGameChanged loaded) { LoadedGame.Invoke(null, loaded); } diff --git a/StardewModdingAPI/Events/Time.cs b/StardewModdingAPI/Events/Time.cs index 56b23dc3..39ca642a 100644 --- a/StardewModdingAPI/Events/Time.cs +++ b/StardewModdingAPI/Events/Time.cs @@ -9,24 +9,34 @@ namespace StardewModdingAPI.Events public static event EventHandler YearOfGameChanged = delegate { }; public static event EventHandler SeasonOfYearChanged = delegate { }; - public static void InvokeTimeOfDayChanged(int priorInt, int newInt) + /// + /// Occurs when Game1.newDay changes. True directly before saving, and False directly after. + /// + public static event EventHandler OnNewDay = delegate { }; + + internal static void InvokeTimeOfDayChanged(int priorInt, int newInt) { TimeOfDayChanged.Invoke(null, new EventArgsIntChanged(priorInt, newInt)); } - public static void InvokeDayOfMonthChanged(int priorInt, int newInt) + internal static void InvokeDayOfMonthChanged(int priorInt, int newInt) { DayOfMonthChanged.Invoke(null, new EventArgsIntChanged(priorInt, newInt)); } - public static void InvokeYearOfGameChanged(int priorInt, int newInt) + internal static void InvokeYearOfGameChanged(int priorInt, int newInt) { YearOfGameChanged.Invoke(null, new EventArgsIntChanged(priorInt, newInt)); } - public static void InvokeSeasonOfYearChanged(string priorString, string newString) + internal static void InvokeSeasonOfYearChanged(string priorString, string newString) { SeasonOfYearChanged.Invoke(null, new EventArgsStringChanged(priorString, newString)); } + + internal static void InvokeOnNewDay(int priorInt, int newInt, bool newDay) + { + OnNewDay.Invoke(null, new EventArgsNewDay(priorInt, newInt, newDay)); + } } } \ No newline at end of file diff --git a/StardewModdingAPI/Inheritance/SGame.cs b/StardewModdingAPI/Inheritance/SGame.cs index b6fe727b..d6263d73 100644 --- a/StardewModdingAPI/Inheritance/SGame.cs +++ b/StardewModdingAPI/Inheritance/SGame.cs @@ -7,7 +7,12 @@ using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using StardewModdingAPI.Events; using StardewValley; +using StardewValley.BellsAndWhistles; +using StardewValley.Locations; using StardewValley.Menus; +using StardewValley.Tools; +using xTile.Dimensions; +using Rectangle = Microsoft.Xna.Framework.Rectangle; namespace StardewModdingAPI.Inheritance { @@ -39,6 +44,7 @@ namespace StardewModdingAPI.Inheritance /// Useless at this time. /// [Obsolete] + // ReSharper disable once UnusedAutoPropertyAccessor.Local public static Dictionary ModItems { get; private set; } /// @@ -162,6 +168,11 @@ namespace StardewModdingAPI.Inheritance /// public int PreviousYearOfGame { get; private set; } + /// + /// The previous result of Game1.newDay + /// + public bool PreviousIsNewDay { get; private set; } + /// /// The previous 'Farmer' (Player) /// @@ -186,6 +197,24 @@ namespace StardewModdingAPI.Inheritance set { typeof (Game1).SetBaseFieldValue(this, "screen", value); } } + /// + /// + /// + public int ThumbstickMotionMargin + { + get { return (int)typeof(Game1).GetBaseFieldValue(Program.gamePtr, "thumbstickMotionMargin"); } + set { typeof(Game1).SetBaseFieldValue(this, "thumbstickMotionMargin", value); } + } + + /// + /// The current Colour in Game1 (Private field, uses reflection) + /// + public Color BgColour + { + get { return (Color)typeof(Game1).GetBaseFieldValue(Program.gamePtr, "bgColor"); } + set { typeof(Game1).SetBaseFieldValue(this, "bgColor", value); } + } + /// /// Static accessor for an Instance of the class SGame /// @@ -200,14 +229,7 @@ namespace StardewModdingAPI.Inheritance /// Whether or not we're in a pseudo 'debug' mode. Mostly for displaying information like FPS. /// public static bool Debug { get; private set; } - - /// - /// A queue of messages to log when Debug is true. - /// If debug is false this queue will be emptied every frame. - /// Do not add to the queue if debug is false. - /// The queue will be drawn once every Draw update. - /// - public static Queue DebugMessageQueue { get; private set; } + internal static Queue DebugMessageQueue { get; private set; } /// /// The current player (equal to Farmer.Player) @@ -364,6 +386,11 @@ namespace StardewModdingAPI.Inheritance return buttons.ToArray(); } + /// + /// Whether or not the game's zoom level is 1.0f + /// + public bool ZoomLevelIsOne => options.zoomLevel.Equals(1.0f); + /// /// XNA Init Method /// @@ -395,21 +422,334 @@ namespace StardewModdingAPI.Inheritance /// protected override void Update(GameTime gameTime) { + QueueDebugMessage("FPS: " + FramesPerSecond); UpdateEventCalls(); + if (ZoomLevelIsOne) + { + options.zoomLevel = 0.99f; + InvokeBasePrivateInstancedMethod("Window_ClientSizeChanged", null, null); + } + if (FramePressedKeys.Contains(Keys.F3)) { Debug = !Debug; } - try + if (FramePressedKeys.Contains(Keys.F2)) { - base.Update(gameTime); + //Built-in debug mode + debugMode = !debugMode; } - catch (Exception ex) + + if (Constants.EnableCompletelyOverridingBaseCalls) { - Log.AsyncR("An error occured in the base update loop: " + ex); - Console.ReadKey(); + #region Overridden Update Call + + if (Program.BuildType == 0) + SteamHelper.update(); + if ((paused /*|| !this.IsActive*/) && (options == null || options.pauseWhenOutOfFocus || paused)) + return; + if (quit) + Exit(); + currentGameTime = gameTime; + if (gameMode != 11) + { + if (IsMultiplayer && gameMode == 3) + { + if (multiplayerMode == 2) + server.receiveMessages(); + else + client.receiveMessages(); + } + if (IsActive) + InvokeBasePrivateInstancedMethod("checkForEscapeKeys"); + //this.checkForEscapeKeys(); + updateMusic(); + updateRaindropPosition(); + if (bloom != null) + bloom.tick(gameTime); + if (globalFade) + { + if (!dialogueUp) + { + if (fadeIn) + { + fadeToBlackAlpha = Math.Max(0.0f, fadeToBlackAlpha - globalFadeSpeed); + if (fadeToBlackAlpha <= 0.0) + { + globalFade = false; + if (afterFade != null) + { + afterFadeFunction afterFadeFunction = afterFade; + afterFade(); + if (afterFade != null && afterFade.Equals(afterFadeFunction)) + afterFade = null; + if (nonWarpFade) + fadeToBlack = false; + } + } + } + else + { + fadeToBlackAlpha = Math.Min(1f, fadeToBlackAlpha + globalFadeSpeed); + if (fadeToBlackAlpha >= 1.0) + { + globalFade = false; + if (afterFade != null) + { + afterFadeFunction afterFadeFunction = afterFade; + afterFade(); + if (afterFade != null && afterFade.Equals(afterFadeFunction)) + afterFade = null; + if (nonWarpFade) + fadeToBlack = false; + } + } + } + } + else + InvokeBasePrivateInstancedMethod("UpdateControlInput", gameTime); + //this.UpdateControlInput(gameTime); + } + else if (pauseThenDoFunctionTimer > 0) + { + freezeControls = true; + pauseThenDoFunctionTimer -= gameTime.ElapsedGameTime.Milliseconds; + if (pauseThenDoFunctionTimer <= 0) + { + freezeControls = false; + if (afterPause != null) + afterPause(); + } + } + if (gameMode == 3 || gameMode == 2) + { + player.millisecondsPlayed += (uint)gameTime.ElapsedGameTime.Milliseconds; + bool flag = true; + if (currentMinigame != null) + { + if (pauseTime > 0.0) + updatePause(gameTime); + if (fadeToBlack) + { + updateScreenFade(gameTime); + if (fadeToBlackAlpha >= 1.0) + fadeToBlack = false; + } + else + { + if (ThumbstickMotionMargin > 0) + ThumbstickMotionMargin -= gameTime.ElapsedGameTime.Milliseconds; + if (IsActive) + { + KeyboardState state1 = Keyboard.GetState(); + MouseState state2 = Mouse.GetState(); + GamePadState state3 = GamePad.GetState(PlayerIndex.One); + foreach (Keys keys in state1.GetPressedKeys()) + { + if (!oldKBState.IsKeyDown(keys)) + currentMinigame.receiveKeyPress(keys); + } + if (options.gamepadControls) + { + if (currentMinigame == null) + { + oldMouseState = state2; + oldKBState = state1; + oldPadState = state3; + return; + } + foreach (Buttons b in Utility.getPressedButtons(state3, oldPadState)) + currentMinigame.receiveKeyPress(Utility.mapGamePadButtonToKey(b)); + if (currentMinigame == null) + { + oldMouseState = state2; + oldKBState = state1; + oldPadState = state3; + return; + } + if (state3.ThumbSticks.Right.Y < -0.200000002980232 && oldPadState.ThumbSticks.Right.Y >= -0.200000002980232) + currentMinigame.receiveKeyPress(Keys.Down); + if (state3.ThumbSticks.Right.Y > 0.200000002980232 && oldPadState.ThumbSticks.Right.Y <= 0.200000002980232) + currentMinigame.receiveKeyPress(Keys.Up); + if (state3.ThumbSticks.Right.X < -0.200000002980232 && oldPadState.ThumbSticks.Right.X >= -0.200000002980232) + currentMinigame.receiveKeyPress(Keys.Left); + if (state3.ThumbSticks.Right.X > 0.200000002980232 && oldPadState.ThumbSticks.Right.X <= 0.200000002980232) + currentMinigame.receiveKeyPress(Keys.Right); + if (oldPadState.ThumbSticks.Right.Y < -0.200000002980232 && state3.ThumbSticks.Right.Y >= -0.200000002980232) + currentMinigame.receiveKeyRelease(Keys.Down); + if (oldPadState.ThumbSticks.Right.Y > 0.200000002980232 && state3.ThumbSticks.Right.Y <= 0.200000002980232) + currentMinigame.receiveKeyRelease(Keys.Up); + if (oldPadState.ThumbSticks.Right.X < -0.200000002980232 && state3.ThumbSticks.Right.X >= -0.200000002980232) + currentMinigame.receiveKeyRelease(Keys.Left); + if (oldPadState.ThumbSticks.Right.X > 0.200000002980232 && state3.ThumbSticks.Right.X <= 0.200000002980232) + currentMinigame.receiveKeyRelease(Keys.Right); + if (isGamePadThumbstickInMotion()) + { + setMousePosition(getMouseX() + (int)(state3.ThumbSticks.Left.X * 16.0), getMouseY() - (int)(state3.ThumbSticks.Left.Y * 16.0)); + lastCursorMotionWasMouse = false; + } + else if (getMousePosition().X != getOldMouseX() || getMousePosition().Y != getOldMouseY()) + lastCursorMotionWasMouse = true; + } + foreach (Keys keys in oldKBState.GetPressedKeys()) + { + if (!state1.IsKeyDown(keys)) + currentMinigame.receiveKeyRelease(keys); + } + if (options.gamepadControls) + { + if (currentMinigame == null) + { + oldMouseState = state2; + oldKBState = state1; + oldPadState = state3; + return; + } + if (state3.IsConnected && state3.IsButtonDown(Buttons.X) && !oldPadState.IsButtonDown(Buttons.X)) + currentMinigame.receiveRightClick(getMouseX(), getMouseY(), true); + else if (state3.IsConnected && state3.IsButtonDown(Buttons.A) && !oldPadState.IsButtonDown(Buttons.A)) + currentMinigame.receiveLeftClick(getMouseX(), getMouseY(), true); + else if (state3.IsConnected && !state3.IsButtonDown(Buttons.X) && oldPadState.IsButtonDown(Buttons.X)) + currentMinigame.releaseRightClick(getMouseX(), getMouseY()); + else if (state3.IsConnected && !state3.IsButtonDown(Buttons.A) && oldPadState.IsButtonDown(Buttons.A)) + currentMinigame.releaseLeftClick(getMouseX(), getMouseY()); + foreach (Buttons b in Utility.getPressedButtons(oldPadState, state3)) + currentMinigame.receiveKeyRelease(Utility.mapGamePadButtonToKey(b)); + if (state3.IsConnected && state3.IsButtonDown(Buttons.A) && currentMinigame != null) + currentMinigame.leftClickHeld(0, 0); + } + if (currentMinigame == null) + { + oldMouseState = state2; + oldKBState = state1; + oldPadState = state3; + return; + } + if (state2.LeftButton == ButtonState.Pressed && oldMouseState.LeftButton != ButtonState.Pressed) + currentMinigame.receiveLeftClick(getMouseX(), getMouseY(), true); + if (state2.RightButton == ButtonState.Pressed && oldMouseState.RightButton != ButtonState.Pressed) + currentMinigame.receiveRightClick(getMouseX(), getMouseY(), true); + if (state2.LeftButton == ButtonState.Released && oldMouseState.LeftButton == ButtonState.Pressed) + currentMinigame.releaseLeftClick(getMouseX(), getMouseY()); + if (state2.RightButton == ButtonState.Released && oldMouseState.RightButton == ButtonState.Pressed) + currentMinigame.releaseLeftClick(getMouseX(), getMouseY()); + if (state2.LeftButton == ButtonState.Pressed && oldMouseState.LeftButton == ButtonState.Pressed) + currentMinigame.leftClickHeld(getMouseX(), getMouseY()); + oldMouseState = state2; + oldKBState = state1; + oldPadState = state3; + } + if (currentMinigame != null && currentMinigame.tick(gameTime)) + { + currentMinigame.unload(); + currentMinigame = null; + fadeIn = true; + fadeToBlackAlpha = 1f; + return; + } + } + flag = IsMultiplayer; + } + else if (farmEvent != null && farmEvent.tickUpdate(gameTime)) + { + farmEvent.makeChangesToLocation(); + timeOfDay = 600; + UpdateOther(gameTime); + displayHUD = true; + farmEvent = null; + currentLocation = getLocationFromName("FarmHouse"); + player.position = Utility.PointToVector2(Utility.getHomeOfFarmer(player).getBedSpot()) * tileSize; + player.position.X -= tileSize; + changeMusicTrack("none"); + currentLocation.resetForPlayerEntry(); + player.forceCanMove(); + freezeControls = false; + displayFarmer = true; + outdoorLight = Color.White; + viewportFreeze = false; + fadeToBlackAlpha = 0.0f; + fadeToBlack = false; + globalFadeToClear(null, 0.02f); + player.mailForTomorrow.Clear(); + showEndOfNightStuff(); + } + if (flag) + { + if (endOfNightMenus.Count() > 0 && activeClickableMenu == null) + activeClickableMenu = endOfNightMenus.Pop(); + if (activeClickableMenu != null) + { + updateActiveMenu(gameTime); + } + else + { + if (pauseTime > 0.0) + updatePause(gameTime); + if (!globalFade && !freezeControls && (activeClickableMenu == null && IsActive)) + InvokeBasePrivateInstancedMethod("UpdateControlInput", gameTime); + //this.UpdateControlInput(gameTime); + } + if (showingEndOfNightStuff && endOfNightMenus.Count() == 0 && activeClickableMenu == null) + { + showingEndOfNightStuff = false; + globalFadeToClear(playMorningSong, 0.02f); + } + if (!showingEndOfNightStuff) + { + if (IsMultiplayer || activeClickableMenu == null && currentMinigame == null) + UpdateGameClock(gameTime); + //this.UpdateCharacters(gameTime); + //this.UpdateLocations(gameTime); + InvokeBasePrivateInstancedMethod("UpdateCharacters", gameTime); + InvokeBasePrivateInstancedMethod("UpdateLocations", gameTime); + UpdateViewPort(false, (Point)InvokeBasePrivateInstancedMethod("getViewportCenter")); + } + UpdateOther(gameTime); + if (messagePause) + { + KeyboardState state1 = Keyboard.GetState(); + MouseState state2 = Mouse.GetState(); + GamePadState state3 = GamePad.GetState(PlayerIndex.One); + if (isOneOfTheseKeysDown(state1, options.actionButton) && !isOneOfTheseKeysDown(oldKBState, options.actionButton)) + pressActionButton(state1, state2, state3); + oldKBState = state1; + oldPadState = state3; + } + } + } + else + { + InvokeBasePrivateInstancedMethod("UpdateTitleScreen", gameTime); + //this.UpdateTitleScreen(gameTime); + if (activeClickableMenu != null) + updateActiveMenu(gameTime); + if (gameMode == 10) + UpdateOther(gameTime); + } + if (audioEngine != null) + audioEngine.Update(); + if (multiplayerMode == 2 && gameMode == 3) + server.sendMessages(gameTime); + } + + //typeof (Game).GetMethod("Update", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(this, new object[] {gameTime}); + //base.Update(gameTime); + + #endregion + } + else + { + try + { + base.Update(gameTime); + } + catch (Exception ex) + { + Log.AsyncR("An error occured in the base update loop: " + ex); + Console.ReadKey(); + } } GameEvents.InvokeUpdateTick(); @@ -458,66 +798,538 @@ namespace StardewModdingAPI.Inheritance { FramesPerSecond = 1 / (float) gameTime.ElapsedGameTime.TotalSeconds; - try + if (Constants.EnableCompletelyOverridingBaseCalls) { - base.Draw(gameTime); - } - catch (Exception ex) - { - Log.AsyncR("An error occured in the base draw loop: " + ex); - Console.ReadKey(); - } + #region Overridden Draw - GraphicsEvents.InvokeDrawTick(); - - if (Constants.EnableDrawingIntoRenderTarget) - { - if (!options.zoomLevel.Equals(1.0f)) + if (!ZoomLevelIsOne) { - if (Screen.RenderTargetUsage == RenderTargetUsage.DiscardContents) - { - Screen = new RenderTarget2D(graphics.GraphicsDevice, Math.Min(4096, (int) (Window.ClientBounds.Width * (1.0 / options.zoomLevel))), - Math.Min(4096, (int) (Window.ClientBounds.Height * (1.0 / options.zoomLevel))), - false, SurfaceFormat.Color, DepthFormat.Depth16, 1, RenderTargetUsage.PreserveContents); - } GraphicsDevice.SetRenderTarget(Screen); } - // Not beginning the batch due to inconsistancies with the standard draw tick... - //spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); - - GraphicsEvents.InvokeDrawInRenderTargetTick(); - - //spriteBatch.End(); - - //Re-draw the HUD - spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); - if ((displayHUD || eventUp) && currentBillboard == 0 && gameMode == 3 && !freezeControls && !panMode) - typeof (Game1).GetMethod("drawHUD", BindingFlags.NonPublic | BindingFlags.Instance)?.Invoke(Program.gamePtr, null); + GraphicsDevice.Clear(BgColour); + if (options.showMenuBackground && activeClickableMenu != null && activeClickableMenu.showWithoutTransparencyIfOptionIsSet()) + { + spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + activeClickableMenu.drawBackground(spriteBatch); + activeClickableMenu.draw(spriteBatch); + spriteBatch.End(); + if (!ZoomLevelIsOne) + { + GraphicsDevice.SetRenderTarget(null); + GraphicsDevice.Clear(BgColour); + spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); + spriteBatch.Draw(Screen, Vector2.Zero, Screen.Bounds, Color.White, 0f, Vector2.Zero, options.zoomLevel, SpriteEffects.None, 1f); + spriteBatch.End(); + } + return; + } + if (gameMode == 11) + { + spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + spriteBatch.DrawString(smoothFont, "Stardew Valley has crashed...", new Vector2(16f, 16f), Color.HotPink); + spriteBatch.DrawString(smoothFont, "Please send the error report or a screenshot of this message to @ConcernedApe. (http://stardewvalley.net/contact/)", new Vector2(16f, 32f), new Color(0, 255, 0)); + spriteBatch.DrawString(smoothFont, parseText(errorMessage, smoothFont, graphics.GraphicsDevice.Viewport.Width), new Vector2(16f, 48f), Color.White); + spriteBatch.End(); + return; + } + if (currentMinigame != null) + { + currentMinigame.draw(spriteBatch); + if (globalFade && !menuUp && (!nameSelectUp || messagePause)) + { + spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + spriteBatch.Draw(fadeToBlackRect, graphics.GraphicsDevice.Viewport.Bounds, Color.Black * ((gameMode == 0) ? (1f - fadeToBlackAlpha) : fadeToBlackAlpha)); + spriteBatch.End(); + } + if (!ZoomLevelIsOne) + { + GraphicsDevice.SetRenderTarget(null); + GraphicsDevice.Clear(BgColour); + spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); + spriteBatch.Draw(Screen, Vector2.Zero, Screen.Bounds, Color.White, 0f, Vector2.Zero, options.zoomLevel, SpriteEffects.None, 1f); + spriteBatch.End(); + } + return; + } + if (showingEndOfNightStuff) + { + spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + activeClickableMenu?.draw(spriteBatch); + spriteBatch.End(); + if (!ZoomLevelIsOne) + { + GraphicsDevice.SetRenderTarget(null); + GraphicsDevice.Clear(BgColour); + spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); + spriteBatch.Draw(Screen, Vector2.Zero, Screen.Bounds, Color.White, 0f, Vector2.Zero, options.zoomLevel, SpriteEffects.None, 1f); + spriteBatch.End(); + } + return; + } + if (gameMode == 6) + { + spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + string text = ""; + int num = 0; + while (num < gameTime.TotalGameTime.TotalMilliseconds % 999.0 / 333.0) + { + text += "."; + num++; + } + SpriteText.drawString(spriteBatch, "Loading" + text, 64, graphics.GraphicsDevice.Viewport.Height - 64, 999, -1, 999, 1f, 1f, false, 0, "Loading..."); + spriteBatch.End(); + if (!ZoomLevelIsOne) + { + GraphicsDevice.SetRenderTarget(null); + GraphicsDevice.Clear(BgColour); + spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); + spriteBatch.Draw(Screen, Vector2.Zero, Screen.Bounds, Color.White, 0f, Vector2.Zero, options.zoomLevel, SpriteEffects.None, 1f); + spriteBatch.End(); + } + return; + } + if (gameMode == 0) + { + spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + } + else + { + if (drawLighting) + { + GraphicsDevice.SetRenderTarget(lightmap); + GraphicsDevice.Clear(Color.White * 0f); + spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.PointClamp, null, null); + spriteBatch.Draw(staminaRect, lightmap.Bounds, currentLocation.name.Equals("UndergroundMine") ? mine.getLightingColor(gameTime) : ((!ambientLight.Equals(Color.White) && (!isRaining || !currentLocation.isOutdoors)) ? ambientLight : outdoorLight)); + for (int i = 0; i < currentLightSources.Count; i++) + { + if (Utility.isOnScreen(currentLightSources.ElementAt(i).position, (int) (currentLightSources.ElementAt(i).radius * tileSize * 4f))) + { + spriteBatch.Draw(currentLightSources.ElementAt(i).lightTexture, GlobalToLocal(viewport, currentLightSources.ElementAt(i).position) / options.lightingQuality, currentLightSources.ElementAt(i).lightTexture.Bounds, currentLightSources.ElementAt(i).color, 0f, new Vector2(currentLightSources.ElementAt(i).lightTexture.Bounds.Center.X, currentLightSources.ElementAt(i).lightTexture.Bounds.Center.Y), currentLightSources.ElementAt(i).radius / options.lightingQuality, SpriteEffects.None, 0.9f); + } + } + spriteBatch.End(); + GraphicsDevice.SetRenderTarget(!ZoomLevelIsOne ? null : Screen); + } + if (bloomDay) + { + bloom?.BeginDraw(); + } + GraphicsDevice.Clear(BgColour); + spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + GraphicsEvents.InvokeOnPreRenderEvent(null, EventArgs.Empty); + background?.draw(spriteBatch); + mapDisplayDevice.BeginScene(spriteBatch); + currentLocation.Map.GetLayer("Back").Draw(mapDisplayDevice, viewport, Location.Origin, false, pixelZoom); + currentLocation.drawWater(spriteBatch); + if (CurrentEvent == null) + { + using (List.Enumerator enumerator = currentLocation.characters.GetEnumerator()) + { + while (enumerator.MoveNext()) + { + NPC current = enumerator.Current; + if (current != null && !current.swimming && !current.hideShadow && !current.IsMonster && !currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(current.getTileLocation())) + { + spriteBatch.Draw(shadowTexture, GlobalToLocal(viewport, current.position + new Vector2(current.sprite.spriteWidth * pixelZoom / 2f, current.GetBoundingBox().Height + (current.IsMonster ? 0 : (pixelZoom * 3)))), shadowTexture.Bounds, Color.White, 0f, new Vector2(shadowTexture.Bounds.Center.X, shadowTexture.Bounds.Center.Y), (pixelZoom + current.yJumpOffset / 40f) * current.scale, SpriteEffects.None, Math.Max(0f, current.getStandingY() / 10000f) - 1E-06f); + } + } + goto IL_B30; + } + } + foreach (NPC current2 in CurrentEvent.actors) + { + if (!current2.swimming && !current2.hideShadow && !currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(current2.getTileLocation())) + { + spriteBatch.Draw(shadowTexture, GlobalToLocal(viewport, current2.position + new Vector2(current2.sprite.spriteWidth * pixelZoom / 2f, current2.GetBoundingBox().Height + (current2.IsMonster ? 0 : (pixelZoom * 3)))), shadowTexture.Bounds, Color.White, 0f, new Vector2(shadowTexture.Bounds.Center.X, shadowTexture.Bounds.Center.Y), (pixelZoom + current2.yJumpOffset / 40f) * current2.scale, SpriteEffects.None, Math.Max(0f, current2.getStandingY() / 10000f) - 1E-06f); + } + } + IL_B30: + if (!player.swimming && !player.isRidingHorse() && !currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(player.getTileLocation())) + { + spriteBatch.Draw(shadowTexture, GlobalToLocal(player.position + new Vector2(32f, 24f)), shadowTexture.Bounds, Color.White, 0f, new Vector2(shadowTexture.Bounds.Center.X, shadowTexture.Bounds.Center.Y), 4f - (((player.running || player.usingTool) && player.FarmerSprite.indexInCurrentAnimation > 1) ? (Math.Abs(FarmerRenderer.featureYOffsetPerFrame[player.FarmerSprite.CurrentFrame]) * 0.5f) : 0f), SpriteEffects.None, 0f); + } + currentLocation.Map.GetLayer("Buildings").Draw(mapDisplayDevice, viewport, Location.Origin, false, pixelZoom); + mapDisplayDevice.EndScene(); + spriteBatch.End(); + spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + if (CurrentEvent == null) + { + using (List.Enumerator enumerator3 = currentLocation.characters.GetEnumerator()) + { + while (enumerator3.MoveNext()) + { + NPC current3 = enumerator3.Current; + if (current3 != null && !current3.swimming && !current3.hideShadow && currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(current3.getTileLocation())) + { + spriteBatch.Draw(shadowTexture, GlobalToLocal(viewport, current3.position + new Vector2(current3.sprite.spriteWidth * pixelZoom / 2f, current3.GetBoundingBox().Height + (current3.IsMonster ? 0 : (pixelZoom * 3)))), shadowTexture.Bounds, Color.White, 0f, new Vector2(shadowTexture.Bounds.Center.X, shadowTexture.Bounds.Center.Y), (pixelZoom + current3.yJumpOffset / 40f) * current3.scale, SpriteEffects.None, Math.Max(0f, current3.getStandingY() / 10000f) - 1E-06f); + } + } + goto IL_F5F; + } + } + foreach (NPC current4 in CurrentEvent.actors) + { + if (!current4.swimming && !current4.hideShadow && currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(current4.getTileLocation())) + { + spriteBatch.Draw(shadowTexture, GlobalToLocal(viewport, current4.position + new Vector2(current4.sprite.spriteWidth * pixelZoom / 2f, current4.GetBoundingBox().Height + (current4.IsMonster ? 0 : (pixelZoom * 3)))), shadowTexture.Bounds, Color.White, 0f, new Vector2(shadowTexture.Bounds.Center.X, shadowTexture.Bounds.Center.Y), (pixelZoom + current4.yJumpOffset / 40f) * current4.scale, SpriteEffects.None, Math.Max(0f, current4.getStandingY() / 10000f) - 1E-06f); + } + } + IL_F5F: + if (!player.swimming && !player.isRidingHorse() && currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(player.getTileLocation())) + { + spriteBatch.Draw(shadowTexture, GlobalToLocal(player.position + new Vector2(32f, 24f)), shadowTexture.Bounds, Color.White, 0f, new Vector2(shadowTexture.Bounds.Center.X, shadowTexture.Bounds.Center.Y), 4f - (((player.running || player.usingTool) && player.FarmerSprite.indexInCurrentAnimation > 1) ? (Math.Abs(FarmerRenderer.featureYOffsetPerFrame[player.FarmerSprite.CurrentFrame]) * 0.5f) : 0f), SpriteEffects.None, Math.Max(0.0001f, player.getStandingY() / 10000f + 0.00011f) - 0.0001f); + } + if (displayFarmer) + { + player.draw(spriteBatch); + } + if ((eventUp || killScreen) && !killScreen) + { + currentLocation.currentEvent?.draw(spriteBatch); + } + if (player.currentUpgrade != null && player.currentUpgrade.daysLeftTillUpgradeDone <= 3 && currentLocation.Name.Equals("Farm")) + { + spriteBatch.Draw(player.currentUpgrade.workerTexture, GlobalToLocal(viewport, player.currentUpgrade.positionOfCarpenter), player.currentUpgrade.getSourceRectangle(), Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, (player.currentUpgrade.positionOfCarpenter.Y + tileSize * 3 / 4) / 10000f); + } + currentLocation.draw(spriteBatch); + if (eventUp && currentLocation.currentEvent?.messageToScreen != null) + { + drawWithBorder(currentLocation.currentEvent.messageToScreen, Color.Black, Color.White, new Vector2(graphics.GraphicsDevice.Viewport.TitleSafeArea.Width / 2 - borderFont.MeasureString(currentLocation.currentEvent.messageToScreen).X / 2f, graphics.GraphicsDevice.Viewport.TitleSafeArea.Height - tileSize), 0f, 1f, 0.999f); + } + if (player.ActiveObject == null && (player.UsingTool || pickingTool) && player.CurrentTool != null && (!player.CurrentTool.Name.Equals("Seeds") || pickingTool)) + { + drawTool(player); + } + if (currentLocation.Name.Equals("Farm")) + { + typeof (Game1).GetMethod("drawFarmBuildings", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(Program.gamePtr, null); + //this.drawFarmBuildings(); + } + if (tvStation >= 0) + { + spriteBatch.Draw(tvStationTexture, GlobalToLocal(viewport, new Vector2(6 * tileSize + tileSize / 4, 2 * tileSize + tileSize / 2)), new Rectangle(tvStation * 24, 0, 24, 15), Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, 1E-08f); + } + if (panMode) + { + spriteBatch.Draw(fadeToBlackRect, new Rectangle((int) Math.Floor((getOldMouseX() + viewport.X) / (double) tileSize) * tileSize - viewport.X, (int) Math.Floor((getOldMouseY() + viewport.Y) / (double) tileSize) * tileSize - viewport.Y, tileSize, tileSize), Color.Lime * 0.75f); + foreach (Warp current5 in currentLocation.warps) + { + spriteBatch.Draw(fadeToBlackRect, new Rectangle(current5.X * tileSize - viewport.X, current5.Y * tileSize - viewport.Y, tileSize, tileSize), Color.Red * 0.75f); + } + } + mapDisplayDevice.BeginScene(spriteBatch); + currentLocation.Map.GetLayer("Front").Draw(mapDisplayDevice, viewport, Location.Origin, false, pixelZoom); + mapDisplayDevice.EndScene(); + currentLocation.drawAboveFrontLayer(spriteBatch); + spriteBatch.End(); + spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + if (currentLocation.Name.Equals("Farm") && stats.SeedsSown >= 200u) + { + spriteBatch.Draw(debrisSpriteSheet, GlobalToLocal(viewport, new Vector2(3 * tileSize + tileSize / 4, tileSize + tileSize / 3)), getSourceRectForStandardTileSheet(debrisSpriteSheet, 16), Color.White); + spriteBatch.Draw(debrisSpriteSheet, GlobalToLocal(viewport, new Vector2(4 * tileSize + tileSize, 2 * tileSize + tileSize)), getSourceRectForStandardTileSheet(debrisSpriteSheet, 16), Color.White); + spriteBatch.Draw(debrisSpriteSheet, GlobalToLocal(viewport, new Vector2(5 * tileSize, 2 * tileSize)), getSourceRectForStandardTileSheet(debrisSpriteSheet, 16), Color.White); + spriteBatch.Draw(debrisSpriteSheet, GlobalToLocal(viewport, new Vector2(3 * tileSize + tileSize / 2, 3 * tileSize)), getSourceRectForStandardTileSheet(debrisSpriteSheet, 16), Color.White); + spriteBatch.Draw(debrisSpriteSheet, GlobalToLocal(viewport, new Vector2(5 * tileSize - tileSize / 4, tileSize)), getSourceRectForStandardTileSheet(debrisSpriteSheet, 16), Color.White); + spriteBatch.Draw(debrisSpriteSheet, GlobalToLocal(viewport, new Vector2(4 * tileSize, 3 * tileSize + tileSize / 6)), getSourceRectForStandardTileSheet(debrisSpriteSheet, 16), Color.White); + spriteBatch.Draw(debrisSpriteSheet, GlobalToLocal(viewport, new Vector2(4 * tileSize + tileSize / 5, 2 * tileSize + tileSize / 3)), getSourceRectForStandardTileSheet(debrisSpriteSheet, 16), Color.White); + } + if (displayFarmer && player.ActiveObject != null && player.ActiveObject.bigCraftable && checkBigCraftableBoundariesForFrontLayer() && currentLocation.Map.GetLayer("Front").PickTile(new Location(player.getStandingX(), player.getStandingY()), viewport.Size) == null) + { + drawPlayerHeldObject(player); + } + else if (displayFarmer && player.ActiveObject != null && ((currentLocation.Map.GetLayer("Front").PickTile(new Location((int) player.position.X, (int) player.position.Y - tileSize * 3 / 5), viewport.Size) != null && !currentLocation.Map.GetLayer("Front").PickTile(new Location((int) player.position.X, (int) player.position.Y - tileSize * 3 / 5), viewport.Size).TileIndexProperties.ContainsKey("FrontAlways")) || (currentLocation.Map.GetLayer("Front").PickTile(new Location(player.GetBoundingBox().Right, (int) player.position.Y - tileSize * 3 / 5), viewport.Size) != null && !currentLocation.Map.GetLayer("Front").PickTile(new Location(player.GetBoundingBox().Right, (int) player.position.Y - tileSize * 3 / 5), viewport.Size).TileIndexProperties.ContainsKey("FrontAlways")))) + { + drawPlayerHeldObject(player); + } + if ((player.UsingTool || pickingTool) && player.CurrentTool != null && (!player.CurrentTool.Name.Equals("Seeds") || pickingTool) && currentLocation.Map.GetLayer("Front").PickTile(new Location(player.getStandingX(), (int) player.position.Y - tileSize * 3 / 5), viewport.Size) != null && currentLocation.Map.GetLayer("Front").PickTile(new Location(player.getStandingX(), player.getStandingY()), viewport.Size) == null) + { + drawTool(player); + } + if (currentLocation.Map.GetLayer("AlwaysFront") != null) + { + mapDisplayDevice.BeginScene(spriteBatch); + currentLocation.Map.GetLayer("AlwaysFront").Draw(mapDisplayDevice, viewport, Location.Origin, false, pixelZoom); + mapDisplayDevice.EndScene(); + } + if (toolHold > 400f && player.CurrentTool.UpgradeLevel >= 1 && player.canReleaseTool) + { + Color color = Color.White; + switch ((int) (toolHold / 600f) + 2) + { + case 1: + color = Tool.copperColor; + break; + case 2: + color = Tool.steelColor; + break; + case 3: + color = Tool.goldColor; + break; + case 4: + color = Tool.iridiumColor; + break; + } + spriteBatch.Draw(littleEffect, new Rectangle((int) player.getLocalPosition(viewport).X - 2, (int) player.getLocalPosition(viewport).Y - (player.CurrentTool.Name.Equals("Watering Can") ? 0 : tileSize) - 2, (int) (toolHold % 600f * 0.08f) + 4, tileSize / 8 + 4), Color.Black); + spriteBatch.Draw(littleEffect, new Rectangle((int) player.getLocalPosition(viewport).X, (int) player.getLocalPosition(viewport).Y - (player.CurrentTool.Name.Equals("Watering Can") ? 0 : tileSize), (int) (toolHold % 600f * 0.08f), tileSize / 8), color); + } + if (isDebrisWeather && currentLocation.IsOutdoors && !currentLocation.ignoreDebrisWeather && !currentLocation.Name.Equals("Desert") && viewport.X > -10) + { + foreach (WeatherDebris current6 in debrisWeather) + { + current6.draw(spriteBatch); + } + } + farmEvent?.draw(spriteBatch); + if (currentLocation.LightLevel > 0f && timeOfDay < 2000) + { + spriteBatch.Draw(fadeToBlackRect, graphics.GraphicsDevice.Viewport.Bounds, Color.Black * currentLocation.LightLevel); + } + if (screenGlow) + { + spriteBatch.Draw(fadeToBlackRect, graphics.GraphicsDevice.Viewport.Bounds, screenGlowColor * screenGlowAlpha); + } + currentLocation.drawAboveAlwaysFrontLayer(spriteBatch); + if (player.CurrentTool is FishingRod && ((player.CurrentTool as FishingRod).isTimingCast || (player.CurrentTool as FishingRod).castingChosenCountdown > 0f || (player.CurrentTool as FishingRod).fishCaught || (player.CurrentTool as FishingRod).showingTreasure)) + { + player.CurrentTool.draw(spriteBatch); + } + if (isRaining && currentLocation.IsOutdoors && !currentLocation.Name.Equals("Desert") && !(currentLocation is Summit) && (!eventUp || currentLocation.isTileOnMap(new Vector2(viewport.X / tileSize, viewport.Y / tileSize)))) + { + for (int j = 0; j < rainDrops.Length; j++) + { + spriteBatch.Draw(rainTexture, rainDrops[j].position, getSourceRectForStandardTileSheet(rainTexture, rainDrops[j].frame), Color.White); + } + } + spriteBatch.End(); + base.Draw(gameTime); + spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + if (eventUp && currentLocation.currentEvent != null) + { + foreach (NPC current7 in currentLocation.currentEvent.actors) + { + if (current7.isEmoting) + { + Vector2 localPosition = current7.getLocalPosition(viewport); + localPosition.Y -= tileSize * 2 + pixelZoom * 3; + if (current7.age == 2) + { + localPosition.Y += tileSize / 2; + } + else if (current7.gender == 1) + { + localPosition.Y += tileSize / 6; + } + spriteBatch.Draw(emoteSpriteSheet, localPosition, new Rectangle(current7.CurrentEmoteIndex * (tileSize / 4) % emoteSpriteSheet.Width, current7.CurrentEmoteIndex * (tileSize / 4) / emoteSpriteSheet.Width * (tileSize / 4), tileSize / 4, tileSize / 4), Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, current7.getStandingY() / 10000f); + } + } + } + spriteBatch.End(); + if (drawLighting) + { + spriteBatch.Begin(SpriteSortMode.Deferred, new BlendState + { + ColorBlendFunction = BlendFunction.ReverseSubtract, + ColorDestinationBlend = Blend.One, + ColorSourceBlend = Blend.SourceColor + }, SamplerState.LinearClamp, null, null); + spriteBatch.Draw(lightmap, Vector2.Zero, lightmap.Bounds, Color.White, 0f, Vector2.Zero, options.lightingQuality, SpriteEffects.None, 1f); + if (isRaining && currentLocation.isOutdoors && !(currentLocation is Desert)) + { + spriteBatch.Draw(staminaRect, graphics.GraphicsDevice.Viewport.Bounds, Color.OrangeRed * 0.45f); + } + spriteBatch.End(); + } + spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + if (drawGrid) + { + int num2 = -viewport.X % tileSize; + float num3 = -(float) viewport.Y % tileSize; + for (int k = num2; k < graphics.GraphicsDevice.Viewport.Width; k += tileSize) + { + spriteBatch.Draw(staminaRect, new Rectangle(k, (int) num3, 1, graphics.GraphicsDevice.Viewport.Height), Color.Red * 0.5f); + } + for (float num4 = num3; num4 < (float) graphics.GraphicsDevice.Viewport.Height; num4 += (float) tileSize) + { + spriteBatch.Draw(staminaRect, new Rectangle(num2, (int) num4, graphics.GraphicsDevice.Viewport.Width, 1), Color.Red * 0.5f); + } + } + if (currentBillboard != 0) + { + drawBillboard(); + } + if ((displayHUD || eventUp) && currentBillboard == 0 && gameMode == 3 && !freezeControls && !panMode) + { + GraphicsEvents.InvokeOnPreRenderHudEvent(null, EventArgs.Empty); + typeof (Game1).GetMethod("drawHUD", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(Program.gamePtr, null); + GraphicsEvents.InvokeOnPostRenderHudEvent(null, EventArgs.Empty); + //this.drawHUD(); + } + else if (activeClickableMenu == null && farmEvent == null) + { + spriteBatch.Draw(mouseCursors, new Vector2(getOldMouseX(), getOldMouseY()), getSourceRectForStandardTileSheet(mouseCursors, 0, 16, 16), Color.White, 0f, Vector2.Zero, 4f + dialogueButtonScale / 150f, SpriteEffects.None, 1f); + } + if (hudMessages.Any() && (!eventUp || isFestival())) + { + for (int l = hudMessages.Count - 1; l >= 0; l--) + { + hudMessages[l].draw(spriteBatch, l); + } + } + } + farmEvent?.draw(spriteBatch); + if (dialogueUp && !nameSelectUp && !messagePause && !(activeClickableMenu is DialogueBox)) + { + typeof (Game1).GetMethod("drawDialogueBox", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(Program.gamePtr, null); + //this.drawDialogueBox(); + } + if (progressBar) + { + spriteBatch.Draw(fadeToBlackRect, new Rectangle((graphics.GraphicsDevice.Viewport.TitleSafeArea.Width - dialogueWidth) / 2, graphics.GraphicsDevice.Viewport.TitleSafeArea.Bottom - tileSize * 2, dialogueWidth, tileSize / 2), Color.LightGray); + spriteBatch.Draw(staminaRect, new Rectangle((graphics.GraphicsDevice.Viewport.TitleSafeArea.Width - dialogueWidth) / 2, graphics.GraphicsDevice.Viewport.TitleSafeArea.Bottom - tileSize * 2, (int) (pauseAccumulator / pauseTime * dialogueWidth), tileSize / 2), Color.DimGray); + } + if (eventUp) + { + currentLocation.currentEvent?.drawAfterMap(spriteBatch); + } + if (isRaining && currentLocation.isOutdoors && !(currentLocation is Desert)) + { + spriteBatch.Draw(staminaRect, graphics.GraphicsDevice.Viewport.Bounds, Color.Blue * 0.2f); + } + if ((fadeToBlack || globalFade) && !menuUp && (!nameSelectUp || messagePause)) + { + spriteBatch.Draw(fadeToBlackRect, graphics.GraphicsDevice.Viewport.Bounds, Color.Black * ((gameMode == 0) ? (1f - fadeToBlackAlpha) : fadeToBlackAlpha)); + } + else if (flashAlpha > 0f) + { + if (options.screenFlash) + { + spriteBatch.Draw(fadeToBlackRect, graphics.GraphicsDevice.Viewport.Bounds, Color.White * Math.Min(1f, flashAlpha)); + } + flashAlpha -= 0.1f; + } + if ((messagePause || globalFade) && dialogueUp) + { + typeof (Game1).GetMethod("drawDialogueBox", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(Program.gamePtr, null); + //this.drawDialogueBox(); + } + foreach (TemporaryAnimatedSprite current8 in screenOverlayTempSprites) + { + current8.draw(spriteBatch, true); + } + if (debugMode) + { + spriteBatch.DrawString(smallFont, string.Concat(new object[] + { + panMode ? ((getOldMouseX() + viewport.X) / tileSize + "," + (getOldMouseY() + viewport.Y) / tileSize) : string.Concat("aplayer: ", player.getStandingX() / tileSize, ", ", player.getStandingY() / tileSize), + Environment.NewLine, + "debugOutput: ", + debugOutput + }), new Vector2(GraphicsDevice.Viewport.TitleSafeArea.X, GraphicsDevice.Viewport.TitleSafeArea.Y), Color.Red, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0.9999999f); + } + if (inputMode) + { + spriteBatch.DrawString(smallFont, "Input: " + debugInput, new Vector2(tileSize, tileSize * 3), Color.Purple); + } + if (showKeyHelp) + { + spriteBatch.DrawString(smallFont, keyHelpString, new Vector2(tileSize, viewport.Height - tileSize - (dialogueUp ? (tileSize * 3 + (isQuestion ? (questionChoices.Count * tileSize) : 0)) : 0) - smallFont.MeasureString(keyHelpString).Y), Color.LightGray, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0.9999999f); + } + if (activeClickableMenu != null) + { + GraphicsEvents.InvokeOnPreRenderGuiEvent(null, EventArgs.Empty); + activeClickableMenu.draw(spriteBatch); + GraphicsEvents.InvokeOnPostRenderGuiEvent(null, EventArgs.Empty); + } + else + { + farmEvent?.drawAboveEverything(spriteBatch); + } + GraphicsEvents.InvokeOnPostRenderEvent(null, EventArgs.Empty); spriteBatch.End(); - - if (!options.zoomLevel.Equals(1.0f)) + if (!ZoomLevelIsOne) { GraphicsDevice.SetRenderTarget(null); + GraphicsDevice.Clear(BgColour); spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); - spriteBatch.Draw(Screen, Vector2.Zero, Screen.Bounds, Color.White, 0.0f, Vector2.Zero, options.zoomLevel, SpriteEffects.None, 1f); + spriteBatch.Draw(Screen, Vector2.Zero, Screen.Bounds, Color.White, 0f, Vector2.Zero, options.zoomLevel, SpriteEffects.None, 1f); spriteBatch.End(); } + + #endregion + } + else + { + #region Base Draw Call + + try + { + base.Draw(gameTime); + } + catch (Exception ex) + { + Log.AsyncR("An error occured in the base draw loop: " + ex); + Console.ReadKey(); + } + + GraphicsEvents.InvokeDrawTick(); + + if (Constants.EnableDrawingIntoRenderTarget) + { + if (!options.zoomLevel.Equals(1.0f)) + { + if (Screen.RenderTargetUsage == RenderTargetUsage.DiscardContents) + { + Screen = new RenderTarget2D(graphics.GraphicsDevice, Math.Min(4096, (int) (Window.ClientBounds.Width * (1.0 / options.zoomLevel))), + Math.Min(4096, (int) (Window.ClientBounds.Height * (1.0 / options.zoomLevel))), + false, SurfaceFormat.Color, DepthFormat.Depth16, 1, RenderTargetUsage.PreserveContents); + } + GraphicsDevice.SetRenderTarget(Screen); + } + + // Not beginning the batch due to inconsistancies with the standard draw tick... + //spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + + GraphicsEvents.InvokeDrawInRenderTargetTick(); + + //spriteBatch.End(); + + //Re-draw the HUD + spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + activeClickableMenu?.draw(spriteBatch); + /* + if ((displayHUD || eventUp) && currentBillboard == 0 && gameMode == 3 && !freezeControls && !panMode) + typeof (Game1).GetMethod("drawHUD", BindingFlags.NonPublic | BindingFlags.Instance)?.Invoke(Program.gamePtr, null); + */ + spriteBatch.Draw(mouseCursors, new Vector2(getOldMouseX(), getOldMouseY()), getSourceRectForStandardTileSheet(mouseCursors, options.gamepadControls ? 44 : 0, 16, 16), Color.White, 0.0f, Vector2.Zero, pixelZoom + dialogueButtonScale / 150f, SpriteEffects.None, 1f); + + spriteBatch.End(); + + if (!options.zoomLevel.Equals(1.0f)) + { + GraphicsDevice.SetRenderTarget(null); + spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); + spriteBatch.Draw(Screen, Vector2.Zero, Screen.Bounds, Color.White, 0.0f, Vector2.Zero, options.zoomLevel, SpriteEffects.None, 1f); + spriteBatch.End(); + } + } + + #endregion } if (Debug) { spriteBatch.Begin(); - spriteBatch.DrawString(smoothFont, "FPS: " + FramesPerSecond, Vector2.Zero, Color.CornflowerBlue); - int i = 1; + int i = 0; while (DebugMessageQueue.Any()) { string s = DebugMessageQueue.Dequeue(); - spriteBatch.DrawString(smoothFont, s, new Vector2(0, i * 12), Color.CornflowerBlue); + spriteBatch.DrawString(smoothFont, s, new Vector2(0, i * 14), Color.CornflowerBlue); i++; } - GraphicsEvents.InvokeDrawDebug(null, null); + GraphicsEvents.InvokeDrawDebug(null, EventArgs.Empty); + spriteBatch.End(); } else @@ -527,6 +1339,7 @@ namespace StardewModdingAPI.Inheritance } [Obsolete("Do not use at this time.")] + // ReSharper disable once UnusedMember.Local private static int RegisterModItem(SObject modItem) { if (modItem.HasBeenRegistered) @@ -544,6 +1357,7 @@ namespace StardewModdingAPI.Inheritance } [Obsolete("Do not use at this time.")] + // ReSharper disable once UnusedMember.Local private static SObject PullModItemFromDict(int id, bool isIndex) { if (isIndex) @@ -734,12 +1548,18 @@ namespace StardewModdingAPI.Inheritance MineEvents.InvokeMineLevelChanged(PreviousMineLevel, mine.mineLevel); PreviousMineLevel = mine.mineLevel; } + + if (PreviousIsNewDay != newDay) + { + TimeEvents.InvokeOnNewDay(PreviousDayOfMonth, dayOfMonth, newDay); + PreviousIsNewDay = newDay; + } } private bool HasInventoryChanged(List items, out List changedItems) { changedItems = new List(); - IEnumerable actualItems = items.Where(n => n != null)?.ToArray(); + IEnumerable actualItems = items.Where(n => n != null).ToArray(); foreach (var item in actualItems) { if (PreviousItems != null && PreviousItems.ContainsKey(item)) @@ -763,5 +1583,40 @@ namespace StardewModdingAPI.Inheritance return changedItems.Any(); } + + /// + /// Invokes a private, non-static method in Game1 via Reflection + /// + /// The name of the method + /// Any parameters needed + /// Whatever the method normally returns. Null if void. + public static object InvokeBasePrivateInstancedMethod(string name, params object[] parameters) + { + try + { + return typeof (Game1).GetMethod(name, BindingFlags.NonPublic | BindingFlags.Instance).Invoke(Program.gamePtr, parameters); + } + catch + { + Log.AsyncR("Failed to call base method: " + name); + return null; + } + } + + /// + /// Queue's a message to be drawn in Debug mode (F3) + /// + /// + public static bool QueueDebugMessage(string message) + { + if (!Debug) + return false; + + if (DebugMessageQueue.Count > 32) + return false; + + DebugMessageQueue.Enqueue(message); + return true; + } } } \ No newline at end of file diff --git a/StardewModdingAPI/Manifest.cs b/StardewModdingAPI/Manifest.cs index 162ab399..e2526cf3 100644 --- a/StardewModdingAPI/Manifest.cs +++ b/StardewModdingAPI/Manifest.cs @@ -1,4 +1,8 @@ using System; +using System.IO; +using System.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; namespace StardewModdingAPI { @@ -50,5 +54,36 @@ namespace StardewModdingAPI EntryDll = ""; return this as T; } + + public override T LoadConfig() + { + if (File.Exists(ConfigLocation)) + { + try + { + Manifest m = JsonConvert.DeserializeObject(File.ReadAllText(ConfigLocation)); + } + catch + { + //Invalid json blob. Try to remove version? + try + { + JObject j = JObject.Parse(File.ReadAllText(ConfigLocation)); + if (!j.GetValue("Version").Contains("{")) + { + Log.AsyncC("INVALID JSON VERSION. TRYING TO REMOVE SO A NEW CAN BE AUTO-GENERATED"); + j.Remove("Version"); + File.WriteAllText(ConfigLocation, j.ToString()); + } + } + catch + { + //Idgaf speeder can go fuck himself + } + } + } + + return base.LoadConfig(); + } } } \ No newline at end of file diff --git a/StardewModdingAPI/Program.cs b/StardewModdingAPI/Program.cs index e6ba103b..fcc247e2 100644 --- a/StardewModdingAPI/Program.cs +++ b/StardewModdingAPI/Program.cs @@ -35,8 +35,8 @@ namespace StardewModdingAPI public static Texture2D DebugPixel { get; private set; } - public static bool StardewInjectorLoaded { get; private set; } - public static Mod StardewInjectorMod { get; private set; } + // ReSharper disable once PossibleNullReferenceException + public static int BuildType => (int) StardewProgramType.GetField("buildType", BindingFlags.Public | BindingFlags.Static).GetValue(null); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////