diff --git a/PKHeX.Core/Legality/Encounters/EncounterSlot/GO/EncounterSlotGO.cs b/PKHeX.Core/Legality/Encounters/EncounterSlot/GO/EncounterSlotGO.cs index 129c475b0..e37ecbc16 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterSlot/GO/EncounterSlotGO.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterSlot/GO/EncounterSlotGO.cs @@ -5,7 +5,7 @@ namespace PKHeX.Core /// /// Contains details about an encounter that can be found in . /// - public abstract record EncounterSlotGO : EncounterSlot, IPogoSlot + public abstract record EncounterSlotGO : EncounterSlot, IPogoSlot, IFixedBall { /// public int Start { get; } @@ -24,6 +24,8 @@ public abstract record EncounterSlotGO : EncounterSlot, IPogoSlot public override bool IsShiny => Shiny.IsShiny(); + public Ball FixedBall => Type.GetValidBall(); + protected EncounterSlotGO(EncounterArea area, int species, int form, int start, int end, Shiny shiny, Gender gender, PogoType type) : base(area, species, form, type.GetMinLevel(), EncountersGO.MAX_LEVEL) { Start = start; diff --git a/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic.cs b/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic.cs index 1fb4af2f4..87b49a22e 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic.cs @@ -9,7 +9,7 @@ namespace PKHeX.Core /// /// Static Encounters are fixed position encounters with properties that are not subject to Wild Encounter conditions. /// - public abstract record EncounterStatic : IEncounterable, IMoveset, ILocation, IEncounterMatch + public abstract record EncounterStatic : IEncounterable, IMoveset, ILocation, IEncounterMatch, IFixedBall { public int Species { get; init; } public int Form { get; init; } @@ -28,6 +28,8 @@ public abstract record EncounterStatic : IEncounterable, IMoveset, ILocation, IE public bool Gift { get; init; } public int Ball { get; init; } = 4; // Only checked when is Gift + public Ball FixedBall => Gift ? (Ball)Ball : Core.Ball.None; + public IReadOnlyList Moves { get; init; } = Array.Empty(); public IReadOnlyList IVs { get; init; } = Array.Empty(); public int FlawlessIVCount { get; init; } diff --git a/PKHeX.Core/Legality/Encounters/EncounterTrade/EncounterTrade.cs b/PKHeX.Core/Legality/Encounters/EncounterTrade/EncounterTrade.cs index 3d8ff54dd..c35b6e762 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterTrade/EncounterTrade.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterTrade/EncounterTrade.cs @@ -10,7 +10,7 @@ namespace PKHeX.Core /// /// Trade data is fixed level in all cases except for the first few generations of games. /// - public abstract record EncounterTrade : IEncounterable, IMoveset, ILocation, IEncounterMatch + public abstract record EncounterTrade : IEncounterable, IMoveset, ILocation, IEncounterMatch, IFixedBall { public int Species { get; init; } public int Form { get; init; } @@ -29,6 +29,8 @@ public abstract record EncounterTrade : IEncounterable, IMoveset, ILocation, IEn public Shiny Shiny { get; init; } = Shiny.Never; public int Ball { get; init; } = 4; + public Ball FixedBall => (Ball)Ball; + public int TID { get; init; } public int SID { get; init; } public int OTGender { get; init; } = -1; diff --git a/PKHeX.Core/Legality/Structures/IFixedBall.cs b/PKHeX.Core/Legality/Structures/IFixedBall.cs new file mode 100644 index 000000000..ac6c0fea4 --- /dev/null +++ b/PKHeX.Core/Legality/Structures/IFixedBall.cs @@ -0,0 +1,7 @@ +namespace PKHeX.Core +{ + public interface IFixedBall + { + Ball FixedBall { get; } + } +} diff --git a/PKHeX.Core/MysteryGifts/MysteryGift.cs b/PKHeX.Core/MysteryGifts/MysteryGift.cs index d48a233d3..9dd00cf3e 100644 --- a/PKHeX.Core/MysteryGifts/MysteryGift.cs +++ b/PKHeX.Core/MysteryGifts/MysteryGift.cs @@ -7,7 +7,7 @@ namespace PKHeX.Core /// /// Mystery Gift Template File /// - public abstract class MysteryGift : IEncounterable, IMoveset, IRelearn, ILocation + public abstract class MysteryGift : IEncounterable, IMoveset, IRelearn, ILocation, IFixedBall { /// /// Determines whether or not the given length of bytes is valid for a mystery gift. @@ -146,6 +146,8 @@ public virtual GameVersion Version public virtual bool EggEncounter => IsEgg; public abstract int EggLocation { get; set; } + public Ball FixedBall => (Ball)Ball; + public int TrainerID7 => (int)((uint)(TID | (SID << 16)) % 1000000); public int TrainerSID7 => (int)((uint)(TID | (SID << 16)) / 1000000); diff --git a/PKHeX.Drawing/ImageUtil.cs b/PKHeX.Drawing/ImageUtil.cs index 88005778b..16a42de66 100644 --- a/PKHeX.Drawing/ImageUtil.cs +++ b/PKHeX.Drawing/ImageUtil.cs @@ -50,6 +50,19 @@ public static Bitmap ChangeAllColorTo(Image img, Color c) return bmp; } + public static Bitmap ChangeTransparentTo(Image img, Color c) + { + var bmp = (Bitmap)img.Clone(); + GetBitmapData(bmp, out BitmapData bmpData, out IntPtr ptr, out byte[] data); + + Marshal.Copy(ptr, data, 0, data.Length); + SetAllTransparencyTo(data, c); + Marshal.Copy(data, 0, ptr, data.Length); + bmp.UnlockBits(bmpData); + + return bmp; + } + public static Bitmap ToGrayscale(Image img) { var bmp = (Bitmap)img.Clone(); @@ -117,6 +130,22 @@ private static void SetAllTransparencyTo(byte[] data, double trans) data[i + 3] = (byte)(data[i + 3] * trans); } + public static void SetAllTransparencyTo(byte[] data, Color c) + { + byte R = c.R; + byte G = c.G; + byte B = c.B; + for (int i = 0; i < data.Length; i += 4) + { + if (data[i + 3] != 0) + continue; + data[i + 0] = B; + data[i + 1] = G; + data[i + 2] = R; + data[i + 3] = 0x3F; + } + } + public static void ChangeAllColorTo(byte[] data, Color c) { byte R = c.R; diff --git a/PKHeX.Drawing/Sprites/SpriteBuilder.cs b/PKHeX.Drawing/Sprites/SpriteBuilder.cs index f234bebbe..fc159281e 100644 --- a/PKHeX.Drawing/Sprites/SpriteBuilder.cs +++ b/PKHeX.Drawing/Sprites/SpriteBuilder.cs @@ -7,6 +7,8 @@ namespace PKHeX.Drawing public abstract class SpriteBuilder : ISpriteBuilder { public static bool ShowEggSpriteAsItem { get; set; } = true; + public static bool EncounterColorBackground { get; set; } = true; + public static bool EncounterShowFixedBall { get; set; } = true; /// Width of the generated Sprite image. public abstract int Width { get; } diff --git a/PKHeX.Drawing/Sprites/SpriteUtil.cs b/PKHeX.Drawing/Sprites/SpriteUtil.cs index 5b5212d17..001f39e81 100644 --- a/PKHeX.Drawing/Sprites/SpriteUtil.cs +++ b/PKHeX.Drawing/Sprites/SpriteUtil.cs @@ -68,6 +68,11 @@ private static Image GetSprite(MysteryGift gift) return Spriter.None; var img = GetBaseImage(gift); + if (SpriteBuilder.EncounterColorBackground) + { + var color = Color.FromArgb(gift.GetType().Name.GetHashCode() * 0x43FD43FD); + img = ImageUtil.ChangeTransparentTo(img, color); + } if (gift.GiftUsed) img = ImageUtil.ChangeOpacity(img, 0.3); return img; @@ -81,6 +86,11 @@ private static Image GetBaseImage(MysteryGift gift) { var gender = Math.Max(0, gift.Gender); var img = GetSprite(gift.Species, gift.Form, gender, 0, gift.HeldItem, gift.IsEgg, gift.IsShiny, gift.Generation); + if (SpriteBuilder.EncounterShowFixedBall && gift is IFixedBall { FixedBall: not Ball.None } b) + { + var ballSprite = GetBallSprite((int)b.FixedBall); + img = ImageUtil.LayerImage(img, ballSprite, 0, img.Height - ballSprite.Height); + } if (gift is IGigantamax {CanGigantamax: true}) { var gm = Resources.dyna; @@ -224,6 +234,16 @@ public static Image Sprite(this IEncounterTemplate enc) return g.Sprite(); var gender = GetDisplayGender(enc); var img = GetSprite(enc.Species, enc.Form, gender, 0, 0, enc.EggEncounter, enc.IsShiny, enc.Generation); + if (SpriteBuilder.EncounterColorBackground) + { + var color = Color.FromArgb(enc.GetType().Name.GetHashCode() * 0x43FD43FD); + img = ImageUtil.ChangeTransparentTo(img, color); + } + if (SpriteBuilder.EncounterShowFixedBall && enc is IFixedBall {FixedBall: not Ball.None} b) + { + var ballSprite = GetBallSprite((int)b.FixedBall); + img = ImageUtil.LayerImage(img, ballSprite, 0, img.Height - ballSprite.Height); + } if (enc is IGigantamax {CanGigantamax: true}) { var gm = Resources.dyna;