mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-10 06:34:19 +00:00
Extract some logic to SAV4
Closes #4128 I don't want to decipher to manual interactions to the Battle Frontier structures now. Prints were just work values, and fly flags were event flags.
This commit is contained in:
parent
61df1981ce
commit
f7a888cc57
19 changed files with 471 additions and 396 deletions
|
@ -55,9 +55,9 @@ public sealed class PersonalInfo3(byte[] Data) : PersonalInfo, IPersonalAbility1
|
|||
|
||||
public bool HasSecondAbility => Ability1 != Ability2;
|
||||
|
||||
public void AddTMHM(ReadOnlySpan<byte> data) => TMHM = FlagUtil.GitBitFlagArray(data);
|
||||
public void AddTMHM(ReadOnlySpan<byte> data) => TMHM = FlagUtil.GetBitFlagArray(data);
|
||||
|
||||
public void AddTypeTutors(ReadOnlySpan<byte> data) => TypeTutors = FlagUtil.GitBitFlagArray(data);
|
||||
public void AddTypeTutors(ReadOnlySpan<byte> data) => TypeTutors = FlagUtil.GetBitFlagArray(data);
|
||||
|
||||
/// <summary>
|
||||
/// TM/HM learn compatibility flags for individual moves.
|
||||
|
|
|
@ -59,7 +59,7 @@ public sealed class PersonalInfo4(byte[] Data) : PersonalInfo, IPersonalAbility1
|
|||
public override byte FormCount { get => Data[0x29]; set {} }
|
||||
public override int FormStatsIndex { get => ReadUInt16LittleEndian(Data.AsSpan(0x2A)); set {} }
|
||||
|
||||
public void AddTypeTutors(ReadOnlySpan<byte> data) => TypeTutors = FlagUtil.GitBitFlagArray(data);
|
||||
public void AddTypeTutors(ReadOnlySpan<byte> data) => TypeTutors = FlagUtil.GetBitFlagArray(data);
|
||||
public void CopyTypeTutors(PersonalInfo4 other) => TypeTutors = other.TypeTutors;
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -201,7 +201,7 @@ public abstract class SAV4 : SaveFile, IEventFlag37
|
|||
{
|
||||
var block = ExtraBlocks[1];
|
||||
var active = GetActiveExtraBlock(block);
|
||||
return active == -1 ? null : new Hall4(Data, (active == 0 ? 0 : PartitionSize) + block.Offset);
|
||||
return active == -1 ? null : new Hall4(Data.AsMemory((active == 0 ? 0 : PartitionSize) + block.Offset, Hall4.SIZE_BLOCK));
|
||||
}
|
||||
|
||||
protected int WondercardFlags = int.MinValue;
|
||||
|
@ -604,7 +604,7 @@ public abstract class SAV4 : SaveFile, IEventFlag37
|
|||
#endregion
|
||||
|
||||
// Seals
|
||||
private const byte SealMaxCount = 99;
|
||||
public const byte SealMaxCount = 99;
|
||||
|
||||
public Span<byte> GetSealCase() => General.Slice(Seal, (int)Seal4.MAX);
|
||||
public void SetSealCase(ReadOnlySpan<byte> value) => SetData(General.Slice(Seal, (int)Seal4.MAX), value);
|
||||
|
@ -652,4 +652,7 @@ public abstract class SAV4 : SaveFile, IEventFlag37
|
|||
++SwarmSeed;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract int BP { get; set; }
|
||||
public abstract BattleFrontierFacility4 MaxFacility { get; }
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ public sealed class SAV4DP : SAV4Sinnoh
|
|||
|
||||
protected override int EventWork => 0xD9C;
|
||||
protected override int EventFlag => 0xFDC;
|
||||
public override BattleFrontierFacility4 MaxFacility => BattleFrontierFacility4.Tower;
|
||||
|
||||
private void GetSAVOffsets()
|
||||
{
|
||||
|
@ -165,6 +166,7 @@ public sealed class SAV4DP : SAV4Sinnoh
|
|||
public override uint SafariSeed { get => ReadUInt32LittleEndian(General[0x53C4..]); set => WriteUInt32LittleEndian(General[0x53C4..], value); }
|
||||
public override uint SwarmSeed { get => ReadUInt32LittleEndian(General[0x53C8..]); set => WriteUInt32LittleEndian(General[0x53C8..], value); }
|
||||
public override uint SwarmMaxCountModulo => 28;
|
||||
public override int BP { get => ReadUInt16LittleEndian(General[0x65F8..]); set => WriteUInt16LittleEndian(General[0x65F8..], (ushort)value); }
|
||||
|
||||
protected override ReadOnlySpan<ushort> TreeSpecies =>
|
||||
[
|
||||
|
|
|
@ -51,6 +51,7 @@ public sealed class SAV4HGSS : SAV4
|
|||
|
||||
protected override int EventWork => 0xDE4;
|
||||
protected override int EventFlag => 0x10C4;
|
||||
public override BattleFrontierFacility4 MaxFacility => BattleFrontierFacility4.Arcade;
|
||||
|
||||
private void GetSAVOffsets()
|
||||
{
|
||||
|
@ -78,6 +79,12 @@ public sealed class SAV4HGSS : SAV4
|
|||
set => value.Data.CopyTo(LockCapsuleSpan);
|
||||
}
|
||||
|
||||
public MapUnlockState4 MapUnlockState
|
||||
{
|
||||
get => (MapUnlockState4)((General[0xBAE7] >> 3) & 3);
|
||||
set => General[0xBAE7] = (byte)((General[0xBAE7] & 0xE7) | ((byte)value << 3));
|
||||
}
|
||||
|
||||
#region Storage
|
||||
// box{pk4[30}[18]
|
||||
// u32 currentBox
|
||||
|
@ -261,14 +268,29 @@ public sealed class SAV4HGSS : SAV4
|
|||
public uint PokewalkerSteps { get => ReadUInt32LittleEndian(General[OFS_WALKER..]); set => WriteUInt32LittleEndian(General[OFS_WALKER..], value); }
|
||||
public uint PokewalkerWatts { get => ReadUInt32LittleEndian(General[(OFS_WALKER + 0x4)..]); set => WriteUInt32LittleEndian(General[(OFS_WALKER + 4)..], value); }
|
||||
|
||||
public bool[] GetPokewalkerCoursesUnlocked() => FlagUtil.GitBitFlagArray(General[(OFS_WALKER + 0x8)..], 32);
|
||||
public void SetPokewalkerCoursesUnlocked(ReadOnlySpan<bool> value) => FlagUtil.SetBitFlagArray(General[(OFS_WALKER + 0x8)..], value);
|
||||
public const int PokewalkerCourseFlagCount = 32;
|
||||
public void GetPokewalkerCoursesUnlocked(Span<bool> value)
|
||||
{
|
||||
if (value.Length != PokewalkerCourseFlagCount)
|
||||
throw new ArgumentOutOfRangeException(nameof(value));
|
||||
FlagUtil.GetBitFlagArray(General[(OFS_WALKER + 0x8)..], value);
|
||||
}
|
||||
|
||||
public void PokewalkerCoursesSetAll(uint value = 0x07FF_FFFFu) => WriteUInt32LittleEndian(General[(OFS_WALKER + 0x8)..], value);
|
||||
public void SetPokewalkerCoursesUnlocked(ReadOnlySpan<bool> value)
|
||||
{
|
||||
if (value.Length != PokewalkerCourseFlagCount)
|
||||
throw new ArgumentOutOfRangeException(nameof(value));
|
||||
FlagUtil.SetBitFlagArray(General[(OFS_WALKER + 0x8)..], value);
|
||||
}
|
||||
|
||||
public void PokewalkerCoursesUnlockAll() => PokewalkerCoursesSetAll(0x07FF_FFFFu); // 31 used
|
||||
public void PokewalkerCoursesUnlockNone() => PokewalkerCoursesSetAll(0);
|
||||
public void PokewalkerCoursesSetAll(uint bitFlags) => WriteUInt32LittleEndian(General[(OFS_WALKER + 0x8)..], bitFlags);
|
||||
|
||||
// Swarm
|
||||
public override uint SwarmSeed { get => ReadUInt32LittleEndian(General[0x68A8..]); set => WriteUInt32LittleEndian(General[0x68A8..], value); }
|
||||
public override uint SwarmMaxCountModulo => 20;
|
||||
public override int BP { get => ReadUInt16LittleEndian(General[0x5BB8..]); set => WriteUInt16LittleEndian(General[0x5BB8..], (ushort)value); }
|
||||
|
||||
// Roamers
|
||||
public Roamer4 RoamerRaikou => GetRoamer(0);
|
||||
|
@ -287,3 +309,11 @@ public sealed class SAV4HGSS : SAV4
|
|||
// Pokeathlon
|
||||
public uint PokeathlonPoints { get => ReadUInt32LittleEndian(General[0xE548..]); set => WriteUInt32LittleEndian(General[0xE548..], value); }
|
||||
}
|
||||
|
||||
public enum MapUnlockState4 : byte
|
||||
{
|
||||
Johto = 0,
|
||||
JohtoPlus = 1,
|
||||
JohtoKanto = 2,
|
||||
Invalid = 3,
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ public sealed class SAV4Pt : SAV4Sinnoh
|
|||
|
||||
protected override int EventWork => 0xDAC;
|
||||
protected override int EventFlag => 0xFEC;
|
||||
public override BattleFrontierFacility4 MaxFacility => BattleFrontierFacility4.Arcade;
|
||||
|
||||
private void GetSAVOffsets()
|
||||
{
|
||||
|
@ -143,6 +144,7 @@ public sealed class SAV4Pt : SAV4Sinnoh
|
|||
public override uint SafariSeed { get => ReadUInt32LittleEndian(General[0x5660..]); set => WriteUInt32LittleEndian(General[0x5660..], value); }
|
||||
public override uint SwarmSeed { get => ReadUInt32LittleEndian(General[0x5664..]); set => WriteUInt32LittleEndian(General[0x5664..], value); }
|
||||
public override uint SwarmMaxCountModulo => 22;
|
||||
public override int BP { get => ReadUInt16LittleEndian(General[0x7234..]); set => WriteUInt16LittleEndian(General[0x7234..], (ushort)value); }
|
||||
|
||||
protected override ReadOnlySpan<ushort> TreeSpecies =>
|
||||
[
|
||||
|
|
|
@ -167,44 +167,3 @@ public abstract class SAV4Sinnoh : SAV4
|
|||
public ushort GetHoneyTreeSpecies(int group, int index) =>
|
||||
TreeSpecies.Slice(group * GroupEntryCount, GroupEntryCount)[index];
|
||||
}
|
||||
|
||||
public enum PoketchColor
|
||||
{
|
||||
Green = 0,
|
||||
Yellow = 1,
|
||||
Orange = 2,
|
||||
Red = 3,
|
||||
Purple = 4,
|
||||
Blue = 5,
|
||||
Turquoise = 6,
|
||||
White = 7,
|
||||
}
|
||||
|
||||
public enum PoketchApp
|
||||
{
|
||||
Digital_Watch,
|
||||
Calculator,
|
||||
Memo_Pad,
|
||||
Pedometer,
|
||||
Party,
|
||||
Friendship_Checker,
|
||||
Dowsing_Machine,
|
||||
Berry_Searcher,
|
||||
Daycare,
|
||||
History,
|
||||
Counter,
|
||||
Analog_Watch,
|
||||
Marking_Map,
|
||||
Link_Searcher,
|
||||
Coin_Toss,
|
||||
Move_Tester,
|
||||
Calendar,
|
||||
Dot_Artist,
|
||||
Roulette,
|
||||
Trainer_Counter,
|
||||
Kitchen_Timer,
|
||||
Color_Changer,
|
||||
Matchup_Checker,
|
||||
Stopwatch,
|
||||
Alarm_Clock,
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
namespace PKHeX.Core;
|
||||
|
||||
public enum BattleFrontierFacility4
|
||||
{
|
||||
Tower = 0,
|
||||
Factory = 1,
|
||||
Hall = 2,
|
||||
Castle = 3,
|
||||
Arcade = 4,
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
namespace PKHeX.Core;
|
||||
|
||||
public enum BattleFrontierPrintStatus4
|
||||
{
|
||||
None = 0,
|
||||
FirstReady = 1,
|
||||
FirstReceived = 2,
|
||||
SecondReady = 3,
|
||||
SecondReceived = 4,
|
||||
}
|
|
@ -18,13 +18,10 @@ public sealed class Chatter4: SaveBlock<SAV4>, IChatter
|
|||
|
||||
public Span<byte> Recording => SAV.General.Slice(Offset + sizeof(uint), IChatter.SIZE_PCM);
|
||||
|
||||
public int ConfusionChance
|
||||
public int ConfusionChance => !Initialized ? 1 : (sbyte)Recording[15] switch
|
||||
{
|
||||
get => !Initialized ? 1 : (sbyte)Recording[15] switch
|
||||
{
|
||||
< -30 => 11,
|
||||
>= 30 => 31,
|
||||
_ => 1,
|
||||
};
|
||||
}
|
||||
< -30 => 11,
|
||||
>= 30 => 31,
|
||||
_ => 1,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -3,16 +3,18 @@ using static System.Buffers.Binary.BinaryPrimitives;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
public sealed class Hall4
|
||||
/// <summary>
|
||||
/// Extra-data block for Hall of Fame records.
|
||||
/// </summary>
|
||||
/// <param name="Raw">Chunk of memory storing the structure.</param>
|
||||
public sealed class Hall4(Memory<byte> Raw)
|
||||
{
|
||||
private const int SIZE = 0xBA0;
|
||||
private const int SIZE_FOOTER = 0x10;
|
||||
private const int SIZE_BLOCK = 0x1000;
|
||||
private const int SIZE_USED = SIZE + SIZE_FOOTER;
|
||||
public const int SIZE_BLOCK = 0x1000;
|
||||
|
||||
private readonly byte[] Raw;
|
||||
private readonly int Offset;
|
||||
private Span<byte> Data => Raw.AsSpan(Offset, SIZE_BLOCK);
|
||||
public Hall4(byte[] data, int offset) => (Raw, Offset) = (data, offset);
|
||||
private Span<byte> Data => Raw.Span[..SIZE_USED];
|
||||
|
||||
private const int SIZE_ARRAY = 0x3DE; // 493+(egg, bad-egg) species
|
||||
|
||||
|
|
30
PKHeX.Core/Saves/Substructures/Gen4/PoketchApp.cs
Normal file
30
PKHeX.Core/Saves/Substructures/Gen4/PoketchApp.cs
Normal file
|
@ -0,0 +1,30 @@
|
|||
namespace PKHeX.Core;
|
||||
|
||||
public enum PoketchApp
|
||||
{
|
||||
Digital_Watch = 0,
|
||||
Calculator = 1,
|
||||
Memo_Pad = 2,
|
||||
Pedometer = 3,
|
||||
Party = 4,
|
||||
Friendship_Checker = 5,
|
||||
Dowsing_Machine = 6,
|
||||
Berry_Searcher = 7,
|
||||
Daycare = 8,
|
||||
History = 9,
|
||||
Counter = 10,
|
||||
Analog_Watch = 11,
|
||||
Marking_Map = 12,
|
||||
Link_Searcher = 13,
|
||||
Coin_Toss = 14,
|
||||
Move_Tester = 15,
|
||||
Calendar = 16,
|
||||
Dot_Artist = 17,
|
||||
Roulette = 18,
|
||||
Trainer_Counter = 19,
|
||||
Kitchen_Timer = 20,
|
||||
Color_Changer = 21,
|
||||
Matchup_Checker = 22,
|
||||
Stopwatch = 23,
|
||||
Alarm_Clock = 24,
|
||||
}
|
13
PKHeX.Core/Saves/Substructures/Gen4/PoketchColor.cs
Normal file
13
PKHeX.Core/Saves/Substructures/Gen4/PoketchColor.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
namespace PKHeX.Core;
|
||||
|
||||
public enum PoketchColor
|
||||
{
|
||||
Green = 0,
|
||||
Yellow = 1,
|
||||
Orange = 2,
|
||||
Red = 3,
|
||||
Purple = 4,
|
||||
Blue = 5,
|
||||
Turquoise = 6,
|
||||
White = 7,
|
||||
}
|
|
@ -13,7 +13,7 @@ public sealed class MysteryBlock6 : SaveBlock<SAV6>
|
|||
public MysteryBlock6(SAV6XY sav, int offset) : base(sav) => Offset = offset;
|
||||
public MysteryBlock6(SAV6AO sav, int offset) : base(sav) => Offset = offset;
|
||||
|
||||
public bool[] GetReceivedFlags() => FlagUtil.GitBitFlagArray(Data.AsSpan(Offset + FlagStart), MaxReceivedFlag);
|
||||
public bool[] GetReceivedFlags() => FlagUtil.GetBitFlagArray(Data.AsSpan(Offset + FlagStart), MaxReceivedFlag);
|
||||
|
||||
public void SetReceivedFlags(ReadOnlySpan<bool> value)
|
||||
{
|
||||
|
|
|
@ -15,7 +15,7 @@ public sealed class MysteryBlock7 : SaveBlock<SAV7>
|
|||
// Mystery Gift
|
||||
public bool[] MysteryGiftReceivedFlags
|
||||
{
|
||||
get => FlagUtil.GitBitFlagArray(Data.AsSpan(Offset + FlagStart), MaxReceivedFlag);
|
||||
get => FlagUtil.GetBitFlagArray(Data.AsSpan(Offset + FlagStart), MaxReceivedFlag);
|
||||
set
|
||||
{
|
||||
if (value.Length != MaxReceivedFlag)
|
||||
|
|
|
@ -18,13 +18,16 @@ public sealed class FashionUnlock8(SAV8SWSH sav, SCBlock block) : SaveBlock<SAV8
|
|||
public const int REGION_LEGWEAR = 13;
|
||||
public const int REGION_FOOTWEAR = 14;
|
||||
|
||||
public bool[] GetArrayOwnedFlag(int region) => FlagUtil.GitBitFlagArray(Data.AsSpan(region * SIZE_ENTRY), SIZE_ENTRY * 8);
|
||||
public bool[] GetArrayNewFlag(int region) => FlagUtil.GitBitFlagArray(Data.AsSpan((region + REGIONS) * SIZE_ENTRY), SIZE_ENTRY * 8);
|
||||
private Span<byte> GetOwnedRegion(int region) => Data.AsSpan(region * SIZE_ENTRY, SIZE_ENTRY);
|
||||
private Span<byte> GetNewRegion(int region) => Data.AsSpan((region + REGIONS) * SIZE_ENTRY, SIZE_ENTRY);
|
||||
|
||||
public bool[] GetArrayOwnedFlag(int region) => FlagUtil.GetBitFlagArray(GetOwnedRegion(region), SIZE_ENTRY * 8);
|
||||
public bool[] GetArrayNewFlag(int region) => FlagUtil.GetBitFlagArray(GetNewRegion(region), SIZE_ENTRY * 8);
|
||||
public int[] GetIndexesOwnedFlag(int region) => GetIndexes(GetArrayOwnedFlag(region));
|
||||
public int[] GetIndexesNewFlag(int region) => GetIndexes(GetArrayNewFlag(region));
|
||||
|
||||
public void SetArrayOwnedFlag(int region, Span<bool> value) => FlagUtil.SetBitFlagArray(Data.AsSpan(region * SIZE_ENTRY), value);
|
||||
public void SetArrayNewFlag(int region, Span<bool> value) => FlagUtil.SetBitFlagArray(Data.AsSpan((region + REGIONS) * SIZE_ENTRY), value);
|
||||
public void SetArrayOwnedFlag(int region, Span<bool> value) => FlagUtil.SetBitFlagArray(GetOwnedRegion(region), value);
|
||||
public void SetArrayNewFlag(int region, Span<bool> value) => FlagUtil.SetBitFlagArray(GetNewRegion(region), value);
|
||||
public void SetIndexesOwnedFlag(int region, ReadOnlySpan<int> value) => SetArrayOwnedFlag(region, SetIndexes(value));
|
||||
public void SetIndexesNewFlag(int region, ReadOnlySpan<int> value) => SetArrayNewFlag(region, SetIndexes(value));
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ public static class FlagUtil
|
|||
arr[offset] = (byte)newValue;
|
||||
}
|
||||
|
||||
public static bool[] GitBitFlagArray(ReadOnlySpan<byte> data, int count)
|
||||
public static bool[] GetBitFlagArray(ReadOnlySpan<byte> data, int count)
|
||||
{
|
||||
var result = new bool[count];
|
||||
GetBitFlagArray(data, result);
|
||||
|
@ -47,7 +47,7 @@ public static class FlagUtil
|
|||
result[i] = (data[i >> 3] & (1 << (i & 7))) != 0;
|
||||
}
|
||||
|
||||
public static bool[] GitBitFlagArray(ReadOnlySpan<byte> data) => GitBitFlagArray(data, data.Length << 3);
|
||||
public static bool[] GetBitFlagArray(ReadOnlySpan<byte> data) => GetBitFlagArray(data, data.Length << 3);
|
||||
|
||||
public static void SetBitFlagArray(Span<byte> data, ReadOnlySpan<bool> value)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Globalization;
|
||||
|
@ -7,6 +6,7 @@ using System.Linq;
|
|||
using System.Windows.Forms;
|
||||
using PKHeX.Core;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
using static PKHeX.WinForms.PoketchDotMatrix;
|
||||
|
||||
namespace PKHeX.WinForms;
|
||||
|
||||
|
@ -20,27 +20,31 @@ public partial class SAV_Misc4 : Form
|
|||
{
|
||||
InitializeComponent();
|
||||
WinFormsUtil.TranslateInterface(this, Main.CurrentLanguage);
|
||||
int ofsFlag;
|
||||
SAV = (SAV4)(Origin = sav).Clone();
|
||||
|
||||
switch (SAV.Version)
|
||||
StatNUDA = [NUD_Stat0, NUD_Stat1, NUD_Stat2, NUD_Stat3];
|
||||
StatLabelA = [L_Stat0, L_Stat1, L_Stat2, L_Stat3]; // Current, Trade, Record, Trade
|
||||
StatRBA = [RB_Stats3_01, RB_Stats3_02];
|
||||
HallNUDA =
|
||||
[
|
||||
NUD_HallType01, NUD_HallType02, NUD_HallType03, NUD_HallType04, NUD_HallType05, NUD_HallType06,
|
||||
NUD_HallType07, NUD_HallType08, NUD_HallType09, NUD_HallType10, NUD_HallType11, NUD_HallType12,
|
||||
NUD_HallType13, NUD_HallType14, NUD_HallType15, NUD_HallType16, NUD_HallType17,
|
||||
];
|
||||
PrintButtonA = [BTN_PrintTower, BTN_PrintFactory, BTN_PrintHall, BTN_PrintCastle, BTN_PrintArcade];
|
||||
|
||||
switch (sav)
|
||||
{
|
||||
case GameVersion.D or GameVersion.P or GameVersion.DP:
|
||||
ofsFlag = 0xFDC;
|
||||
ofsBP = 0x65F8;
|
||||
ofsUGFlagCount = 0x3A60;
|
||||
case SAV4DP:
|
||||
L_CurrentMap.Visible = CB_UpgradeMap.Visible = false;
|
||||
GB_Prints.Visible = GB_Prints.Enabled = GB_Hall.Visible = GB_Hall.Enabled = GB_Castle.Visible = GB_Castle.Enabled = false;
|
||||
BFF = [
|
||||
[0, 1, 0x5FCA, 0x04, 0x6601],
|
||||
];
|
||||
break;
|
||||
case GameVersion.Pt:
|
||||
ofsFlag = 0xFEC;
|
||||
ofsBP = 0x7234;
|
||||
ofsUGFlagCount = 0x3CE8;
|
||||
case SAV4Pt:
|
||||
L_CurrentMap.Visible = CB_UpgradeMap.Visible = false;
|
||||
ofsPrints = 0xE4A;
|
||||
PrintIndexStart = 79;
|
||||
BFF = [
|
||||
[0, 1, 0x68E0, 0x04, 0x723D],
|
||||
[1, 0, 0x68F4, 0x10, 0x7EF8],
|
||||
|
@ -50,13 +54,9 @@ public partial class SAV_Misc4 : Form
|
|||
];
|
||||
Hall = SAV.GetHall();
|
||||
break;
|
||||
case GameVersion.HG or GameVersion.SS or GameVersion.HGSS:
|
||||
ofsFlag = 0x10C4;
|
||||
ofsBP = 0x5BB8;
|
||||
L_UGFlags.Visible = NUD_UGFlags.Visible = false;
|
||||
case SAV4HGSS:
|
||||
GB_Poketch.Visible = false;
|
||||
ofsMap = 0xBAE7;
|
||||
ofsPrints = 0xE7E;
|
||||
PrintIndexStart = 77;
|
||||
BFF = [
|
||||
// { BFV, BFT, addr, 1BFTlen, checkBit
|
||||
[0, 1, 0x5264, 0x04, 0x5BC1],
|
||||
|
@ -67,9 +67,9 @@ public partial class SAV_Misc4 : Form
|
|||
];
|
||||
Hall = SAV.GetHall();
|
||||
break;
|
||||
default: return;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(sav), sav, null);
|
||||
}
|
||||
ofsFly = ofsFlag + 0x136;
|
||||
ReadMain();
|
||||
ReadBattleFrontier();
|
||||
if (SAV is SAV4Sinnoh s)
|
||||
|
@ -78,9 +78,9 @@ public partial class SAV_Misc4 : Form
|
|||
poffinCase4Editor1.Initialize(s);
|
||||
TC_Misc.Controls.Remove(Tab_PokeGear);
|
||||
}
|
||||
else
|
||||
else if (SAV is SAV4HGSS hgss)
|
||||
{
|
||||
pokeGear4Editor1.Initialize((SAV4HGSS)SAV);
|
||||
pokeGear4Editor1.Initialize(hgss);
|
||||
TC_Misc.Controls.Remove(Tab_Poffins);
|
||||
}
|
||||
}
|
||||
|
@ -98,119 +98,76 @@ public partial class SAV_Misc4 : Form
|
|||
Close();
|
||||
}
|
||||
|
||||
private void B_Cancel_Click(object sender, EventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
private void B_Cancel_Click(object sender, EventArgs e) => Close();
|
||||
|
||||
private readonly int ofsFly;
|
||||
private readonly int ofsBP;
|
||||
private readonly int ofsMap = -1;
|
||||
private readonly int ofsUGFlagCount = -1;
|
||||
private int[] FlyDestC = null!;
|
||||
private const int FlyFlagStart = 2480;
|
||||
private static ReadOnlySpan<byte> FlyWorkFlagSinnoh => [000, 001, 002, 003, 004, 005, 006, 007, 008, 009, 010, 011, 012, 013, 014, 015, 016, 017, 067, 068];
|
||||
private static ReadOnlySpan<byte> LocationIDsSinnoh => [001, 002, 003, 004, 005, 082, 083, 006, 007, 008, 009, 010, 011, 012, 013, 014, 054, 081, 055, 015];
|
||||
private static ReadOnlySpan<byte> FlyWorkFlagHGSS => [000, 001, 002, 003, 004, 005, 006, 007, 008, 009, 010, 011, 012, 013, 014, 015, 016, 017, 018, 019, 020, 021, 022, 027, 030, 033, 035];
|
||||
private static ReadOnlySpan<byte> LocationIDsHGSS => [138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 229, 227, 221, 225];
|
||||
|
||||
private void ReadMain()
|
||||
{
|
||||
NUD_Coin.Value = SAV.Coin;
|
||||
NUD_Coin.Maximum = SAV.MaxCoins;
|
||||
int[] FlyDestD;
|
||||
IReadOnlyList<ComboItem> metLocationList;
|
||||
switch (SAV)
|
||||
{
|
||||
case SAV4Sinnoh:
|
||||
metLocationList = GameInfo.GetLocationList(GameVersion.Pt, EntityContext.Gen4, false);
|
||||
FlyDestD = [001, 002, 006, 008, 003, 009, 010, 004, 012, 011, 005, 007, 014, 013, 054, 015, 081, 082, 083, 055];
|
||||
FlyDestC = [000, 001, 007, 009, 002, 010, 011, 003, 013, 012, 004, 008, 015, 014, 016, 068, 017, 005, 006, 067];
|
||||
break;
|
||||
case SAV4HGSS:
|
||||
metLocationList = GameInfo.GetLocationList(GameVersion.HG, EntityContext.Gen4, false);
|
||||
FlyDestD = [126, 127, 128, 129, 131, 133, 132, 130, 134, 135, 136, 227, 229, 137, 221, 147, 138, 139, 140, 141, 143, 142, 144, 148, 145, 146, 225];
|
||||
FlyDestC = [011, 012, 013, 014, 016, 018, 017, 015, 019, 020, 021, 030, 027, 022, 033, 009, 000, 001, 002, 003, 005, 004, 006, 010, 007, 008, 035];
|
||||
break;
|
||||
default: return;
|
||||
}
|
||||
uint valFly = ReadUInt32LittleEndian(SAV.General[ofsFly..]);
|
||||
NUD_Coin.Value = Math.Clamp(SAV.Coin, 0, SAV.MaxCoins);
|
||||
NUD_BP.Value = Math.Clamp(SAV.BP, 0, 9999);
|
||||
|
||||
var locations = SAV is SAV4Sinnoh ? LocationIDsSinnoh : LocationIDsHGSS;
|
||||
var flags = SAV is SAV4Sinnoh ? FlyWorkFlagSinnoh : FlyWorkFlagHGSS;
|
||||
|
||||
CLB_FlyDest.Items.Clear();
|
||||
for (int i = 0; i < FlyDestD.Length; i++)
|
||||
for (int i = 0; i < locations.Length; i++)
|
||||
{
|
||||
var dest = FlyDestD[i];
|
||||
var name = metLocationList.First(v => v.Value == dest).Text;
|
||||
var state = FlyDestC[i] < 32
|
||||
? (valFly & (1u << FlyDestC[i])) != 0
|
||||
: (SAV.General[ofsFly + (FlyDestC[i] >> 3)] & (1 << (FlyDestC[i] & 7))) != 0;
|
||||
var flagIndex = FlyFlagStart + flags[i];
|
||||
var state = SAV.GetEventFlag(flagIndex);
|
||||
|
||||
var locationID = locations[i];
|
||||
var name = GameInfo.Strings.Gen4.Met0[locationID];
|
||||
CLB_FlyDest.Items.Add(name, state);
|
||||
}
|
||||
uint valBP = ReadUInt16LittleEndian(SAV.General[ofsBP..]);
|
||||
NUD_BP.Value = valBP > 9999 ? 9999 : valBP;
|
||||
|
||||
if (SAV is SAV4Sinnoh sinnoh)
|
||||
{
|
||||
ReadPoketch(sinnoh);
|
||||
NUD_UGFlags.Value = Math.Clamp(sinnoh.UG_Flags, 0, 999_999);
|
||||
}
|
||||
else if (SAV is SAV4HGSS hgss)
|
||||
{
|
||||
ReadWalker(hgss);
|
||||
ReadPokeathlon(hgss);
|
||||
}
|
||||
|
||||
if (ofsUGFlagCount > 0)
|
||||
{
|
||||
uint flagCount = ReadUInt32LittleEndian(SAV.General[ofsUGFlagCount..]) & 0xFFFFF;
|
||||
NUD_UGFlags.Value = Math.Clamp(flagCount, 0, 999_999);
|
||||
}
|
||||
if (ofsMap > 0)
|
||||
{
|
||||
string[] items = ["Map Johto", "Map Johto+", "Map Johto & Kanto"];
|
||||
int index = (SAV.General[ofsMap] >> 3) & 3;
|
||||
if (index > 2) index = 2;
|
||||
CB_UpgradeMap.Items.AddRange(items);
|
||||
CB_UpgradeMap.SelectedIndex = index;
|
||||
L_UGFlags.Visible = NUD_UGFlags.Visible = false;
|
||||
ReadOnlySpan<string> items = ["Map Johto", "Map Johto+", "Map Johto & Kanto"];
|
||||
var index = hgss.MapUnlockState;
|
||||
if (index >= MapUnlockState4.Invalid)
|
||||
index = MapUnlockState4.JohtoKanto;
|
||||
foreach (var item in items)
|
||||
CB_UpgradeMap.Items.Add(item);
|
||||
CB_UpgradeMap.SelectedIndex = (int)index;
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveMain()
|
||||
{
|
||||
SAV.Coin = (uint)NUD_Coin.Value;
|
||||
uint valFly = ReadUInt32LittleEndian(SAV.General[ofsFly..]);
|
||||
SAV.BP = (ushort)NUD_BP.Value;
|
||||
|
||||
var flags = SAV is SAV4Sinnoh ? FlyWorkFlagSinnoh : FlyWorkFlagHGSS;
|
||||
for (int i = 0; i < CLB_FlyDest.Items.Count; i++)
|
||||
{
|
||||
if (FlyDestC[i] < 32)
|
||||
{
|
||||
if (CLB_FlyDest.GetItemChecked(i))
|
||||
valFly |= 1u << FlyDestC[i];
|
||||
else
|
||||
valFly &= ~(1u << FlyDestC[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
var o = ofsFly + (FlyDestC[i] >> 3);
|
||||
SAV.General[o] = (byte)((SAV.General[o] & ~(1 << (FlyDestC[i] & 7))) | (CLB_FlyDest.GetItemChecked(i) ? 1 << (FlyDestC[i] & 7) : 0));
|
||||
}
|
||||
var index = FlyFlagStart + flags[i];
|
||||
SAV.SetEventFlag(index, CLB_FlyDest.GetItemChecked(i));
|
||||
}
|
||||
WriteUInt32LittleEndian(SAV.General[ofsFly..], valFly);
|
||||
WriteUInt16LittleEndian(SAV.General[ofsBP..], (ushort)NUD_BP.Value);
|
||||
|
||||
if (SAV is SAV4Sinnoh sinnoh)
|
||||
{
|
||||
SavePoketch(sinnoh);
|
||||
sinnoh.UG_Flags = (uint)NUD_UGFlags.Value;
|
||||
}
|
||||
else if (SAV is SAV4HGSS hgss)
|
||||
{
|
||||
SaveWalker(hgss);
|
||||
SavePokeathlon(hgss);
|
||||
}
|
||||
|
||||
if (ofsUGFlagCount > 0)
|
||||
{
|
||||
var current = ReadUInt32LittleEndian(SAV.General[ofsUGFlagCount..]) & ~0xFFFFFu;
|
||||
var update = current | (uint)NUD_UGFlags.Value;
|
||||
WriteUInt32LittleEndian(SAV.General[ofsUGFlagCount..], update);
|
||||
}
|
||||
if (ofsMap > 0)
|
||||
{
|
||||
int valMap = CB_UpgradeMap.SelectedIndex;
|
||||
if (valMap >= 0)
|
||||
SAV.General[ofsMap] = (byte)((SAV.General[ofsMap] & 0xE7) | (valMap << 3));
|
||||
hgss.MapUnlockState = (MapUnlockState4)CB_UpgradeMap.SelectedIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -221,30 +178,31 @@ public partial class SAV_Misc4 : Form
|
|||
}
|
||||
|
||||
#region Poketch
|
||||
private byte[] DotArtistByte = null!;
|
||||
private static ReadOnlySpan<byte> ColorTable => [ 248, 168, 88, 8 ];
|
||||
private byte[] DotArtistByte = [];
|
||||
|
||||
private void ReadPoketch(SAV4Sinnoh s)
|
||||
{
|
||||
string[] PoketchTitle = Enum.GetNames(typeof(PoketchApp));
|
||||
|
||||
CB_CurrentApp.Items.AddRange(PoketchTitle);
|
||||
CB_CurrentApp.SelectedIndex = s.CurrentPoketchApp;
|
||||
CB_CurrentApp.Items.Clear();
|
||||
CLB_Poketch.Items.Clear();
|
||||
for (int i = 0; i < PoketchTitle.Length; i++)
|
||||
for (PoketchApp i = 0; i <= PoketchApp.Alarm_Clock; i++)
|
||||
{
|
||||
var title = $"{i:00} - {PoketchTitle[i]}";
|
||||
var value = s.GetPoketchAppUnlocked((PoketchApp)i);
|
||||
var name = i.ToString();
|
||||
var title = $"{i:00} - {name}";
|
||||
CB_CurrentApp.Items.Add(name);
|
||||
var value = s.GetPoketchAppUnlocked(i);
|
||||
CLB_Poketch.Items.Add(title, value);
|
||||
}
|
||||
CB_CurrentApp.SelectedIndex = s.CurrentPoketchApp;
|
||||
|
||||
DotArtistByte = s.GetPoketchDotArtistData();
|
||||
SetPictureBoxFromFlags(DotArtistByte);
|
||||
string tip = "Guide about D&D ImageFile Format";
|
||||
tip += Environment.NewLine + " width = 24px";
|
||||
tip += Environment.NewLine + " height = 20px";
|
||||
tip += Environment.NewLine + " used color count <= 4";
|
||||
tip += Environment.NewLine + " file size < 2058byte";
|
||||
const string tip = """
|
||||
Guide about D&D ImageFile Format
|
||||
width = 24px
|
||||
height = 20px
|
||||
used color count <= 4
|
||||
file size < 2058byte
|
||||
""";
|
||||
tip1.SetToolTip(PB_DotArtist, tip);
|
||||
TAB_Main.AllowDrop = true;
|
||||
}
|
||||
|
@ -265,149 +223,33 @@ public partial class SAV_Misc4 : Form
|
|||
|
||||
private void SetPictureBoxFromFlags(ReadOnlySpan<byte> inp)
|
||||
{
|
||||
if (inp.Length != 120)
|
||||
if (inp.Length != DotMatrixPixelCount / 4)
|
||||
return;
|
||||
PB_DotArtist.Image = GetDotArt(inp);
|
||||
}
|
||||
|
||||
private static Bitmap GetDotArt(ReadOnlySpan<byte> inp)
|
||||
private void SetFlagsFromFileName(string fileName)
|
||||
{
|
||||
byte[] dupbyte = new byte[23040];
|
||||
for (int iy = 0; iy < 20; iy++)
|
||||
{
|
||||
for (int ix = 0; ix < 24; ix++)
|
||||
{
|
||||
var ib = ix + (24 * iy);
|
||||
var ict = ColorTable[(inp[ib >> 2] >> ((ib % 4) << 1)) & 3];
|
||||
var iz = (12 * ix) + (0x480 * iy);
|
||||
for (int izy = 0; izy < 4; izy++)
|
||||
{
|
||||
for (int izx = 0; izx < 4; izx++)
|
||||
{
|
||||
for (int ic = 0; ic < 3; ic++)
|
||||
dupbyte[ic + (3 * izx) + (0x120 * izy) + iz] = ict;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Bitmap dabmp = new(96, 80);
|
||||
BitmapData dabdata = dabmp.LockBits(new Rectangle(0, 0, dabmp.Width, dabmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
|
||||
System.Runtime.InteropServices.Marshal.Copy(dupbyte, 0, dabdata.Scan0, dupbyte.Length);
|
||||
dabmp.UnlockBits(dabdata);
|
||||
return dabmp;
|
||||
}
|
||||
|
||||
private void SetFlagsFromFileName(string inpFileName)
|
||||
{
|
||||
if (FileUtil.GetFileSize(inpFileName) > 2058)
|
||||
return; // 24*20*4(ARGB)=1920
|
||||
|
||||
using var bmp = (Bitmap)Image.FromFile(inpFileName);
|
||||
if (bmp.Width != 24 || bmp.Height != 20)
|
||||
return;
|
||||
|
||||
Span<byte> brightMap = stackalloc byte[480];
|
||||
Span<byte> brightCount = stackalloc byte[0x100];
|
||||
Span<byte> iBrightCount = stackalloc byte[0x100];
|
||||
for (int iy = 0; iy < 20; iy++)
|
||||
{
|
||||
for (int ix = 0; ix < 24; ix++)
|
||||
{
|
||||
var ig = (byte)(0xFF * bmp.GetPixel(ix, iy).GetBrightness());
|
||||
brightMap[ix + (24 * iy)] = ig;
|
||||
brightCount[ig]++;
|
||||
}
|
||||
}
|
||||
|
||||
int colorCount = 0;
|
||||
foreach (var value in brightCount)
|
||||
{
|
||||
if (value > 0)
|
||||
++colorCount;
|
||||
}
|
||||
|
||||
if (colorCount is 0 or > 4)
|
||||
return;
|
||||
int errorsMin = int.MaxValue;
|
||||
Span<byte> LCT = stackalloc byte[4];
|
||||
Span<byte> mLCT = stackalloc byte[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
LCT[i] = (byte)(colorCount < i + 1 ? 4 : colorCount - i - 1);
|
||||
int ee = 0;
|
||||
while (++ee < 1000)
|
||||
{
|
||||
brightCount.CopyTo(iBrightCount);
|
||||
for (int i = 0, j = 0; i < 0x100; i++)
|
||||
{
|
||||
if (iBrightCount[i] > 0)
|
||||
iBrightCount[i] = LCT[j++];
|
||||
}
|
||||
|
||||
var errorsTotal = 0;
|
||||
for (int i = 0; i < 480; i++)
|
||||
errorsTotal += Math.Abs(brightMap[i] - ColorTable[iBrightCount[brightMap[i]]]);
|
||||
if (errorsMin > errorsTotal)
|
||||
{
|
||||
errorsMin = errorsTotal;
|
||||
LCT.CopyTo(mLCT);
|
||||
}
|
||||
GetNextLCT(LCT);
|
||||
if (LCT[0] >= 4)
|
||||
break;
|
||||
}
|
||||
for (int i = 0, j = 0; i < 0x100; i++)
|
||||
{
|
||||
if (brightCount[i] > 0)
|
||||
brightCount[i] = mLCT[j++];
|
||||
}
|
||||
|
||||
for (int i = 0; i < 480; i++)
|
||||
brightMap[i] = brightCount[brightMap[i]];
|
||||
|
||||
Span<byte> ndab = stackalloc byte[120];
|
||||
for (int i = 0; i < 480; i++)
|
||||
ndab[i >> 2] |= (byte)((brightMap[i] & 3) << ((i % 4) << 1));
|
||||
|
||||
ndab.CopyTo(DotArtistByte.AsSpan(0));
|
||||
}
|
||||
|
||||
private static void GetNextLCT(Span<byte> inp)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (++inp[0] < 4)
|
||||
continue;
|
||||
|
||||
inp[0] = 0;
|
||||
if (++inp[1] < 4)
|
||||
continue;
|
||||
|
||||
inp[1] = 0;
|
||||
if (++inp[2] < 4)
|
||||
continue;
|
||||
|
||||
inp[2] = 0;
|
||||
if (++inp[3] < 4)
|
||||
continue;
|
||||
|
||||
inp[0] = 4;
|
||||
return;
|
||||
}
|
||||
var dest = DotArtistByte;
|
||||
PoketchDotMatrix.TryBuild(fileName, dest);
|
||||
}
|
||||
|
||||
private void SetFlagsFromClickPoint(int inpX, int inpY)
|
||||
{
|
||||
inpX = Math.Clamp(inpX, 0, 95);
|
||||
inpY = Math.Clamp(inpY, 0, 79);
|
||||
int i = (inpX >> 2) + (24 * (inpY >> 2));
|
||||
byte[] ndab = new byte[120];
|
||||
DotArtistByte.CopyTo(ndab, 0);
|
||||
inpX = Math.Clamp(inpX, 0, (DotMatrixWidth * DotMatrixUpscaleFactor) - 1);
|
||||
inpY = Math.Clamp(inpY, 0, (DotMatrixHeight * DotMatrixUpscaleFactor) - 1);
|
||||
int i = (inpX >> 2) + (DotMatrixWidth * (inpY >> 2));
|
||||
Span<byte> ndab = stackalloc byte[DotMatrixPixelCount / 4];
|
||||
DotArtistByte.AsSpan().CopyTo(ndab);
|
||||
|
||||
byte c = (byte)((ndab[i >> 2] >> ((i % 4) << 1)) & 3);
|
||||
if (++c >= 4) c = 0;
|
||||
if (++c >= 4)
|
||||
c = 0;
|
||||
|
||||
ndab[i >> 2] &= (byte)~(3 << ((i % 4) << 1));
|
||||
ndab[i >> 2] |= (byte)((c & 3) << ((i % 4) << 1));
|
||||
ndab.CopyTo(DotArtistByte, 0);
|
||||
|
||||
ndab.CopyTo(DotArtistByte);
|
||||
}
|
||||
|
||||
private void B_GiveAll_Click(object sender, EventArgs e)
|
||||
|
@ -446,19 +288,17 @@ public partial class SAV_Misc4 : Form
|
|||
#endregion
|
||||
|
||||
#region BattleFrontier
|
||||
private int[] Prints = null!;
|
||||
private readonly int ofsPrints = -1;
|
||||
private Color[] PrintColorA = null!;
|
||||
private Button[] PrintButtonA = null!;
|
||||
private readonly RadioButton[] StatRBA;
|
||||
private readonly NumericUpDown[] StatNUDA;
|
||||
private readonly Label[] StatLabelA;
|
||||
private readonly NumericUpDown[] HallNUDA;
|
||||
private readonly Button[] PrintButtonA;
|
||||
private readonly int[][] BFF;
|
||||
private readonly int PrintIndexStart;
|
||||
|
||||
private bool editing;
|
||||
private RadioButton[] StatRBA = null!;
|
||||
private NumericUpDown[] StatNUDA = null!;
|
||||
private Label[] StatLabelA = null!;
|
||||
private readonly int[][] BFF = null!;
|
||||
private string[][] BFT = null!;
|
||||
private int[][] BFV = null!;
|
||||
private string[] BFN = null!;
|
||||
private NumericUpDown[] HallNUDA = null!;
|
||||
private bool HallStatUpdated;
|
||||
|
||||
private void ReadBattleFrontier()
|
||||
|
@ -472,28 +312,13 @@ public partial class SAV_Misc4 : Form
|
|||
["Singles", "Doubles", "Multi"],
|
||||
["Singles", "Doubles", "Multi (Trainer)", "Multi (Friend)", "Wi-Fi"],
|
||||
];
|
||||
BFN = ["Tower", "Factory", "Hall", "Castle", "Arcade"];
|
||||
if (SAV is SAV4DP) BFN = BFN.Take(1).ToArray();
|
||||
StatNUDA = [NUD_Stat0, NUD_Stat1, NUD_Stat2, NUD_Stat3];
|
||||
StatLabelA = [L_Stat0, L_Stat1, L_Stat2, L_Stat3];
|
||||
StatRBA = [RB_Stats3_01, RB_Stats3_02];
|
||||
|
||||
if (ofsPrints > 0)
|
||||
if (SAV is not SAV4DP)
|
||||
{
|
||||
PrintColorA = [Color.Transparent, Color.Silver, Color.Gold];
|
||||
PrintButtonA = [BTN_PrintTower, BTN_PrintFactory, BTN_PrintHall, BTN_PrintCastle, BTN_PrintArcade];
|
||||
Prints = new int[PrintButtonA.Length];
|
||||
for (int i = 0; i < Prints.Length; i++)
|
||||
Prints[i] = 1 + Math.Sign((ReadUInt16LittleEndian(SAV.General[(ofsPrints + (i << 1))..]) >> 1) - 1);
|
||||
SetPrints();
|
||||
SetPrintColors(PrintButtonA);
|
||||
|
||||
HallNUDA = [
|
||||
NUD_HallType01, NUD_HallType02, NUD_HallType03, NUD_HallType04, NUD_HallType05, NUD_HallType06,
|
||||
NUD_HallType07, NUD_HallType08, NUD_HallType09, NUD_HallType10, NUD_HallType11, NUD_HallType12,
|
||||
NUD_HallType13, NUD_HallType14, NUD_HallType15, NUD_HallType16, NUD_HallType17,
|
||||
];
|
||||
string[] typeNames = GameInfo.Strings.types;
|
||||
int[] typenameIndex = [0, 9, 10, 12, 11, 14, 1, 3, 4, 2, 13, 6, 5, 7, 15, 16, 8];
|
||||
ReadOnlySpan<string> typeNames = GameInfo.Strings.types;
|
||||
ReadOnlySpan<byte> typenameIndex = [0, 9, 10, 12, 11, 14, 1, 3, 4, 2, 13, 6, 5, 7, 15, 16, 8];
|
||||
for (int i = 0; i < HallNUDA.Length; i++)
|
||||
tip2.SetToolTip(HallNUDA[i], typeNames[typenameIndex[i]]);
|
||||
}
|
||||
|
@ -502,8 +327,8 @@ public partial class SAV_Misc4 : Form
|
|||
|
||||
editing = true;
|
||||
CB_Stats1.Items.Clear();
|
||||
foreach (string t in BFN)
|
||||
CB_Stats1.Items.Add(t);
|
||||
for (BattleFrontierFacility4 i = 0; i <= SAV.MaxFacility; i++)
|
||||
CB_Stats1.Items.Add(i.ToString());
|
||||
StatRBA[0].Checked = true;
|
||||
|
||||
// Clear Listbox and ComboBox
|
||||
|
@ -521,25 +346,37 @@ public partial class SAV_Misc4 : Form
|
|||
|
||||
private void SaveBattleFrontier()
|
||||
{
|
||||
if (ofsPrints > 0)
|
||||
{
|
||||
for (int i = 0; i < Prints.Length; i++)
|
||||
{
|
||||
if (Prints[i] == 1 + Math.Sign((ReadUInt16LittleEndian(SAV.General[(ofsPrints + (i << 1))..]) >> 1) - 1))
|
||||
continue;
|
||||
var value = Prints[i] << 1;
|
||||
WriteInt32LittleEndian(SAV.General[(ofsPrints + (i << 1))..], value);
|
||||
}
|
||||
}
|
||||
|
||||
if (HallStatUpdated)
|
||||
Hall?.RefreshChecksum();
|
||||
}
|
||||
|
||||
private void SetPrints()
|
||||
private void SetPrintColors(ReadOnlySpan<Control> controls)
|
||||
{
|
||||
for (int i = 0; i < PrintButtonA.Length; i++)
|
||||
PrintButtonA[i].BackColor = PrintColorA[Prints[i]];
|
||||
for (int i = 0; i < controls.Length; i++)
|
||||
{
|
||||
var pb = controls[i];
|
||||
var workIndex = PrintIndexStart + i;
|
||||
var value = SAV.GetWork(workIndex);
|
||||
SetPrintColor(pb, (BattleFrontierPrintStatus4)value);
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetPrintColor(Control pb, BattleFrontierPrintStatus4 value)
|
||||
{
|
||||
bool ready = value is BattleFrontierPrintStatus4.FirstReady or BattleFrontierPrintStatus4.SecondReady;
|
||||
if (ready)
|
||||
pb.ForeColor = Color.Red;
|
||||
else if (value != 0)
|
||||
pb.ForeColor = Color.Green;
|
||||
else
|
||||
pb.ResetForeColor();
|
||||
|
||||
if (value is BattleFrontierPrintStatus4.FirstReady or BattleFrontierPrintStatus4.FirstReceived)
|
||||
pb.BackColor = Color.Silver;
|
||||
else if (value is BattleFrontierPrintStatus4.SecondReady or BattleFrontierPrintStatus4.SecondReceived)
|
||||
pb.BackColor = Color.Gold;
|
||||
else
|
||||
pb.ResetBackColor();
|
||||
}
|
||||
|
||||
private void BTN_Print_Click(object sender, EventArgs e)
|
||||
|
@ -549,8 +386,14 @@ public partial class SAV_Misc4 : Form
|
|||
int index = Array.IndexOf(PrintButtonA, b);
|
||||
if (index < 0)
|
||||
return;
|
||||
Prints[index] = (Prints[index] + 1) % 3;
|
||||
SetPrints();
|
||||
index += PrintIndexStart;
|
||||
var current = SAV.GetWork(index);
|
||||
current++;
|
||||
if (current > (int)BattleFrontierPrintStatus4.SecondReceived)
|
||||
current = 0;
|
||||
SAV.SetWork(index, current);
|
||||
|
||||
SetPrintColor(b, (BattleFrontierPrintStatus4)current);
|
||||
}
|
||||
|
||||
private void ChangeStat1(object sender, EventArgs e)
|
||||
|
@ -579,11 +422,16 @@ public partial class SAV_Misc4 : Form
|
|||
}
|
||||
else
|
||||
{
|
||||
if (StatNUDA[1].Value > 9999) StatNUDA[1].Value = 9999;
|
||||
if (StatNUDA[1].Value > 9999)
|
||||
StatNUDA[1].Value = 9999;
|
||||
StatNUDA[1].Maximum = 9999;
|
||||
}
|
||||
if (facility == 1) StatLabelA[1].Text = StatLabelA[3].Text = "Trade";
|
||||
if (facility == 3) StatLabelA[1].Text = StatLabelA[3].Text = "CP";
|
||||
|
||||
if (facility == 1)
|
||||
StatLabelA[1].Text = StatLabelA[3].Text = "Trade";
|
||||
else if (facility == 3)
|
||||
StatLabelA[1].Text = StatLabelA[3].Text = "CP";
|
||||
|
||||
GB_Hall.Visible = facility == 2;
|
||||
GB_Castle.Visible = facility == 3;
|
||||
|
||||
|
@ -624,19 +472,21 @@ public partial class SAV_Misc4 : Form
|
|||
byte maskFlag = (byte)(1 << (BattleType + (RBi << 2)));
|
||||
int TowerContinueCountOfs = SAV is SAV4DP ? 3 : 1;
|
||||
|
||||
var general = SAV.General;
|
||||
if (SetSavToVal)
|
||||
{
|
||||
editing = true;
|
||||
for (int i = 0; i < BFV[BFF[Facility][0]].Length; i++)
|
||||
{
|
||||
if (BFV[BFF[Facility][0]][i] < 0) continue;
|
||||
int vali = ReadUInt16LittleEndian(SAV.General[(addrVal + (i << 1))..]);
|
||||
if (BFV[BFF[Facility][0]][i] < 0)
|
||||
continue;
|
||||
int vali = ReadUInt16LittleEndian(general[(addrVal + (i << 1))..]);
|
||||
StatNUDA[BFV[BFF[Facility][0]][i]].Value = vali > 9999 ? 9999 : vali;
|
||||
}
|
||||
CHK_Continue.Checked = (SAV.General[addrFlag] & maskFlag) != 0;
|
||||
|
||||
if (Facility == 0) // tower continue count
|
||||
StatNUDA[1].Value = ReadUInt16LittleEndian(SAV.General[(addrFlag + TowerContinueCountOfs + (BattleType << 1))..]);
|
||||
StatNUDA[1].Value = ReadUInt16LittleEndian(general[(addrFlag + TowerContinueCountOfs + (BattleType << 1))..]);
|
||||
|
||||
editing = false;
|
||||
return;
|
||||
|
@ -648,26 +498,27 @@ public partial class SAV_Misc4 : Form
|
|||
if (Facility == 0 && SetValToSav == 1) // tower continue count
|
||||
{
|
||||
var offset = addrFlag + TowerContinueCountOfs + (BattleType << 1);
|
||||
WriteUInt16LittleEndian(SAV.General[offset..], val);
|
||||
WriteUInt16LittleEndian(general[offset..], val);
|
||||
}
|
||||
|
||||
SetValToSav = Array.IndexOf(BFV[BFF[Facility][0]], SetValToSav);
|
||||
if (SetValToSav < 0)
|
||||
return;
|
||||
var clamp = Math.Min((ushort)9999, val);
|
||||
WriteUInt16LittleEndian(SAV.General[(addrVal + (SetValToSav << 1))..], clamp);
|
||||
WriteUInt16LittleEndian(general[(addrVal + (SetValToSav << 1))..], clamp);
|
||||
return;
|
||||
}
|
||||
if (SetValToSav == -1)
|
||||
{
|
||||
if (CHK_Continue.Checked)
|
||||
{
|
||||
SAV.General[addrFlag] |= maskFlag;
|
||||
if (Facility == 3) SAV.General[addrFlag + 1] |= 0x01; // not found what this flag means
|
||||
general[addrFlag] |= maskFlag;
|
||||
if (Facility == 3)
|
||||
general[addrFlag + 1] |= 0x01; // not found what this flag means
|
||||
}
|
||||
else
|
||||
{
|
||||
SAV.General[addrFlag] &= (byte)~maskFlag;
|
||||
general[addrFlag] &= (byte)~maskFlag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -676,24 +527,32 @@ public partial class SAV_Misc4 : Form
|
|||
{
|
||||
if (editing)
|
||||
return;
|
||||
|
||||
int n = Array.IndexOf(StatNUDA, sender);
|
||||
if (n < 0)
|
||||
return;
|
||||
|
||||
StatAddrControl(SetValToSav: n, SetSavToVal: false);
|
||||
|
||||
if (CB_Stats1.SelectedIndex == 0 && Math.Floor(StatNUDA[0].Value / 7) != StatNUDA[1].Value)
|
||||
if (CB_Stats1.SelectedIndex != 0)
|
||||
return;
|
||||
|
||||
const int bias = 7;
|
||||
var n0 = StatNUDA[0];
|
||||
var n1 = StatNUDA[1];
|
||||
if (Math.Floor(n0.Value / bias) == n1.Value)
|
||||
return;
|
||||
|
||||
if (n == 0)
|
||||
{
|
||||
if (n == 0)
|
||||
{
|
||||
StatNUDA[1].Value = Math.Floor(StatNUDA[0].Value / 7);
|
||||
}
|
||||
else if (n == 1)
|
||||
{
|
||||
if (StatNUDA[0].Maximum > StatNUDA[1].Value * 7)
|
||||
StatNUDA[0].Value = StatNUDA[1].Value * 7;
|
||||
else if (StatNUDA[0].Value < StatNUDA[0].Maximum)
|
||||
StatNUDA[0].Value = StatNUDA[0].Maximum;
|
||||
}
|
||||
n1.Value = Math.Floor(n0.Value / bias);
|
||||
}
|
||||
else if (n == 1)
|
||||
{
|
||||
if (n0.Maximum > n1.Value * bias)
|
||||
n0.Value = n1.Value * bias;
|
||||
else if (n0.Value < n0.Maximum)
|
||||
n0.Value = n0.Maximum;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -711,6 +570,7 @@ public partial class SAV_Misc4 : Form
|
|||
species = (ushort)WinFormsUtil.GetIndex(CB_Species);
|
||||
if (editing)
|
||||
return;
|
||||
|
||||
editing = true;
|
||||
GetHallStat();
|
||||
editing = false;
|
||||
|
@ -747,7 +607,7 @@ public partial class SAV_Misc4 : Form
|
|||
CHK_HallCurrent.Checked = c;
|
||||
CHK_HallCurrent.Text = curspe > 0 && curspe <= SAV.MaxSpeciesID
|
||||
? $"Current: {SpeciesName.GetSpeciesName(curspe, GameLanguage.GetLanguageIndex(Main.CurrentLanguage))}"
|
||||
: "Current: (none)";
|
||||
: "Current: (None)";
|
||||
|
||||
int s = 0;
|
||||
for (int i = 0; i < HallNUDA.Length; i++)
|
||||
|
@ -801,34 +661,48 @@ public partial class SAV_Misc4 : Form
|
|||
|
||||
private void ReadWalker(SAV4HGSS s)
|
||||
{
|
||||
string[] walkercourses = GameInfo.Sources.Strings.walkercourses;
|
||||
bool[] isChecked = s.GetPokewalkerCoursesUnlocked();
|
||||
ReadOnlySpan<string> walkercourses = GameInfo.Sources.Strings.walkercourses;
|
||||
CLB_WalkerCourses.Items.Clear();
|
||||
for (int i = 0; i < walkercourses.Length; i++)
|
||||
CLB_WalkerCourses.Items.Add(walkercourses[i], isChecked[i]);
|
||||
foreach (var name in walkercourses)
|
||||
CLB_WalkerCourses.Items.Add(name);
|
||||
|
||||
ReadWalkerCourseUnlockFlags(s);
|
||||
|
||||
NUD_Watts.Value = s.PokewalkerWatts;
|
||||
NUD_Steps.Value = s.PokewalkerSteps;
|
||||
}
|
||||
|
||||
private void ReadWalkerCourseUnlockFlags(SAV4HGSS s)
|
||||
{
|
||||
Span<bool> courses = stackalloc bool[SAV4HGSS.PokewalkerCourseFlagCount];
|
||||
s.GetPokewalkerCoursesUnlocked(courses);
|
||||
for (int i = 0; i < CLB_WalkerCourses.Items.Count; i++)
|
||||
CLB_WalkerCourses.SetItemChecked(i, courses[i]);
|
||||
}
|
||||
|
||||
private void SaveWalker(SAV4HGSS s)
|
||||
{
|
||||
Span<bool> courses = stackalloc bool[32];
|
||||
Span<bool> courses = stackalloc bool[SAV4HGSS.PokewalkerCourseFlagCount];
|
||||
for (int i = 0; i < CLB_WalkerCourses.Items.Count; i++)
|
||||
courses[i] = CLB_WalkerCourses.GetItemChecked(i);
|
||||
s.SetPokewalkerCoursesUnlocked(courses);
|
||||
|
||||
s.PokewalkerWatts = (uint)NUD_Watts.Value;
|
||||
s.PokewalkerSteps = (uint)NUD_Steps.Value;
|
||||
}
|
||||
|
||||
private void B_AllWalkerCourses_Click(object sender, EventArgs e)
|
||||
{
|
||||
for (int i = 0; i < CLB_WalkerCourses.Items.Count; i++)
|
||||
CLB_WalkerCourses.SetItemChecked(i, true);
|
||||
if (SAV is not SAV4HGSS s)
|
||||
throw new Exception("Invalid SAV type");
|
||||
s.PokewalkerCoursesUnlockAll();
|
||||
ReadWalkerCourseUnlockFlags(s);
|
||||
}
|
||||
|
||||
private void OnBAllSealsLegalOnClick(object sender, EventArgs e)
|
||||
{
|
||||
SAV.SetAllSeals(99, sender == B_AllSealsIllegal);
|
||||
bool setUnreleasedIndexes = sender == B_AllSealsIllegal;
|
||||
SAV.SetAllSeals(SAV4.SealMaxCount, setUnreleasedIndexes);
|
||||
System.Media.SystemSounds.Asterisk.Play();
|
||||
}
|
||||
|
||||
|
@ -842,3 +716,143 @@ public partial class SAV_Misc4 : Form
|
|||
s.PokeathlonPoints = (uint)NUD_PokeathlonPoints.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PoketchDotMatrix
|
||||
{
|
||||
public const int DotMatrixHeight = 20;
|
||||
public const int DotMatrixWidth = 24;
|
||||
public const int DotMatrixPixelCount = DotMatrixHeight * DotMatrixWidth;
|
||||
|
||||
public static ReadOnlySpan<byte> ColorTable => [248, 168, 88, 8];
|
||||
|
||||
public static bool TryBuild(string fileName, Span<byte> result)
|
||||
{
|
||||
if (FileUtil.GetFileSize(fileName) > 0x80A)
|
||||
return false;
|
||||
|
||||
using var bmp = (Bitmap)Image.FromFile(fileName);
|
||||
if (bmp.Width != DotMatrixWidth || bmp.Height != DotMatrixHeight)
|
||||
return false;
|
||||
|
||||
Span<byte> brightMap = stackalloc byte[DotMatrixPixelCount];
|
||||
Span<byte> brightCount = stackalloc byte[0x100];
|
||||
if (!TryBuildBrightMap(bmp, brightMap, brightCount, out int colorCount))
|
||||
return false;
|
||||
|
||||
Build(colorCount, brightCount, brightMap, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool TryBuildBrightMap(Bitmap bmp, Span<byte> brightMap, Span<byte> brightCount, out int colorCount)
|
||||
{
|
||||
for (int iy = 0; iy < DotMatrixHeight; iy++) // Height
|
||||
{
|
||||
for (int ix = 0; ix < DotMatrixWidth; ix++) // Width
|
||||
{
|
||||
var ig = (byte)(0xFF * bmp.GetPixel(ix, iy).GetBrightness());
|
||||
brightMap[ix + (DotMatrixWidth * iy)] = ig;
|
||||
brightCount[ig]++;
|
||||
}
|
||||
}
|
||||
colorCount = brightCount.Length - brightCount.Count<byte>(0);
|
||||
return (colorCount - 1) <= 3; // 1-4
|
||||
}
|
||||
|
||||
private static void Build(int colorCount, Span<byte> brightCount, Span<byte> brightMap, Span<byte> result)
|
||||
{
|
||||
int errorsMin = int.MaxValue;
|
||||
Span<byte> LCT = stackalloc byte[4];
|
||||
for (int i = 0; i < LCT.Length; i++)
|
||||
LCT[i] = (byte)(colorCount < i + 1 ? 4 : colorCount - i - 1);
|
||||
|
||||
Span<byte> mLCT = stackalloc byte[4];
|
||||
Span<byte> iBrightCount = stackalloc byte[0x100];
|
||||
int ee = 0;
|
||||
while (++ee < 1000)
|
||||
{
|
||||
brightCount.CopyTo(iBrightCount);
|
||||
for (int i = 0, j = 0; i < iBrightCount.Length; i++)
|
||||
{
|
||||
if (iBrightCount[i] > 0)
|
||||
iBrightCount[i] = LCT[j++];
|
||||
}
|
||||
|
||||
var errorsTotal = 0;
|
||||
for (int i = 0; i < DotMatrixPixelCount; i++)
|
||||
errorsTotal += Math.Abs(brightMap[i] - ColorTable[iBrightCount[brightMap[i]]]);
|
||||
if (errorsMin > errorsTotal)
|
||||
{
|
||||
errorsMin = errorsTotal;
|
||||
LCT.CopyTo(mLCT);
|
||||
}
|
||||
GetNextLCT(LCT);
|
||||
if (LCT[0] >= 4)
|
||||
break;
|
||||
}
|
||||
for (int i = 0, j = 0; i < brightCount.Length; i++)
|
||||
{
|
||||
if (brightCount[i] > 0)
|
||||
brightCount[i] = mLCT[j++];
|
||||
}
|
||||
|
||||
for (int i = 0; i < brightMap.Length; i++)
|
||||
brightMap[i] = brightCount[brightMap[i]];
|
||||
|
||||
for (int i = 0; i < brightMap.Length; i++)
|
||||
result[i >> 2] |= (byte)((brightMap[i] & 3) << ((i % 4) << 1));
|
||||
}
|
||||
|
||||
private static void GetNextLCT(Span<byte> inp)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (++inp[0] < 4)
|
||||
continue;
|
||||
|
||||
inp[0] = 0;
|
||||
if (++inp[1] < 4)
|
||||
continue;
|
||||
|
||||
inp[1] = 0;
|
||||
if (++inp[2] < 4)
|
||||
continue;
|
||||
|
||||
inp[2] = 0;
|
||||
if (++inp[3] < 4)
|
||||
continue;
|
||||
|
||||
inp[0] = 4;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public const int DotMatrixUpscaleFactor = 4;
|
||||
|
||||
public static Bitmap GetDotArt(ReadOnlySpan<byte> inp)
|
||||
{
|
||||
byte[] dupbyte = new byte[23040];
|
||||
for (int iy = 0; iy < DotMatrixHeight; iy++)
|
||||
{
|
||||
for (int ix = 0; ix < DotMatrixWidth; ix++)
|
||||
{
|
||||
var ib = ix + (DotMatrixWidth * iy);
|
||||
var ict = ColorTable[(inp[ib >> 2] >> ((ib % 4) << 1)) & 3];
|
||||
var iz = (12 * ix) + (0x480 * iy);
|
||||
for (int izy = 0; izy < 4; izy++)
|
||||
{
|
||||
for (int izx = 0; izx < 4; izx++)
|
||||
{
|
||||
for (int ic = 0; ic < 3; ic++)
|
||||
dupbyte[ic + (3 * izx) + (0x120 * izy) + iz] = ict;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var dabmp = new Bitmap(DotMatrixWidth * DotMatrixUpscaleFactor, DotMatrixHeight * DotMatrixUpscaleFactor);
|
||||
var dabdata = dabmp.LockBits(new Rectangle(0, 0, dabmp.Width, dabmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
|
||||
System.Runtime.InteropServices.Marshal.Copy(dupbyte, 0, dabdata.Scan0, dupbyte.Length);
|
||||
dabmp.UnlockBits(dabdata);
|
||||
return dabmp;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,9 +18,9 @@ public partial class SettingsEditor : Form
|
|||
|
||||
if (obj is PKHeXSettings s)
|
||||
{
|
||||
GameVersion[] noSelectVersions = [GameVersion.GO, 0];
|
||||
static bool IsInvalidSaveFileVersion(GameVersion value) => value is 0 or GameVersion.GO;
|
||||
CB_Blank.InitializeBinding();
|
||||
CB_Blank.DataSource = GameInfo.VersionDataSource.Where(z => !noSelectVersions.Contains((GameVersion)z.Value)).ToList();
|
||||
CB_Blank.DataSource = GameInfo.VersionDataSource.Where(z => !IsInvalidSaveFileVersion((GameVersion)z.Value)).ToList();
|
||||
CB_Blank.SelectedValue = (int)s.Startup.DefaultSaveVersion;
|
||||
CB_Blank.SelectedValueChanged += (_, _) => s.Startup.DefaultSaveVersion = (GameVersion)WinFormsUtil.GetIndex(CB_Blank);
|
||||
CB_Blank.SelectedIndexChanged += (_, _) => BlankChanged = true;
|
||||
|
|
Loading…
Reference in a new issue