From 9a768dded3350e4f4c798e42f4d1a2f1cfd82dd0 Mon Sep 17 00:00:00 2001 From: Kurt Date: Wed, 19 Apr 2023 00:11:45 -0700 Subject: [PATCH] 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> --- PKHeX.Core/Editing/Pokerus.cs | 23 ++++++++---- PKHeX.Core/PKM/PKM.cs | 2 +- .../Controls/PKM Editor/LoadSave.cs | 5 ++- .../Controls/PKM Editor/PKMEditor.cs | 37 ++++++++++++++----- 4 files changed, 46 insertions(+), 21 deletions(-) diff --git a/PKHeX.Core/Editing/Pokerus.cs b/PKHeX.Core/Editing/Pokerus.cs index fea80b73a..7aff49a57 100644 --- a/PKHeX.Core/Editing/Pokerus.cs +++ b/PKHeX.Core/Editing/Pokerus.cs @@ -49,16 +49,23 @@ public static bool IsStrainValid(PKM pk, int strain, int days) { if (!IsObtainable(pk)) return IsSusceptible(strain, days); - return IsStrainValid(strain, days); + if (pk.Format <= 2) + return IsStrainValid2(strain); + return IsStrainValid(strain); } /// - public static bool IsStrainValid(int strain, int days) => strain switch - { - 0 when days is not 0 => false, - 8 => false, - _ => true, - }; + /// + /// Strains 9+ are not obtainable due to game programming error (jmp label too early). + /// + public static bool IsStrainValid2(int strain) => strain <= 8; + + /// + /// + /// 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. + /// + public static bool IsStrainValid(int strain) => strain <= 0xF; /// /// Checks if the Pokérus value for Duration is possible to have on the input entity. @@ -88,7 +95,7 @@ public static bool IsDurationValid(int strain, int days, out int max) /// Strain number /// Duration remaining /// True if currently infected, and infectious to others. - public static bool IsInfectuous(int strain, int days) => strain != 0 && days != 0; + public static bool IsInfectious(int strain, int days) => days != 0; /// /// Checks if the Pokémon can be infected with the Pokérus. diff --git a/PKHeX.Core/PKM/PKM.cs b/PKHeX.Core/PKM/PKM.cs index 376e8bf16..fed0967b5 100644 --- a/PKHeX.Core/PKM/PKM.cs +++ b/PKHeX.Core/PKM/PKM.cs @@ -318,7 +318,7 @@ public int Generation } } - 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 { diff --git a/PKHeX.WinForms/Controls/PKM Editor/LoadSave.cs b/PKHeX.WinForms/Controls/PKM Editor/LoadSave.cs index aed3e31cb..9948abf78 100644 --- a/PKHeX.WinForms/Controls/PKM Editor/LoadSave.cs +++ b/PKHeX.WinForms/Controls/PKM Editor/LoadSave.cs @@ -56,9 +56,10 @@ private void SaveOT(PKM pk) 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 } diff --git a/PKHeX.WinForms/Controls/PKM Editor/PKMEditor.cs b/PKHeX.WinForms/Controls/PKM Editor/PKMEditor.cs index 49048c7d9..8beb62e66 100644 --- a/PKHeX.WinForms/Controls/PKM Editor/PKMEditor.cs +++ b/PKHeX.WinForms/Controls/PKM Editor/PKMEditor.cs @@ -1043,21 +1043,32 @@ private void RefreshFormArguments() 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 @@ private void UpdatePKRSdays(object sender, EventArgs e) 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 @@ private void UpdatePKRSCured(object sender, EventArgs e) private void UpdatePKRSInfected(object sender, EventArgs e) { + if (!FieldsLoaded) + return; + if (CHK_Cured.Checked) { if (!CHK_Infected.Checked)