mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-24 04:53:08 +00:00
02420d3e93
* Handle some nullable cases Refactor MysteryGift into a second abstract class (backed by a byte array, or fake data) Make some classes have explicit constructors instead of { } initialization * Handle bits more obviously without null * Make SaveFile.BAK explicitly readonly again * merge constructor methods to have readonly fields * Inline some properties * More nullable handling * Rearrange box actions define straightforward classes to not have any null properties * Make extrabyte reference array immutable * Move tooltip creation to designer * Rearrange some logic to reduce nesting * Cache generated fonts * Split mystery gift album purpose * Handle more tooltips * Disallow null setters * Don't capture RNG object, only type enum * Unify learnset objects Now have readonly properties which are never null don't new() empty learnsets (>800 Learnset objects no longer created, total of 2400 objects since we also new() a move & level array) optimize g1/2 reader for early abort case * Access rewrite Initialize blocks in a separate object, and get via that object removes a couple hundred "might be null" warnings since blocks are now readonly getters some block references have been relocated, but interfaces should expose all that's needed put HoF6 controls in a groupbox, and disable * Readonly personal data * IVs non nullable for mystery gift * Explicitly initialize forced encounter moves * Make shadow objects readonly & non-null Put murkrow fix in binary data resource, instead of on startup * Assign dex form fetch on constructor Fixes legality parsing edge cases also handle cxd parse for valid; exit before exception is thrown in FrameGenerator * Remove unnecessary null checks * Keep empty value until init SetPouch sets the value to an actual one during load, but whatever * Readonly team lock data * Readonly locks Put locked encounters at bottom (favor unlocked) * Mail readonly data / offset Rearrange some call flow and pass defaults Add fake classes for SaveDataEditor mocking Always party size, no need to check twice in stat editor use a fake save file as initial data for savedata editor, and for gamedata (wow i found a usage) constrain eventwork editor to struct variable types (uint, int, etc), thus preventing null assignment errors
232 lines
No EOL
8.6 KiB
C#
232 lines
No EOL
8.6 KiB
C#
using System;
|
|
using System.Linq;
|
|
|
|
namespace PKHeX.Core
|
|
{
|
|
public abstract class Zukan
|
|
{
|
|
protected SaveFile SAV { get; set; }
|
|
public int PokeDex { get; private set; }
|
|
protected int PokeDexLanguageFlags { get; set; }
|
|
|
|
protected Zukan(SaveFile sav, int dex, int langflag)
|
|
{
|
|
SAV = sav;
|
|
PokeDex = dex;
|
|
PokeDexLanguageFlags = langflag;
|
|
if (langflag > dex)
|
|
throw new ArgumentException(nameof(langflag));
|
|
}
|
|
|
|
protected abstract int OFS_SEEN { get; }
|
|
protected abstract int OFS_CAUGHT { get; }
|
|
protected abstract int BitSeenSize { get; }
|
|
protected abstract int DexLangFlagByteCount { get; }
|
|
protected abstract int DexLangIDCount { get; }
|
|
protected abstract int GetDexLangFlag(int lang);
|
|
|
|
protected abstract bool GetSaneFormsToIterate(int species, out int formStart, out int formEnd, int formIn);
|
|
protected virtual void SetSpindaDexData(PKM pkm, bool alreadySeen) { }
|
|
protected abstract void SetAllDexFlagsLanguage(int bit, int lang, bool value = true);
|
|
protected abstract void SetAllDexSeenFlags(int baseBit, int altform, int gender, bool isShiny, bool value = true);
|
|
|
|
protected bool GetFlag(int ofs, int bitIndex) => SAV.GetFlag(PokeDex + ofs + (bitIndex >> 3), bitIndex);
|
|
protected void SetFlag(int ofs, int bitIndex, bool value = true) => SAV.SetFlag(PokeDex + ofs + (bitIndex >> 3), bitIndex, value);
|
|
|
|
public virtual bool GetCaught(int species) => GetFlag(OFS_CAUGHT, species - 1);
|
|
public virtual void SetCaught(int species, bool value = true) => SetFlag(OFS_CAUGHT, species - 1, value);
|
|
|
|
public int SeenCount => Enumerable.Range(1, SAV.MaxSpeciesID).Count(GetSeen);
|
|
public int CaughtCount => Enumerable.Range(1, SAV.MaxSpeciesID).Count(GetCaught);
|
|
public decimal PercentSeen => (decimal)SeenCount / SAV.MaxSpeciesID;
|
|
public decimal PercentCaught => (decimal)CaughtCount / SAV.MaxSpeciesID;
|
|
|
|
public virtual bool GetSeen(int species)
|
|
{
|
|
// check all 4 seen flags (gender/shiny)
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
if (GetSeen(species, i))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public bool GetSeen(int species, int i) => GetFlag(OFS_SEEN + (i * BitSeenSize), species - 1);
|
|
public void SetSeen(int species, int i, bool value) => SetFlag(OFS_SEEN + (i * BitSeenSize), species - 1, value);
|
|
|
|
public bool GetDisplayed(int bit, int i) => GetFlag(OFS_SEEN + ((i + 4) * BitSeenSize), bit);
|
|
public void SetDisplayed(int bit, int i, bool value) => SetFlag(OFS_SEEN + ((i + 4) * BitSeenSize), bit, value);
|
|
|
|
public bool GetLanguageFlag(int bit, int lang) => GetFlag(PokeDexLanguageFlags, (bit * DexLangIDCount) + lang);
|
|
public void SetLanguageFlag(int bit, int lang, bool value) => SetFlag(PokeDexLanguageFlags, (bit * DexLangIDCount) + lang, value);
|
|
|
|
public virtual void SetSeen(int species, bool value = true)
|
|
{
|
|
if (!value)
|
|
{
|
|
ClearSeen(species);
|
|
return;
|
|
}
|
|
|
|
// check all 4 seen flags (gender/shiny)
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
if (GetFlag(OFS_SEEN + (i * BitSeenSize), species - 1))
|
|
return;
|
|
}
|
|
var gender = SAV.Personal[species].RandomGender() & 1;
|
|
SetAllDexSeenFlags(species - 1, 0, gender, false);
|
|
}
|
|
|
|
private void ClearSeen(int species)
|
|
{
|
|
SetCaught(species, false);
|
|
for (int i = 0; i < 4; i++)
|
|
SetFlag(OFS_SEEN + (i * BitSeenSize), species - 1, false);
|
|
}
|
|
|
|
public virtual void SetDex(PKM pkm)
|
|
{
|
|
if (PokeDex < 0 || SAV.Version == GameVersion.Invalid) // sanity
|
|
return;
|
|
if (pkm.Species == 0 || pkm.Species > SAV.MaxSpeciesID) // out of range
|
|
return;
|
|
if (pkm.IsEgg) // do not add
|
|
return;
|
|
|
|
int species = pkm.Species;
|
|
if (species == 327) // Spinda
|
|
SetSpindaDexData(pkm, GetSeen(species));
|
|
|
|
int bit = pkm.Species - 1;
|
|
int form = pkm.AltForm;
|
|
int gender = pkm.Gender & 1;
|
|
bool shiny = pkm.IsShiny;
|
|
int lang = pkm.Language;
|
|
SetDex(species, bit, form, gender, shiny, lang);
|
|
}
|
|
|
|
protected virtual void SetDex(int species, int bit, int form, int gender, bool shiny, int lang)
|
|
{
|
|
SetCaught(species); // Set the Owned Flag
|
|
SetAllDexSeenFlags(bit, form, gender, shiny); // genderless -> male
|
|
SetAllDexFlagsLanguage(bit, lang);
|
|
}
|
|
|
|
protected void SetDexFlags(int baseBit, int formBit, int gender, int shiny, bool value = true)
|
|
{
|
|
int shift = (gender & 1) | (shiny << 1);
|
|
|
|
// Set the [Species/Gender/Shiny] Seen Flag
|
|
SetFlag(OFS_SEEN + (shift * BitSeenSize), baseBit, value);
|
|
|
|
// Set the Display flag if none are set
|
|
SetDisplayedFlag(baseBit, formBit, value, shift);
|
|
}
|
|
|
|
protected virtual void SetDisplayedFlag(int baseBit, int formBit, bool value, int shift)
|
|
{
|
|
bool displayed = GetIsSpeciesFormAnyDisplayed(baseBit, formBit);
|
|
if (!displayed || !value)
|
|
SetFlag(OFS_SEEN + ((4 + shift) * BitSeenSize), formBit, value);
|
|
}
|
|
|
|
private bool GetIsSpeciesFormAnyDisplayed(int baseBit, int formBit)
|
|
{
|
|
// Check Displayed Status for base form
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
if (GetDisplayed(baseBit, i))
|
|
return true;
|
|
}
|
|
if (baseBit == formBit)
|
|
return false;
|
|
|
|
// If form is not base form, check form too
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
if (GetDisplayed(formBit, i))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Bulk Manipulation
|
|
public void SeenNone() => SetDexEntriesAll(false, shinyToo: true);
|
|
public void CaughtNone() => SetAllCaught(false, true);
|
|
public void SeenAll(bool shinyToo = false) => SetAllSeen(shinyToo);
|
|
public void CompleteDex(bool shinyToo = false) => SetDexEntriesAll(shinyToo: shinyToo);
|
|
|
|
public void CaughtAll(bool shinyToo = false)
|
|
{
|
|
SetAllSeen(true, shinyToo);
|
|
SetAllCaught(true, shinyToo);
|
|
}
|
|
|
|
public void SetAllCaught(bool value = true, bool shinyToo = false)
|
|
{
|
|
for (int i = 0; i < SAV.MaxSpeciesID; i++)
|
|
{
|
|
int species = i + 1;
|
|
SetCaught(species, value); // Set the Owned Flag
|
|
SetSeenSingle(i + 1, value, shinyToo);
|
|
}
|
|
}
|
|
|
|
public void SetAllSeen(bool value = true, bool shinyToo = false)
|
|
{
|
|
for (int i = 0; i < SAV.MaxSpeciesID; i++)
|
|
SetSeenSingle(i + 1, value, shinyToo);
|
|
}
|
|
|
|
public void SetDexEntriesAll(bool value = true, int max = -1, bool shinyToo = false)
|
|
{
|
|
if (max <= 0)
|
|
max = SAV.MaxSpeciesID;
|
|
|
|
for (int i = 1; i <= max; i++)
|
|
{
|
|
SetSeenSingle(i, value, shinyToo);
|
|
SetCaughtSingle(i, value);
|
|
}
|
|
}
|
|
|
|
public void SetCaughtSingle(int species, bool value = true)
|
|
{
|
|
SetCaught(species, value);
|
|
int baseBit = species - 1;
|
|
SetAllDexFlagsLanguage(baseBit, value);
|
|
}
|
|
|
|
public void SetSeenSingle(int species, bool seen = true, bool shinyToo = false)
|
|
{
|
|
SetSeen(species, seen);
|
|
|
|
var entry = SAV.Personal[species];
|
|
int baseBit = species - 1;
|
|
int fc = entry.FormeCount;
|
|
for (int f = 0; f < fc; f++)
|
|
{
|
|
if (!entry.OnlyFemale)
|
|
{
|
|
SetAllDexSeenFlags(baseBit, f, 0, false, seen);
|
|
if (shinyToo)
|
|
SetAllDexSeenFlags(baseBit, f, 0, true, seen);
|
|
}
|
|
if (!entry.OnlyMale && !entry.Genderless)
|
|
{
|
|
SetAllDexSeenFlags(baseBit, f, 1, false, seen);
|
|
if (shinyToo)
|
|
SetAllDexSeenFlags(baseBit, f, 1, true, seen);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void SetAllDexFlagsLanguage(int bit, bool value = true)
|
|
{
|
|
for (int i = 1; i <= DexLangIDCount + 1; i++)
|
|
SetAllDexFlagsLanguage(bit, i, value);
|
|
}
|
|
}
|
|
} |