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,
};
}