using System; using static PKHeX.Core.Species; namespace PKHeX.Core; /// /// Alternate form data has an associated value. /// /// /// How long (days) the form can last before reverting to Form-0 (5 days max) /// : How long (days) the form can last before reverting to Form-0 (3 days max) /// : Topping (Strawberry, Star, etc); [0,7] /// How much damage the Pokémon has taken as Yamask-1 [0,9999]. /// How much damage the Pokémon has taken as Yamask-1 [0,9999]. /// How many times the Pokémon has used Psyshield Bash in the Agile Style [0,9999]. /// How many times the Pokémon has used Barb Barrage in the Strong Style as Qwilfish-1 [0,9999]. /// How much damage the Pokémon has taken through recoil as Basculin-2 [0,9999]. /// How many times the Pokémon has used Rage Fist [0,9999]. /// How many Bisharp that head up a group of Pawniard have been KOed [0,9999]. /// How many Gimmighoul Coins were in the player's Bag after last leveling up [0,998]. /// How many Gimmighoul Coins were used on Gimmighoul to evolve into this Pokémon. /// Flags whether or not this Pokémon was originally in its Ride Form (0/1). /// Flags whether or not this Pokémon was originally in its Ride Form (0/1). /// public interface IFormArgument { /// /// Argument for the associated /// uint FormArgument { get; set; } /// /// Amount of days the timed will remain active for. /// byte FormArgumentRemain { get; set; } /// /// Amount of days the timed has been active for. /// byte FormArgumentElapsed { get; set; } /// /// Maximum amount of days the has maintained a without reverting to its base form. /// byte FormArgumentMaximum { get; set; } } /// /// Logic for mutating an object. /// public static class FormArgumentUtil { /// /// Sets the suggested Form Argument to the . /// public static void SetSuggestedFormArgument(this PKM pk, ushort originalSpecies = 0) { if (pk is not IFormArgument) return; uint value = IsFormArgumentTypeDatePair(pk.Species, pk.Form) ? GetFormArgumentMax(pk.Species, pk.Form, pk.Context) : GetFormArgumentMinEvolution(pk.Species, originalSpecies); if (pk.Species is (int)Hoopa && pk.Format >= 8) value = 0; // SV does not set the argument for Hoopa pk.ChangeFormArgument(value); } /// /// Modifies the values for the provided to the requested . /// public static void ChangeFormArgument(this PKM pk, uint value) { if (pk is not IFormArgument f) return; f.ChangeFormArgument(pk.Species, pk.Form, pk.Context, value); } /// /// Modifies the values for the provided inputs to the requested . /// /// Form Argument object /// Entity Species /// Entity Species /// Entity current context /// Value to apply public static void ChangeFormArgument(this IFormArgument f, ushort species, byte form, EntityContext context, uint value) { if (!IsFormArgumentTypeDatePair(species, form)) { f.FormArgument = value; return; } var max = GetFormArgumentMax(species, form, context); f.FormArgumentRemain = (byte)value; if (value == max || (value == 0 && species is (int)Hoopa && form == 1 && context.Generation() >= 8)) { f.FormArgumentElapsed = f.FormArgumentMaximum = 0; return; } byte elapsed = max < value ? (byte)0 : (byte)(max - value); f.FormArgumentElapsed = elapsed; if (species == (int)Furfrou) f.FormArgumentMaximum = Math.Max(f.FormArgumentMaximum, elapsed); } /// /// Gets the maximum value the can be. /// /// Entity Species /// Entity Form /// Context to check with. public static uint GetFormArgumentMax(ushort species, byte form, EntityContext context) { int gen = context.Generation(); if (gen <= 5) return 0; return species switch { (int)Furfrou when form != 0 => 5, (int)Hoopa when form == 1 => 3, (int)Yamask when form == 1 => 9999, (int)Runerigus when form == 0 => 9999, (int)Alcremie => (uint)AlcremieDecoration.Ribbon, (int)Qwilfish when form == 1 && gen >= 8 => 9999, (int)Overqwil => 9999, // 20 (int)Stantler or (int)Wyrdeer when gen >= 8 => 9999, (int)Basculin when form == 2 => 9999, // 294 (int)Basculegion => 9999, // 294 (int)Primeape or (int)Annihilape when gen >= 8 => 9999, (int)Bisharp or (int)Kingambit when gen >= 8 => 9999, (int)Gimmighoul => 998, (int)Gholdengo => 999, (int)Koraidon or (int)Miraidon => 1, _ => 0, }; } /// /// Gets the minimum value the value can be to satisfy an evolution requirement. /// /// Current state species /// Initial species public static uint GetFormArgumentMinEvolution(ushort currentSpecies, ushort originalSpecies) => originalSpecies switch { (int)Yamask when currentSpecies == (int)Runerigus => 49u, (int)Qwilfish when currentSpecies == (int)Overqwil => 20u, (int)Stantler when currentSpecies == (int)Wyrdeer => 20u, (int)Basculin when currentSpecies == (int)Basculegion => 294u, (int)Mankey or (int)Primeape when currentSpecies == (int)Annihilape => 20u, (int)Pawniard or (int)Bisharp when currentSpecies == (int)Kingambit => 3u, (int)Gimmighoul when currentSpecies == (int)Gholdengo => 999u, _ => 0u, }; /// /// Checks if the value is stored as a days-elapsed / days-remaining pair. /// public static bool IsFormArgumentTypeDatePair(ushort species, byte form) => species switch { (int)Furfrou when form != 0 => true, (int)Hoopa when form == 1 => true, _ => false, }; }