2017-07-20 11:51:05 +08:00
using Microsoft.Xna.Framework ;
using Microsoft.Xna.Framework.Graphics ;
2018-05-06 12:21:18 +08:00
using Netcode ;
2017-07-20 11:51:05 +08:00
using StardewModdingAPI ;
using StardewModdingAPI.Events ;
using StardewValley ;
using StardewValley.Characters ;
2018-05-06 12:21:18 +08:00
using StardewValley.Network ;
2017-07-20 11:51:05 +08:00
using System ;
2019-11-27 12:43:17 +08:00
using System.Linq ;
2017-07-20 11:51:05 +08:00
using System.Timers ;
namespace UIInfoSuite.UIElements
{
class ShowWhenAnimalNeedsPet : IDisposable
{
private readonly Timer _timer = new Timer ( ) ;
private float _yMovementPerDraw ;
private float _alpha ;
private readonly IModHelper _helper ;
public ShowWhenAnimalNeedsPet ( IModHelper helper )
{
_timer . Elapsed + = StartDrawingPetNeeds ;
_helper = helper ;
}
public void ToggleOption ( bool showWhenAnimalNeedsPet )
{
_timer . Stop ( ) ;
2018-12-25 12:36:39 +08:00
_helper . Events . Player . Warped - = OnWarped ;
_helper . Events . Display . RenderingHud - = OnRenderingHud_DrawAnimalHasProduct ;
2017-07-20 11:51:05 +08:00
if ( showWhenAnimalNeedsPet )
{
_timer . Start ( ) ;
2018-12-25 12:36:39 +08:00
_helper . Events . Player . Warped + = OnWarped ;
_helper . Events . Display . RenderingHud + = OnRenderingHud_DrawAnimalHasProduct ;
2017-07-20 11:51:05 +08:00
}
}
public void Dispose ( )
{
ToggleOption ( false ) ;
}
2018-12-25 12:36:39 +08:00
/// <summary>Raised before drawing the HUD (item toolbar, clock, etc) to the screen. The vanilla HUD may be hidden at this point (e.g. because a menu is open).</summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event arguments.</param>
private void OnRenderingHud_DrawAnimalHasProduct ( object sender , RenderingHudEventArgs e )
2017-07-20 11:51:05 +08:00
{
if ( ! Game1 . eventUp & &
2018-05-06 12:21:18 +08:00
Game1 . activeClickableMenu = = null & &
Game1 . currentLocation ! = null )
2017-07-20 11:51:05 +08:00
{
var animalsInCurrentLocation = GetAnimalsInCurrentLocation ( ) ;
if ( animalsInCurrentLocation ! = null )
{
2018-05-06 12:21:18 +08:00
foreach ( var animal in animalsInCurrentLocation . Pairs )
2017-07-20 11:51:05 +08:00
{
if ( ! animal . Value . IsEmoting & &
2018-05-06 12:21:18 +08:00
animal . Value . currentProduce . Value ! = 430 & &
animal . Value . currentProduce . Value > 0 & &
animal . Value . age . Value > = animal . Value . ageWhenMature . Value )
2017-07-20 11:51:05 +08:00
{
Vector2 positionAboveAnimal = GetPetPositionAboveAnimal ( animal . Value ) ;
2018-05-06 12:21:18 +08:00
positionAboveAnimal . Y + = ( float ) ( Math . Sin ( Game1 . currentGameTime . TotalGameTime . TotalMilliseconds / 300.0 + ( double ) animal . Value . Name . GetHashCode ( ) ) * 5.0 ) ;
2017-07-20 11:51:05 +08:00
Game1 . spriteBatch . Draw (
Game1 . emoteSpriteSheet ,
new Vector2 ( positionAboveAnimal . X + 14f , positionAboveAnimal . Y ) ,
new Rectangle ( 3 * ( Game1 . tileSize / 4 ) % Game1 . emoteSpriteSheet . Width , 3 * ( Game1 . tileSize / 4 ) / Game1 . emoteSpriteSheet . Width * ( Game1 . tileSize / 4 ) , Game1 . tileSize / 4 , Game1 . tileSize / 4 ) ,
Color . White * 0.9f ,
0.0f ,
Vector2 . Zero ,
4f ,
SpriteEffects . None ,
1f ) ;
2018-05-06 12:21:18 +08:00
Rectangle sourceRectangle = GameLocation . getSourceRectForObject ( animal . Value . currentProduce . Value ) ;
2017-07-20 11:51:05 +08:00
Game1 . spriteBatch . Draw (
Game1 . objectSpriteSheet ,
new Vector2 ( positionAboveAnimal . X + 28f , positionAboveAnimal . Y + 8f ) ,
sourceRectangle ,
Color . White * 0.9f ,
0.0f ,
Vector2 . Zero ,
2.2f ,
SpriteEffects . None ,
1f ) ;
}
}
}
}
}
2018-12-25 12:36:39 +08:00
/// <summary>Raised after a player warps to a new location.</summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event arguments.</param>
private void OnWarped ( object sender , WarpedEventArgs e )
2017-07-20 11:51:05 +08:00
{
2018-12-25 12:36:39 +08:00
if ( e . IsLocalPlayer )
2017-07-20 11:51:05 +08:00
{
2018-12-25 12:36:39 +08:00
if ( e . NewLocation is AnimalHouse | | e . NewLocation is Farm )
{
_timer . Interval = 1000 ;
_timer . Start ( ) ;
}
else
{
_timer . Stop ( ) ;
StopDrawingPetNeeds ( ) ;
}
2017-07-20 11:51:05 +08:00
}
}
2018-12-25 12:36:39 +08:00
/// <summary>Raised before drawing the HUD (item toolbar, clock, etc) to the screen. The vanilla HUD may be hidden at this point (e.g. because a menu is open).</summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event arguments.</param>
private void OnRenderingHud_DrawNeedsPetTooltip ( object sender , RenderingHudEventArgs e )
2017-07-20 11:51:05 +08:00
{
2018-12-25 12:36:39 +08:00
if ( ! Game1 . eventUp & & Game1 . activeClickableMenu = = null )
2017-07-20 11:51:05 +08:00
{
DrawIconForFarmAnimals ( ) ;
DrawIconForPets ( ) ;
}
}
private void StartDrawingPetNeeds ( object sender , ElapsedEventArgs e )
{
2017-07-21 11:28:02 +08:00
_timer . Stop ( ) ;
2018-12-25 12:36:39 +08:00
_helper . Events . Display . RenderingHud + = OnRenderingHud_DrawNeedsPetTooltip ;
_helper . Events . GameLoop . UpdateTicked + = UpdateTicked ;
2017-07-20 11:51:05 +08:00
_yMovementPerDraw = - 3f ;
_alpha = 1f ;
}
private void StopDrawingPetNeeds ( )
{
2018-12-25 12:36:39 +08:00
_helper . Events . Display . RenderingHud - = OnRenderingHud_DrawNeedsPetTooltip ;
_helper . Events . GameLoop . UpdateTicked - = UpdateTicked ;
2017-07-20 11:51:05 +08:00
}
2018-12-25 12:36:39 +08:00
/// <summary>Raised after the game state is updated (≈60 times per second).</summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event arguments.</param>
private void UpdateTicked ( object sender , UpdateTickedEventArgs e )
2017-07-20 11:51:05 +08:00
{
2018-12-25 12:36:39 +08:00
// update pet draw
if ( e . IsMultipleOf ( 2 ) )
2017-07-20 11:51:05 +08:00
{
2018-12-25 12:36:39 +08:00
_yMovementPerDraw + = 0.3f ;
_alpha - = 0.014f ;
if ( _alpha < 0.1f )
{
StopDrawingPetNeeds ( ) ;
_timer . Start ( ) ;
}
2017-07-20 11:51:05 +08:00
}
}
private void DrawIconForFarmAnimals ( )
{
var animalsInCurrentLocation = GetAnimalsInCurrentLocation ( ) ;
if ( animalsInCurrentLocation ! = null )
{
2018-05-06 12:21:18 +08:00
foreach ( var animal in animalsInCurrentLocation . Pairs )
2017-07-20 11:51:05 +08:00
{
if ( ! animal . Value . IsEmoting & &
2018-05-06 12:21:18 +08:00
! animal . Value . wasPet . Value )
2017-07-20 11:51:05 +08:00
{
Vector2 positionAboveAnimal = GetPetPositionAboveAnimal ( animal . Value ) ;
2018-05-06 12:21:18 +08:00
String animalType = animal . Value . type . Value . ToLower ( ) ;
2017-07-20 11:51:05 +08:00
if ( animalType . Contains ( "cow" ) | |
animalType . Contains ( "sheep" ) | |
animalType . Contains ( "goat" ) | |
animalType . Contains ( "pig" ) )
{
positionAboveAnimal . X + = 50f ;
positionAboveAnimal . Y + = 50f ;
}
Game1 . spriteBatch . Draw (
Game1 . mouseCursors ,
new Vector2 ( positionAboveAnimal . X , positionAboveAnimal . Y + _yMovementPerDraw ) ,
new Rectangle ( 32 , 0 , 16 , 16 ) ,
Color . White * _alpha ,
0.0f ,
Vector2 . Zero ,
4f ,
SpriteEffects . None ,
1f ) ;
}
}
}
}
private void DrawIconForPets ( )
{
foreach ( var character in Game1 . currentLocation . characters )
{
2019-11-27 12:43:17 +08:00
if ( character is Pet pet & &
! pet . lastPetDay . Values . Any ( day = > day = = Game1 . Date . TotalDays ) )
2017-07-20 11:51:05 +08:00
{
Vector2 positionAboveAnimal = GetPetPositionAboveAnimal ( character ) ;
2017-07-21 11:28:02 +08:00
positionAboveAnimal . X + = 50f ;
positionAboveAnimal . Y - = 20f ;
2017-07-20 11:51:05 +08:00
Game1 . spriteBatch . Draw (
Game1 . mouseCursors ,
new Vector2 ( positionAboveAnimal . X , positionAboveAnimal . Y + _yMovementPerDraw ) ,
new Rectangle ( 32 , 0 , 16 , 16 ) ,
Color . White * _alpha ,
0.0f ,
Vector2 . Zero ,
4f ,
SpriteEffects . None ,
1f ) ;
}
}
}
private Vector2 GetPetPositionAboveAnimal ( Character animal )
{
2020-02-16 21:20:00 +08:00
if ( Constants . TargetPlatform = = GamePlatform . Android )
{
return new Vector2 ( Game1 . viewport . Width < = Game1 . currentLocation . map . DisplayWidth ? ( animal . position . X - Game1 . viewport . X + 16 ) * Game1 . options . zoomLevel : ( animal . position . X + ( ( Game1 . viewport . Width - Game1 . currentLocation . map . DisplayWidth ) / 2 + 18 ) ) * Game1 . options . zoomLevel ,
Game1 . viewport . Height < = Game1 . currentLocation . map . DisplayHeight ? ( animal . position . Y - Game1 . viewport . Y - 34 ) * Game1 . options . zoomLevel : ( animal . position . Y + ( ( Game1 . viewport . Height - Game1 . currentLocation . map . DisplayHeight ) / 2 - 50 ) ) * Game1 . options . zoomLevel ) ;
}
2017-07-21 11:28:02 +08:00
return new Vector2 ( Game1 . viewport . Width < = Game1 . currentLocation . map . DisplayWidth ? animal . position . X - Game1 . viewport . X + 16 : animal . position . X + ( ( Game1 . viewport . Width - Game1 . currentLocation . map . DisplayWidth ) / 2 + 18 ) ,
Game1 . viewport . Height < = Game1 . currentLocation . map . DisplayHeight ? animal . position . Y - Game1 . viewport . Y - 34 : animal . position . Y + ( ( Game1 . viewport . Height - Game1 . currentLocation . map . DisplayHeight ) / 2 - 50 ) ) ;
2017-07-20 11:51:05 +08:00
}
2018-05-06 12:21:18 +08:00
private NetLongDictionary < FarmAnimal , NetRef < FarmAnimal > > GetAnimalsInCurrentLocation ( )
2017-07-20 11:51:05 +08:00
{
2018-05-06 12:21:18 +08:00
NetLongDictionary < FarmAnimal , NetRef < FarmAnimal > > animals = null ;
2017-07-20 11:51:05 +08:00
if ( Game1 . currentLocation is AnimalHouse )
{
animals = ( Game1 . currentLocation as AnimalHouse ) . animals ;
}
else if ( Game1 . currentLocation is Farm )
{
animals = ( Game1 . currentLocation as Farm ) . animals ;
}
return animals ;
}
}
}