2017-11-26 06:28:38 +00:00
|
|
|
|
using System.Linq;
|
|
|
|
|
|
|
|
|
|
namespace PKHeX.Core
|
2017-05-15 06:21:34 +00:00
|
|
|
|
{
|
|
|
|
|
public static class SlotRange
|
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private static readonly Range[] H_OldRod = GetRanges(70, 30);
|
|
|
|
|
private static readonly Range[] H_GoodRod = GetRanges(60, 20, 20);
|
2017-11-29 04:56:21 +00:00
|
|
|
|
private static readonly Range[] H_SuperRod = GetRanges(40, 40, 15, 4, 1);
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private static readonly Range[] H_Surf = GetRanges(60, 30, 5, 4, 1);
|
|
|
|
|
private static readonly Range[] H_Regular = GetRanges(20, 20, 10, 10, 10, 10, 5, 5, 4, 4, 1, 1);
|
2017-05-15 06:21:34 +00:00
|
|
|
|
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private static readonly Range[] J_SuperRod = GetRanges(40, 40, 15, 4, 1);
|
2017-11-29 04:56:21 +00:00
|
|
|
|
private static readonly Range[] K_SuperRod = GetRanges(40, 30, 15, 10, 5);
|
2017-11-26 06:28:38 +00:00
|
|
|
|
private static readonly Range[] K_BCC = GetRanges(5,5,5,5, 10,10,10,10, 20,20).Reverse().ToArray();
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private static readonly Range[] K_Headbutt = GetRanges(50, 15, 15, 10, 5, 5);
|
2017-05-15 06:21:34 +00:00
|
|
|
|
|
2017-12-02 00:33:03 +00:00
|
|
|
|
public static int GetSlot(SlotType type, uint rand, FrameType t)
|
2017-05-15 06:21:34 +00:00
|
|
|
|
{
|
2019-10-08 01:40:09 +00:00
|
|
|
|
return t switch
|
2017-05-15 06:21:34 +00:00
|
|
|
|
{
|
2019-10-08 01:40:09 +00:00
|
|
|
|
FrameType.MethodH => HSlot(type, rand),
|
|
|
|
|
FrameType.MethodJ => JSlot(type, rand),
|
|
|
|
|
FrameType.MethodK => KSlot(type, rand),
|
|
|
|
|
_ => -1
|
|
|
|
|
};
|
2017-05-15 06:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static int HSlot(SlotType type, uint rand)
|
|
|
|
|
{
|
|
|
|
|
var ESV = rand % 100;
|
2019-10-08 01:40:09 +00:00
|
|
|
|
return type switch
|
2017-05-15 06:21:34 +00:00
|
|
|
|
{
|
2019-10-08 01:40:09 +00:00
|
|
|
|
SlotType.Old_Rod => CalcSlot(ESV, H_OldRod),
|
|
|
|
|
SlotType.Old_Rod_Safari => CalcSlot(ESV, H_OldRod),
|
|
|
|
|
SlotType.Good_Rod => CalcSlot(ESV, H_GoodRod),
|
|
|
|
|
SlotType.Good_Rod_Safari => CalcSlot(ESV, H_GoodRod),
|
|
|
|
|
SlotType.Super_Rod => CalcSlot(ESV, H_SuperRod),
|
|
|
|
|
SlotType.Super_Rod_Safari => CalcSlot(ESV, H_SuperRod),
|
|
|
|
|
SlotType.Rock_Smash => CalcSlot(ESV, H_Surf),
|
|
|
|
|
SlotType.Rock_Smash_Safari => CalcSlot(ESV, H_Surf),
|
|
|
|
|
SlotType.Surf => CalcSlot(ESV, H_Surf),
|
|
|
|
|
SlotType.Surf_Safari => CalcSlot(ESV, H_Surf),
|
|
|
|
|
SlotType.Swarm => (ESV < 50 ? 0 : -1),
|
|
|
|
|
_ => CalcSlot(ESV, H_Regular)
|
|
|
|
|
};
|
2017-05-15 06:21:34 +00:00
|
|
|
|
}
|
2018-09-15 05:37:47 +00:00
|
|
|
|
|
2017-12-02 00:33:03 +00:00
|
|
|
|
private static int KSlot(SlotType type, uint rand)
|
2017-05-15 06:21:34 +00:00
|
|
|
|
{
|
|
|
|
|
var ESV = rand % 100;
|
|
|
|
|
switch (type)
|
|
|
|
|
{
|
2017-11-30 07:20:49 +00:00
|
|
|
|
case SlotType.Rock_Smash:
|
2017-05-15 06:21:34 +00:00
|
|
|
|
case SlotType.Surf:
|
2017-12-02 00:33:03 +00:00
|
|
|
|
return CalcSlot(ESV, H_Surf);
|
2017-05-15 06:21:34 +00:00
|
|
|
|
case SlotType.Super_Rod:
|
|
|
|
|
case SlotType.Good_Rod:
|
|
|
|
|
case SlotType.Old_Rod:
|
2017-12-02 00:33:03 +00:00
|
|
|
|
return CalcSlot(ESV, K_SuperRod);
|
2017-05-15 06:21:34 +00:00
|
|
|
|
case SlotType.BugContest:
|
2017-12-02 00:33:03 +00:00
|
|
|
|
return CalcSlot(ESV, K_BCC);
|
2017-05-15 06:21:34 +00:00
|
|
|
|
case SlotType.Grass_Safari:
|
|
|
|
|
case SlotType.Surf_Safari:
|
|
|
|
|
case SlotType.Old_Rod_Safari:
|
|
|
|
|
case SlotType.Good_Rod_Safari:
|
|
|
|
|
case SlotType.Super_Rod_Safari:
|
|
|
|
|
case SlotType.Rock_Smash_Safari:
|
2017-11-25 23:03:37 +00:00
|
|
|
|
return 0; // (int)(rand % 10); /* Block Slot Priority not implemented */
|
2017-05-15 06:21:34 +00:00
|
|
|
|
case SlotType.Headbutt:
|
|
|
|
|
case SlotType.Headbutt_Special:
|
2017-12-02 00:33:03 +00:00
|
|
|
|
return CalcSlot(ESV, K_Headbutt);
|
2017-05-15 06:21:34 +00:00
|
|
|
|
default:
|
|
|
|
|
return CalcSlot(ESV, H_Regular);
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-09-15 05:37:47 +00:00
|
|
|
|
|
2017-12-02 00:33:03 +00:00
|
|
|
|
private static int JSlot(SlotType type, uint rand)
|
2017-05-15 06:21:34 +00:00
|
|
|
|
{
|
|
|
|
|
uint ESV = rand / 656;
|
|
|
|
|
switch (type)
|
|
|
|
|
{
|
|
|
|
|
case SlotType.Old_Rod:
|
2017-11-30 07:20:49 +00:00
|
|
|
|
case SlotType.Rock_Smash:
|
2017-05-15 06:21:34 +00:00
|
|
|
|
case SlotType.Surf:
|
2017-12-02 00:33:03 +00:00
|
|
|
|
return CalcSlot(ESV, H_Surf);
|
2017-05-15 06:21:34 +00:00
|
|
|
|
case SlotType.Good_Rod:
|
|
|
|
|
case SlotType.Super_Rod:
|
2017-12-02 00:33:03 +00:00
|
|
|
|
return CalcSlot(ESV, J_SuperRod);
|
2017-11-25 21:53:39 +00:00
|
|
|
|
case SlotType.HoneyTree:
|
|
|
|
|
return 0;
|
2017-05-15 06:21:34 +00:00
|
|
|
|
default:
|
|
|
|
|
return CalcSlot(ESV, H_Regular);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private struct Range
|
2017-05-15 06:21:34 +00:00
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
internal Range(uint min, uint max)
|
2017-05-15 06:21:34 +00:00
|
|
|
|
{
|
|
|
|
|
Min = min;
|
|
|
|
|
Max = max;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-18 01:37:19 +00:00
|
|
|
|
internal uint Min { get; }
|
|
|
|
|
internal uint Max { get; }
|
2017-05-15 06:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private static Range[] GetRanges(params uint[] rates)
|
2017-05-15 06:21:34 +00:00
|
|
|
|
{
|
|
|
|
|
var len = rates.Length;
|
|
|
|
|
var arr = new Range[len];
|
|
|
|
|
uint sum = 0;
|
|
|
|
|
for (int i = 0; i < len; ++i)
|
|
|
|
|
arr[i] = new Range(sum, (sum += rates[i]) - 1);
|
|
|
|
|
return arr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static int CalcSlot(uint esv, Range[] ranges)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < ranges.Length; ++i)
|
2018-10-27 15:53:09 +00:00
|
|
|
|
{
|
2017-05-15 06:21:34 +00:00
|
|
|
|
if (esv >= ranges[i].Min && esv <= ranges[i].Max)
|
|
|
|
|
return i;
|
2018-10-27 15:53:09 +00:00
|
|
|
|
}
|
2017-05-15 06:21:34 +00:00
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-30 07:20:49 +00:00
|
|
|
|
public static int GetLevel(EncounterSlot slot, LeadRequired lead, uint lvlrand)
|
2017-05-15 06:21:34 +00:00
|
|
|
|
{
|
2017-11-30 07:20:49 +00:00
|
|
|
|
if (lead == LeadRequired.PressureHustleSpirit)
|
2017-11-30 05:31:52 +00:00
|
|
|
|
return slot.LevelMax;
|
|
|
|
|
if (slot.LevelMin == slot.LevelMax)
|
|
|
|
|
return slot.LevelMin;
|
|
|
|
|
int delta = slot.LevelMax - slot.LevelMin + 1;
|
|
|
|
|
var adjust = (int)(lvlrand % delta);
|
|
|
|
|
|
2017-11-30 07:20:49 +00:00
|
|
|
|
return slot.LevelMin + adjust;
|
2017-11-30 05:31:52 +00:00
|
|
|
|
}
|
2018-09-15 05:37:47 +00:00
|
|
|
|
|
2017-11-30 07:20:49 +00:00
|
|
|
|
public static bool GetIsEncounterable(EncounterSlot slot, FrameType frameType, int rand, LeadRequired lead)
|
2017-11-30 05:31:52 +00:00
|
|
|
|
{
|
2017-11-30 07:20:49 +00:00
|
|
|
|
if (slot.Type.IsSweetScentType())
|
|
|
|
|
return true;
|
2017-11-30 05:31:52 +00:00
|
|
|
|
return true; // todo
|
2018-03-11 03:40:57 +00:00
|
|
|
|
//return GetCanEncounter(slot, frameType, rand, lead);
|
2017-11-30 07:20:49 +00:00
|
|
|
|
}
|
2018-09-15 05:37:47 +00:00
|
|
|
|
|
2017-11-30 07:20:49 +00:00
|
|
|
|
private static bool GetCanEncounter(EncounterSlot slot, FrameType frameType, int rand, LeadRequired lead)
|
|
|
|
|
{
|
|
|
|
|
int proc = frameType == FrameType.MethodJ ? rand / 656 : rand % 100;
|
2018-05-12 19:28:48 +00:00
|
|
|
|
if ((slot.Type & SlotType.Rock_Smash) != 0)
|
2017-11-30 07:20:49 +00:00
|
|
|
|
return proc < 60;
|
|
|
|
|
if (frameType == FrameType.MethodH)
|
|
|
|
|
return true; // fishing encounters are disjointed by the hooked message.
|
|
|
|
|
|
|
|
|
|
// fishing
|
2018-05-12 19:28:48 +00:00
|
|
|
|
if ((slot.Type & SlotType.Old_Rod) != 0)
|
2017-11-30 07:20:49 +00:00
|
|
|
|
{
|
|
|
|
|
if (proc < 25)
|
|
|
|
|
return true;
|
|
|
|
|
if (proc < 50)
|
|
|
|
|
return lead == LeadRequired.None;
|
|
|
|
|
}
|
2018-05-12 19:28:48 +00:00
|
|
|
|
else if ((slot.Type & SlotType.Good_Rod) != 0)
|
2017-11-30 07:20:49 +00:00
|
|
|
|
{
|
|
|
|
|
if (proc < 50)
|
|
|
|
|
return true;
|
|
|
|
|
if (proc < 75 && lead == LeadRequired.None)
|
|
|
|
|
return lead == LeadRequired.None;
|
|
|
|
|
}
|
2018-05-12 19:28:48 +00:00
|
|
|
|
else if ((slot.Type & SlotType.Super_Rod) != 0)
|
2017-11-30 07:20:49 +00:00
|
|
|
|
{
|
|
|
|
|
if (proc < 75)
|
|
|
|
|
return true;
|
|
|
|
|
return lead == LeadRequired.None; // < 100 always true
|
|
|
|
|
}
|
|
|
|
|
return false; // shouldn't hit here
|
2017-05-15 06:21:34 +00:00
|
|
|
|
}
|
2017-12-02 00:33:03 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Checks both Static and Magnet Pull ability type selection encounters to see if the encounter can be selected.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="slot">Slot Data</param>
|
|
|
|
|
/// <param name="ESV">Rand16 value for the call</param>
|
|
|
|
|
/// <returns>Slot number from the slot data if the slot is selected on this frame, else an invalid slot value.</returns>
|
|
|
|
|
internal static int GetSlotStaticMagnet(EncounterSlot slot, uint ESV)
|
|
|
|
|
{
|
|
|
|
|
if (slot.Permissions.StaticIndex >= 0)
|
|
|
|
|
{
|
|
|
|
|
var index = ESV % slot.Permissions.StaticCount;
|
|
|
|
|
if (index == slot.Permissions.StaticIndex)
|
|
|
|
|
return slot.SlotNumber;
|
|
|
|
|
}
|
|
|
|
|
if (slot.Permissions.MagnetPullIndex >= 0)
|
|
|
|
|
{
|
|
|
|
|
var index = ESV % slot.Permissions.MagnetPullCount;
|
|
|
|
|
if (index == slot.Permissions.MagnetPullIndex)
|
|
|
|
|
return slot.SlotNumber;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2017-05-15 06:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
}
|