Permit pkrs strain 0 & 8 on Gen3+ context

Ruby & Sapphire had a bug that only looped when (rand) == 0 !!! instead of (rand & 7) == 0.
End result is that the pkrs giving method yields strains 0 & 8 with 30/255 & 1/255 rarity.

Gen2: z80 assembly does NOT work as intended, and has a separate bug that causes strains 9+ to never be obtainable. So close to a neat statistical separation.

Revise the GUI to disable the events on field loading, and allow for selecting Strain0 w/ days !0.
VC2->7 does not transfer pkrs; not that it matters since Gen3++ transfers can spread every strain.

Thanks @SNBeast for clarification on Gen2's assembly logic and repro!

Co-Authored-By: SNBeast <21327530+snbeast@users.noreply.github.com>
This commit is contained in:
Kurt 2023-04-19 00:11:45 -07:00
parent b08581aecf
commit 9a768dded3
4 changed files with 46 additions and 21 deletions

View file

@ -49,16 +49,23 @@ public static class Pokerus
{
if (!IsObtainable(pk))
return IsSusceptible(strain, days);
return IsStrainValid(strain, days);
if (pk.Format <= 2)
return IsStrainValid2(strain);
return IsStrainValid(strain);
}
/// <inheritdoc cref="IsStrainValid(PKM,int,int)"/>
public static bool IsStrainValid(int strain, int days) => strain switch
{
0 when days is not 0 => false,
8 => false,
_ => true,
};
/// <remarks>
/// Strains 9+ are not obtainable due to game programming error (jmp label too early).
/// </remarks>
public static bool IsStrainValid2(int strain) => strain <= 8;
/// <inheritdoc cref="IsStrainValid(PKM,int,int)"/>
/// <remarks>
/// Gen3 R/S have a 30/255 chance of giving strain 0, and a 1/255 chance of giving strain 8.
/// Transfers will retain strain 0/8 and they're still able to infect others.
/// </remarks>
public static bool IsStrainValid(int strain) => strain <= 0xF;
/// <summary>
/// Checks if the Pokérus value for Duration is possible to have on the input entity.
@ -88,7 +95,7 @@ public static class Pokerus
/// <param name="strain">Strain number</param>
/// <param name="days">Duration remaining</param>
/// <returns>True if currently infected, and infectious to others.</returns>
public static bool IsInfectuous(int strain, int days) => strain != 0 && days != 0;
public static bool IsInfectious(int strain, int days) => days != 0;
/// <summary>
/// Checks if the Pokémon can be infected with the Pokérus.

View file

@ -318,7 +318,7 @@ public abstract class PKM : ISpeciesForm, ITrainerID32, IGeneration, IShiny, ILa
}
}
public bool PKRS_Infected { get => PKRS_Strain != 0; set => PKRS_Strain = value ? Math.Max(PKRS_Strain, 1) : 0; }
public bool PKRS_Infected { get => PKRS_Days != 0; set => PKRS_Strain = value ? Math.Max(PKRS_Strain, 1) : 0; }
public bool PKRS_Cured
{

View file

@ -56,9 +56,10 @@ public partial class PKMEditor
private void LoadPKRS(PKM pk)
{
Label_PKRS.Visible = CB_PKRSStrain.Visible = CHK_Infected.Checked = Label_PKRSdays.Visible = CB_PKRSDays.Visible = pk.PKRS_Infected;
LoadClamp(CB_PKRSStrain, pk.PKRS_Strain);
CHK_Infected.Checked = Label_PKRS.Visible = Label_PKRSdays.Visible = CB_PKRSStrain.Visible = CB_PKRSDays.Visible = pk.PKRS_Infected;
CHK_Cured.Checked = pk.PKRS_Cured;
ChangePKRSstrainDropDownLists(CB_PKRSStrain.SelectedIndex, pk.PKRS_Strain, 0);
LoadClamp(CB_PKRSStrain, pk.PKRS_Strain);
LoadClamp(CB_PKRSDays, pk.PKRS_Days); // clamp to valid day values for the current strain
}

View file

@ -1043,21 +1043,32 @@ public sealed partial class PKMEditor : UserControl, IMainEditor
private void UpdatePKRSstrain(object sender, EventArgs e)
{
// Change the PKRS Days to the legal bounds.
int currentDuration = CB_PKRSDays.SelectedIndex;
CB_PKRSDays.Items.Clear();
if (!FieldsLoaded)
return;
var strain = CB_PKRSStrain.SelectedIndex;
int max = Pokerus.GetMaxDuration(strain);
// Change the PKRS Days to the legal bounds.
ChangePKRSstrainDropDownLists(-1, CB_PKRSStrain.SelectedIndex, CB_PKRSDays.SelectedIndex);
}
private void ChangePKRSstrainDropDownLists(int oldStrain, int newStrain, int currentDuration)
{
if (oldStrain == newStrain)
return;
CB_PKRSDays.Items.Clear();
int max = Pokerus.GetMaxDuration(newStrain);
for (int day = 0; day <= max; day++)
CB_PKRSDays.Items.Add(day.ToString());
// Set the days back if they're legal
CB_PKRSDays.SelectedIndex = strain == 0 ? 0 : Math.Min(max, currentDuration);
CB_PKRSDays.SelectedIndex = Math.Min(max, currentDuration);
}
private void UpdatePKRSdays(object sender, EventArgs e)
{
if (!FieldsLoaded)
return;
var days = CB_PKRSDays.SelectedIndex;
if (days != 0)
return;
@ -1072,19 +1083,22 @@ public sealed partial class PKMEditor : UserControl, IMainEditor
private void UpdatePKRSCured(object sender, EventArgs e)
{
if (!FieldsLoaded)
return;
// Cured PokeRus is toggled
if (CHK_Cured.Checked)
{
// If we're cured we have to have a strain infection.
if (CB_PKRSStrain.SelectedIndex == 0)
CB_PKRSStrain.SelectedIndex = 1;
// Has Had PokeRus
Label_PKRSdays.Visible = CB_PKRSDays.Visible = false;
CB_PKRSDays.SelectedIndex = 0;
Label_PKRS.Visible = CB_PKRSStrain.Visible = true;
CHK_Infected.Checked = true;
// If we're cured we have to have a strain infection.
if (CB_PKRSStrain.SelectedIndex == 0)
CB_PKRSStrain.SelectedIndex = 1;
}
else if (!CHK_Infected.Checked)
{
@ -1107,6 +1121,9 @@ public sealed partial class PKMEditor : UserControl, IMainEditor
private void UpdatePKRSInfected(object sender, EventArgs e)
{
if (!FieldsLoaded)
return;
if (CHK_Cured.Checked)
{
if (!CHK_Infected.Checked)