mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-10 06:34:19 +00:00
Add special generator for Gen3 unown
Removes incorrect slots ( see 2bf963009f
)
Allow Unown of any form through (unspecified in Possible generator)
Adds SlotRange get method for Gen3/4 methods.
This commit is contained in:
parent
ba0c4c90d2
commit
9352301b65
8 changed files with 340 additions and 18 deletions
|
@ -368,7 +368,7 @@ public static class EncounterMovesetGenerator
|
|||
return true;
|
||||
if (FormInfo.IsFormChangeable(enc.Species, enc.Form, evo.Form, enc.Context, current))
|
||||
return true;
|
||||
if (enc is IEncounterFormRandom { IsRandomUnspecificForm: true })
|
||||
if (enc is IEncounterFormRandom { IsRandomUnspecificForm: true } or { Species: (ushort)Species.Unown })
|
||||
return true;
|
||||
if (enc is EncounterStatic7 {IsTotem: true} && evo.Form == 0 && current.Generation() > 7) // totems get form wiped
|
||||
return true;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using static PKHeX.Core.PIDType;
|
||||
using static PKHeX.Core.SlotType3;
|
||||
|
||||
|
@ -76,27 +77,90 @@ public record EncounterSlot3(EncounterArea3 Parent, ushort Species, byte Form, b
|
|||
|
||||
if (Species == (int)Core.Species.Unown)
|
||||
{
|
||||
do
|
||||
{
|
||||
var seed = PIDGenerator.SetRandomWildPID4(pk, nature, ability, gender, Method_1_Unown);
|
||||
var lead = MethodH.GetSeed(this, seed, lvl, false, 2, 3);
|
||||
if (pk.Form != Form && lead.IsValid())
|
||||
return;
|
||||
ability ^= 1; // some nature-forms cannot have a certain PID-ability set, so just flip it as Unown doesn't have dual abilities.
|
||||
} while (ctr++ < 10_000);
|
||||
if (criteria.IsSpecifiedIVs() && SetUnownFromIVs(pk, criteria))
|
||||
return;
|
||||
|
||||
// Generate a random Unown with the correct form and desired nature.
|
||||
SetUnownRandom(pk, criteria);
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
do
|
||||
{
|
||||
do
|
||||
var seed = PIDGenerator.SetRandomWildPID4(pk, nature, ability, gender, Method_1);
|
||||
var result = MethodH.GetSeed(this, seed, lvl, pk.E, pk.Gender, 3);
|
||||
if (result.IsValid())
|
||||
return;
|
||||
} while (ctr++ < 10_000);
|
||||
}
|
||||
|
||||
private void SetUnownRandom(PK3 pk, EncounterCriteria criteria)
|
||||
{
|
||||
//bool checkForm = forms.Contains(criteria.Form); // not a property :(
|
||||
var (min, max) = SlotMethodH.GetRangeGrass(SlotNumber);
|
||||
var seed = Util.Rand32() & 0x7FFF_FFFF;
|
||||
// Can't game the seed with % 100 increments as Unown's form calculation is based on the PID.
|
||||
|
||||
while (true)
|
||||
{
|
||||
var esv = LCRNG.Next16(ref seed) % 100;
|
||||
if (esv < min || esv > max)
|
||||
continue;
|
||||
// Skip the level roll, always results in the same level value.
|
||||
var rand = LCRNG.Next2(seed);
|
||||
if (criteria.Nature != Nature.Random && (rand >> 16) % 25 != (byte)criteria.Nature)
|
||||
continue;
|
||||
|
||||
while (true)
|
||||
{
|
||||
var seed = PIDGenerator.SetRandomWildPID4(pk, nature, ability, gender, Method_1);
|
||||
var result = MethodH.GetSeed(this, seed, lvl, pk.E, pk.Gender, 3);
|
||||
if (result.IsValid())
|
||||
return;
|
||||
} while (ctr++ < 10_000);
|
||||
var a = LCRNG.Next16(ref rand);
|
||||
var b = LCRNG.Next16(ref rand);
|
||||
var pid = a << 16 | b;
|
||||
var form = EntityPID.GetUnownForm3(pid);
|
||||
if (form != Form)
|
||||
continue;
|
||||
|
||||
pk.PID = pid;
|
||||
var iv1 = LCRNG.Next16(ref rand);
|
||||
var iv2 = LCRNG.Next16(ref rand);
|
||||
pk.IV32 = ((iv2 & 0x7FFF) << 15) | (iv1 & 0x7FFF);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool SetUnownFromIVs(PK3 pk, EncounterCriteria criteria)
|
||||
{
|
||||
Span<uint> seeds = stackalloc uint[LCRNG.MaxCountSeedsIV];
|
||||
var count = LCRNGReversal.GetSeedsIVs(seeds, (byte)criteria.IV_HP, (byte)criteria.IV_ATK, (byte)criteria.IV_DEF, (byte)criteria.IV_SPA, (byte)criteria.IV_SPD, (byte)criteria.IV_SPE);
|
||||
seeds = seeds[..count];
|
||||
foreach (ref var seed in seeds)
|
||||
{
|
||||
seed = LCRNG.Prev2(seed);
|
||||
var s = seed;
|
||||
|
||||
var a = LCRNG.Next16(ref s);
|
||||
var b = LCRNG.Next16(ref s);
|
||||
var pid = a << 16 | b;
|
||||
if (criteria.Nature != Nature.Random && (Nature)(pid % 25) != criteria.Nature)
|
||||
continue;
|
||||
var form = EntityPID.GetUnownForm3(pid);
|
||||
if (form != Form)
|
||||
continue;
|
||||
var lead = MethodH.GetSeed(this, seed, this, false, 2, 3);
|
||||
if (!lead.IsValid()) // Verifies the slot and nature loop; if it passes, apply the details.
|
||||
continue;
|
||||
|
||||
pk.PID = pid;
|
||||
var iv1 = LCRNG.Next16(ref s);
|
||||
var iv2 = LCRNG.Next16(ref s);
|
||||
pk.IV32 = ((iv2 & 0x7FFF) << 15) | (iv1 & 0x7FFF);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected virtual void SetEncounterMoves(PKM pk) => EncounterUtil.SetEncounterMoves(pk, Version, LevelMin);
|
||||
#endregion
|
||||
|
||||
|
|
|
@ -26,6 +26,23 @@ public static class SlotMethodH
|
|||
_ => Invalid,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the range that a given slot number is allowed to roll for a specific <see cref="SlotType3"/>.
|
||||
/// </summary>
|
||||
public static (byte Min, byte Max) GetRange(SlotType3 type, byte slotNumber) => type switch
|
||||
{
|
||||
Grass => GetRangeGrass(slotNumber),
|
||||
Surf => GetRangeSurf(slotNumber),
|
||||
Old_Rod => GetRangeOldRod(slotNumber),
|
||||
Good_Rod => GetRangeGoodRod(slotNumber),
|
||||
Super_Rod => GetRangeSuperRod(slotNumber),
|
||||
Rock_Smash => GetRangeSurf(slotNumber),
|
||||
|
||||
SwarmFish50 => (0, 49),
|
||||
SwarmGrass50 => (0, 49),
|
||||
_ => (Invalid, Invalid),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the encounter slot index based on the roll for a Gen3 Wild encounter.
|
||||
/// </summary>
|
||||
|
@ -91,10 +108,77 @@ public static class SlotMethodH
|
|||
public static byte GetSuperRod(uint roll) => roll switch
|
||||
{
|
||||
< 40 => 0, // 00,39 (40%)
|
||||
< 80 => 1, // 40,69 (40%)
|
||||
< 95 => 2, // 70,94 (15%)
|
||||
< 80 => 1, // 40,69 (30%)
|
||||
< 95 => 2, // 70,94 (25%)
|
||||
< 99 => 3, // 95,98 ( 4%)
|
||||
99 => 4, // 99 ( 1%)
|
||||
_ => Invalid,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the range a given slot number is allowed to roll in for a <see cref="Grass"/> encounter.
|
||||
/// </summary>
|
||||
public static (byte Min, byte Max) GetRangeGrass(byte slotNumber) => slotNumber switch
|
||||
{
|
||||
0 => (00, 19), // (20%)
|
||||
1 => (20, 39), // (20%)
|
||||
2 => (40, 49), // (10%)
|
||||
3 => (50, 59), // (10%)
|
||||
4 => (60, 69), // (10%)
|
||||
5 => (70, 79), // (10%)
|
||||
6 => (80, 84), // ( 5%)
|
||||
7 => (85, 89), // ( 5%)
|
||||
8 => (90, 93), // ( 4%)
|
||||
9 => (94, 97), // ( 4%)
|
||||
10=> (98, 98), // ( 1%)
|
||||
11=> (99, 99), // ( 1%)
|
||||
_ => (Invalid, Invalid),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the range a given slot number is allowed to roll in for a <see cref="Surf"/> encounter.
|
||||
/// </summary>
|
||||
public static (byte Min, byte Max) GetRangeSurf(byte slotNumber) => slotNumber switch
|
||||
{
|
||||
0 => (00, 59), // (60%)
|
||||
1 => (60, 89), // (30%)
|
||||
2 => (90, 94), // ( 5%)
|
||||
3 => (95, 98), // ( 4%)
|
||||
4 => (99, 99), // ( 1%)
|
||||
_ => (Invalid, Invalid),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the range a given slot number is allowed to roll in for a <see cref="Old_Rod"/> encounter.
|
||||
/// </summary>
|
||||
public static (byte Min, byte Max) GetRangeOldRod(byte slotNumber) => slotNumber switch
|
||||
{
|
||||
0 => (00, 69), // (70%)
|
||||
1 => (70, 99), // (30%)
|
||||
_ => (Invalid, Invalid),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the range a given slot number is allowed to roll in for a <see cref="Good_Rod"/> encounter.
|
||||
/// </summary>
|
||||
public static (byte Min, byte Max) GetRangeGoodRod(byte slotNumber) => slotNumber switch
|
||||
{
|
||||
0 => (00, 59), // (60%)
|
||||
1 => (60, 79), // (20%)
|
||||
2 => (80, 99), // (20%)
|
||||
_ => (Invalid, Invalid),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the range a given slot number is allowed to roll in for a <see cref="Super_Rod"/> encounter.
|
||||
/// </summary>
|
||||
public static (byte Min, byte Max) GetRangeSuperRod(byte slotNumber) => slotNumber switch
|
||||
{
|
||||
0 => (00, 39), // (40%)
|
||||
1 => (40, 69), // (30%)
|
||||
2 => (70, 94), // (25%)
|
||||
3 => (95, 98), // ( 4%)
|
||||
4 => (99, 99), // ( 1%)
|
||||
_ => (Invalid, Invalid),
|
||||
};
|
||||
}
|
||||
|
|
52
PKHeX.Core/Legality/RNG/ClassicEra/Gen3/TanobyRuins3.cs
Normal file
52
PKHeX.Core/Legality/RNG/ClassicEra/Gen3/TanobyRuins3.cs
Normal file
|
@ -0,0 +1,52 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
public static class TanobyRuins3
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks if the form is available in the location.
|
||||
/// </summary>
|
||||
public static bool IsFormInLocation(byte location, byte form) => IsLocationInRuins(location) && GetForms(location).Contains(form);
|
||||
|
||||
/// <summary>
|
||||
/// If you're calling this method and know which template you are matched to, just check the form from the template directly.
|
||||
/// </summary>
|
||||
public static bool IsFormValid(byte location, byte form, byte slot)
|
||||
{
|
||||
if (!IsLocationInRuins(location))
|
||||
return false;
|
||||
|
||||
var forms = GetForms(location);
|
||||
if (form > forms.Length)
|
||||
return false;
|
||||
return forms[slot] == form;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the form for the location and slot.
|
||||
/// </summary>
|
||||
public static byte GetForm(byte location, byte slot)
|
||||
{
|
||||
if (!IsLocationInRuins(location))
|
||||
return 0;
|
||||
var forms = GetForms(location);
|
||||
if (slot > forms.Length)
|
||||
return 0;
|
||||
return forms[slot];
|
||||
}
|
||||
|
||||
private static bool IsLocationInRuins(byte location) => location is >= 188 and <= 194;
|
||||
|
||||
public static ReadOnlySpan<byte> GetForms(byte location) => location switch
|
||||
{
|
||||
188 => [00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 27], // 188 = Monean Chamber
|
||||
189 => [02, 02, 02, 03, 03, 03, 07, 07, 07, 20, 20, 14], // 189 = Liptoo Chamber
|
||||
190 => [13, 13, 13, 13, 18, 18, 18, 18, 08, 08, 04, 04], // 190 = Weepth Chamber
|
||||
191 => [15, 15, 11, 11, 09, 09, 17, 17, 17, 16, 16, 16], // 191 = Dilford Chamber
|
||||
192 => [24, 24, 19, 19, 06, 06, 06, 05, 05, 05, 10, 10], // 192 = Scufib Chamber
|
||||
193 => [21, 21, 21, 22, 22, 22, 23, 23, 12, 12, 01, 01], // 193 = Rixy Chamber
|
||||
194 => [25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26], // 194 = Viapois Chamber
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(location)),
|
||||
};
|
||||
}
|
|
@ -25,6 +25,17 @@ public static class SlotMethodJ
|
|||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the range that a given slot number is allowed to roll for a specific <see cref="SlotType4"/>.
|
||||
/// </summary>
|
||||
public static (byte Min, byte Max) GetRange(SlotType4 type, byte slotNumber) => type switch
|
||||
{
|
||||
Old_Rod or Surf => GetRangeSurf(slotNumber),
|
||||
Good_Rod or Super_Rod => GetRangeSuperRod(slotNumber),
|
||||
HoneyTree => (0, 99), // Fake
|
||||
_ => GetRangeGrass(slotNumber),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the encounter slot index based on the roll for a Gen4 Wild encounter.
|
||||
/// </summary>
|
||||
|
@ -54,4 +65,28 @@ public static class SlotMethodJ
|
|||
99 => 4, // 99 ( 1%)
|
||||
_ => Invalid,
|
||||
};
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the range a given slot number is allowed to roll in for a <see cref="Grass"/> encounter.
|
||||
/// </summary>
|
||||
public static (byte Min, byte Max) GetRangeGrass(byte slotNumber) => SlotMethodH.GetRangeGrass(slotNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the range a given slot number is allowed to roll in for a <see cref="Surf"/> encounter.
|
||||
/// </summary>
|
||||
public static (byte Min, byte Max) GetRangeSurf(byte slotNumber) => SlotMethodH.GetRangeSurf(slotNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the range a given slot number is allowed to roll in for a <see cref="Super_Rod"/> encounter.
|
||||
/// </summary>
|
||||
public static (byte Min, byte Max) GetRangeSuperRod(byte slotNumber) => slotNumber switch
|
||||
{
|
||||
0 => (00, 39), // (40%)
|
||||
1 => (40, 79), // (40%)
|
||||
2 => (80, 94), // (15%)
|
||||
3 => (95, 98), // ( 4%)
|
||||
4 => (99, 99), // ( 1%)
|
||||
_ => (Invalid, Invalid),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -27,6 +27,22 @@ public static class SlotMethodK
|
|||
_ => Invalid,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the range that a given slot number is allowed to roll for a specific <see cref="SlotType4"/>.
|
||||
/// </summary>
|
||||
public static (byte Min, byte Max) GetRange(SlotType4 type, byte slotNumber) => type switch
|
||||
{
|
||||
Grass => GetRangeGrass(slotNumber),
|
||||
Surf => GetRangeSurf(slotNumber),
|
||||
Old_Rod or Good_Rod or Super_Rod => GetRangeSuperRod(slotNumber),
|
||||
Rock_Smash => GetRangeRockSmash(slotNumber),
|
||||
Headbutt or HeadbuttSpecial => GetRangeHeadbutt(slotNumber),
|
||||
BugContest => GetRangeBugCatchingContest(slotNumber),
|
||||
Safari_Grass or Safari_Surf or
|
||||
Safari_Old_Rod or Safari_Good_Rod or Safari_Super_Rod => GetRangeSafari(slotNumber),
|
||||
_ => (Invalid, Invalid),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the encounter slot index based on the roll for a Gen4 Wild encounter.
|
||||
/// </summary>
|
||||
|
@ -106,4 +122,75 @@ public static class SlotMethodK
|
|||
<100 => 5, // 95,99 ( 5%)
|
||||
_ => Invalid,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the range a given slot number is allowed to roll in for a <see cref="Grass"/> encounter.
|
||||
/// </summary>
|
||||
public static (byte Min, byte Max) GetRangeGrass(byte slotNumber) => SlotMethodH.GetRangeGrass(slotNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the range a given slot number is allowed to roll in for a <see cref="Surf"/> encounter.
|
||||
/// </summary>
|
||||
public static (byte Min, byte Max) GetRangeSurf(byte slotNumber) => SlotMethodH.GetRangeSurf(slotNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the range a given slot number is allowed to roll in for a <see cref="Super_Rod"/> encounter.
|
||||
/// </summary>
|
||||
public static (byte Min, byte Max) GetRangeSuperRod(byte slotNumber) => slotNumber switch
|
||||
{
|
||||
0 => (00, 39), // (40%)
|
||||
1 => (40, 69), // (30%)
|
||||
2 => (70, 84), // (15%)
|
||||
3 => (85, 94), // (10%)
|
||||
4 => (95, 99), // ( 5%)
|
||||
_ => (Invalid, Invalid),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the range a given slot number is allowed to roll in for a <see cref="Rock_Smash"/> encounter.
|
||||
/// </summary>
|
||||
public static (byte Min, byte Max) GetRangeRockSmash(byte slotNumber) => slotNumber switch
|
||||
{
|
||||
0 => (00, 79), // (80%)
|
||||
1 => (80, 99), // (20%)
|
||||
_ => (Invalid, Invalid),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the range a given slot number is allowed to roll in for a <see cref="Headbutt"/> encounter.
|
||||
/// </summary>
|
||||
public static (byte Min, byte Max) GetRangeHeadbutt(byte slotNumber) => slotNumber switch
|
||||
{
|
||||
0 => (00, 49), // (50%)
|
||||
1 => (50, 64), // (15%)
|
||||
2 => (65, 79), // (15%)
|
||||
3 => (80, 89), // (10%)
|
||||
4 => (90, 94), // ( 5%)
|
||||
5 => (95, 99), // ( 5%)
|
||||
_ => (Invalid, Invalid),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the range a given slot number is allowed to roll in for a <see cref="BugContest"/> encounter.
|
||||
/// </summary>
|
||||
public static (byte Min, byte Max) GetRangeBugCatchingContest(byte slotNumber) => slotNumber switch
|
||||
{
|
||||
9 => (00, 04), // ( 5%)
|
||||
8 => (05, 09), // ( 5%)
|
||||
7 => (10, 14), // ( 5%)
|
||||
6 => (15, 19), // ( 5%)
|
||||
5 => (20, 29), // (10%)
|
||||
4 => (30, 39), // (10%)
|
||||
3 => (40, 49), // (10%)
|
||||
2 => (50, 59), // (10%)
|
||||
1 => (60, 79), // (20%)
|
||||
0 => (80, 99), // (20%)
|
||||
_ => (Invalid, Invalid),
|
||||
};
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the range a given slot number is allowed to roll in for a <see cref="Safari_Grass"/> (and other Safari Types) encounter.
|
||||
/// </summary>
|
||||
public static (byte Min, byte Max) GetRangeSafari(byte slotNumber) => (slotNumber, slotNumber);
|
||||
}
|
||||
|
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in a new issue