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;