Skip to content

Commit

Permalink
Add Handling for Event Outbreak reading/editing (#84)
Browse files Browse the repository at this point in the history
  • Loading branch information
Manu098vm committed Aug 7, 2024
2 parents 4707473 + 5286f7d commit 6dbd8ec
Show file tree
Hide file tree
Showing 9 changed files with 2,899 additions and 380 deletions.
2,460 changes: 2,172 additions & 288 deletions TeraFinder.Core/Classes/DataBlocks.cs

Large diffs are not rendered by default.

218 changes: 218 additions & 0 deletions TeraFinder.Core/Classes/EventMassOutbreak.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
using PKHeX.Core;
using System.Text.Json.Nodes;
using System.Text.Json;

namespace TeraFinder.Core;

public class EventMassOutbreak : IOutbreak
{
protected int ID { get; init; }
protected SAV9SV SAV { get; init; }
protected string LocationMap { get; init; }

public GameCoordinates? LocationCenter { get; set; }
public GameCoordinates? LocationDummy { get; set; }
public sbyte AmountAvailable { get => GetAmountAvailable(); set => SetAmountAvailable(value); }
public bool Found { get => GetFound(); set => SetFound(value); }
public bool Enabled { get => GetEnabled(); set => SetEnabled(value); }
public uint Species { get => GetSpecies(); set => SetSpecies(value); }
public byte Form { get => GetForm(); set => SetForm(value); }
public int NumKO { get => GetNumKO(); set => SetNumKO(value); }
public int MaxSpawns { get => GetMaxSpawns(); set => SetMaxSpawns(value); }

public EventMassOutbreak(SAV9SV sav, int id, TeraRaidMapParent map)
{
ID = id;
SAV = sav;
LocationMap = map switch { TeraRaidMapParent.Kitakami => "DLC1", TeraRaidMapParent.Blueberry => "DLC2", _ => "Main" };

var blockInfo = (BlockDefinition)typeof(BlockDefinitions).GetField($"KOutbreakBC{ID:00}{LocationMap}CenterPos")!.GetValue(new BlockDefinition())!;
var block = sav.Accessor.GetBlockSafe(blockInfo.Key);

if (block.Type is SCTypeCode.Array)
LocationCenter = new GameCoordinates(block);
else
LocationCenter = null;

blockInfo = (BlockDefinition)typeof(BlockDefinitions).GetField($"KOutbreakBC{ID:00}{LocationMap}DummyPos")!.GetValue(new BlockDefinition())!;
block = sav.Accessor.GetBlockSafe(blockInfo.Key);

if (block.Type is SCTypeCode.Array)
LocationDummy = new GameCoordinates(block);
else
LocationDummy = null;
}


public FakeOutbreak Clone() => new(this);

public void DumpTojson(string path)
{
if (LocationCenter is not null && LocationDummy is not null)
{
var json = "{\n" +
"\t\"LocationCenter\": \"" + BitConverter.ToString([.. LocationCenter.GetCoordinates()]).Replace("-", string.Empty) + "\",\n" +
"\t\"LocationDummy\": \"" + BitConverter.ToString([.. LocationDummy.GetCoordinates()]).Replace("-", string.Empty) + "\",\n" +
"\t\"Species\": " + SpeciesConverter.GetNational9((ushort)Species) + ",\n" +
"\t\"Form\": " + Form + ",\n" +
"\t\"MaxSpawns\": " + MaxSpawns + "\n" +
"}";

File.WriteAllText(path, json);
}
}

public void RestoreFromJson(string json)
{
var simpleOutbreak = JsonSerializer.Deserialize<JsonNode>(json)!;
var locationCenter = Convert.FromHexString(simpleOutbreak[nameof(LocationCenter)]!.GetValue<string>());
var locationDummy = Convert.FromHexString(simpleOutbreak[nameof(LocationDummy)]!.GetValue<string>());
var species = SpeciesConverter.GetInternal9(simpleOutbreak[nameof(Species)]!.GetValue<ushort>());
var form = simpleOutbreak[nameof(Form)]!.GetValue<byte>();
var maxSpawns = simpleOutbreak[nameof(MaxSpawns)]!.GetValue<int>();

LocationCenter!.SetCoordinates(locationCenter);
LocationDummy!.SetCoordinates(locationDummy);
Species = species;
Form = form;
MaxSpawns = maxSpawns;
}

private sbyte GetAmountAvailable()
{
var info = LocationMap switch { "DLC1" => BlockDefinitions.KOutbreakBCDLC1NumActive, "DLC2" => BlockDefinitions.KOutbreakBCDLC2NumActive, _ => BlockDefinitions.KOutbreakBCMainNumActive };
var block = SAV.Accessor.GetBlockSafe(info.Key);

if (block.Type is SCTypeCode.SByte)
return (sbyte)block.GetValue();

return 0;
}

private void SetAmountAvailable(sbyte value)
{
var info = LocationMap switch { "DLC1" => BlockDefinitions.KOutbreakBCDLC1NumActive, "DLC2" => BlockDefinitions.KOutbreakBCDLC2NumActive, _ => BlockDefinitions.KOutbreakBCMainNumActive };
var block = SAV.Accessor.GetBlockSafe(info.Key);

if (block.Type is SCTypeCode.SByte)
block.ChangeData((new byte[] { (byte)value }).AsSpan());
}

private bool GetEnabled()
{
return ID <= AmountAvailable;
}

private void SetEnabled(bool value)
{
if (value && AmountAvailable < ID)
AmountAvailable = (sbyte)ID;
else if (!value && AmountAvailable >= ID)
AmountAvailable = (sbyte)(ID - 1);
}

private bool GetFound()
{
var blockInfo = (BlockDefinition)typeof(BlockDefinitions).GetField($"KOutbreakBC{ID:00}{LocationMap}Found")!.GetValue(new BlockDefinition())!;
var block = SAV.Accessor.FindOrDefault(blockInfo.Key);

if (block.Type.IsBoolean() && block.Type is SCTypeCode.Bool2)
return true;

return false;
}

private void SetFound(bool value)
{
var blockInfo = (BlockDefinition)typeof(BlockDefinitions).GetField($"KOutbreakBC{ID:00}{LocationMap}Found")!.GetValue(new BlockDefinition())!; ;
var block = SAV.Accessor.FindOrDefault(blockInfo.Key);

if (block.Type.IsBoolean())
{
if (value)
block.ChangeBooleanType(SCTypeCode.Bool2);
else
block.ChangeBooleanType(SCTypeCode.Bool1);
}
}

private uint GetSpecies()
{
var blockInfo = (BlockDefinition)typeof(BlockDefinitions).GetField($"KOutbreakBC{ID:00}{LocationMap}Species")!.GetValue(new BlockDefinition())!;
var block = SAV.Accessor.GetBlockSafe(blockInfo.Key);

if (block.Type is SCTypeCode.UInt32)
return (uint)block.GetValue();

return 0;
}

private void SetSpecies(uint value)
{
var blockInfo = (BlockDefinition)typeof(BlockDefinitions).GetField($"KOutbreakBC{ID:00}{LocationMap}Species")!.GetValue(new BlockDefinition())!; ;
var block = SAV.Accessor.GetBlockSafe(blockInfo.Key);

if (block.Type is SCTypeCode.UInt32)
block.SetValue(value);
}

private byte GetForm()
{
var blockInfo = (BlockDefinition)typeof(BlockDefinitions).GetField($"KOutbreakBC{ID:00}{LocationMap}Form")!.GetValue(new BlockDefinition())!;
var block = SAV.Accessor.GetBlockSafe(blockInfo.Key);

if (block.Type is SCTypeCode.Byte or SCTypeCode.SByte)
return (byte)block.GetValue();

return 0;
}

private void SetForm(byte value)
{
var blockInfo = (BlockDefinition)typeof(BlockDefinitions).GetField($"KOutbreakBC{ID:00}{LocationMap}Form")!.GetValue(new BlockDefinition())!;
var block = SAV.Accessor.GetBlockSafe(blockInfo.Key);

if (block.Type is SCTypeCode.Byte or SCTypeCode.SByte)
block.SetValue(value);
}

private int GetNumKO()
{
var blockInfo = (BlockDefinition)typeof(BlockDefinitions).GetField($"KOutbreakBC{ID:00}{LocationMap}NumKOed")!.GetValue(new BlockDefinition())!;
var block = SAV.Accessor.GetBlockSafe(blockInfo.Key);

if (block.Type is SCTypeCode.Int32)
return (int)block.GetValue();

return 0;
}

private void SetNumKO(int value)
{
var blockInfo = (BlockDefinition)typeof(BlockDefinitions).GetField($"KOutbreakBC{ID:00}{LocationMap}NumKOed")!.GetValue(new BlockDefinition())!;
var block = SAV.Accessor.GetBlockSafe(blockInfo.Key);

if (block.Type is SCTypeCode.Int32)
block.SetValue(value);
}

private int GetMaxSpawns()
{
var blockInfo = (BlockDefinition)typeof(BlockDefinitions).GetField($"KOutbreakBC{ID:00}{LocationMap}TotalSpawns")!.GetValue(new BlockDefinition())!;
var block = SAV.Accessor.GetBlockSafe(blockInfo.Key);

if (block.Type is SCTypeCode.Int32)
return (int)block.GetValue();

return 0;
}

private void SetMaxSpawns(int value)
{
var blockInfo = (BlockDefinition)typeof(BlockDefinitions).GetField($"KOutbreakBC{ID:00}{LocationMap}TotalSpawns")!.GetValue(new BlockDefinition())!;
var block = SAV.Accessor.GetBlockSafe(blockInfo.Key);

if (block.Type is SCTypeCode.Int32)
block.SetValue(value);
}
}
39 changes: 39 additions & 0 deletions TeraFinder.Core/Classes/FakeOutbreak.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using PKHeX.Core;
using System.Text.Json.Nodes;
using System.Text.Json;
using static System.Buffers.Binary.BinaryPrimitives;

namespace TeraFinder.Core;

public class FakeOutbreak(IOutbreak outbreak)
{
private byte[] LocationCenter { get; set; } = [.. outbreak.LocationCenter!.GetCoordinates()];
private byte[] LocationDummy { get; set; } = [.. outbreak.LocationDummy!.GetCoordinates()];
public uint Species { get; private set; } = outbreak.Species;
public byte Form { get; private set; } = outbreak.Form;
public int MaxSpawns { get; private set; } = outbreak.MaxSpawns;

public float CenterX { get => ReadSingleLittleEndian(LocationCenter.AsSpan()); }
public float CenterY { get => ReadSingleLittleEndian(LocationCenter.AsSpan()[4..]); }
public float CenterZ { get => ReadSingleLittleEndian(LocationCenter.AsSpan()[8..]); }

public float DummyX { get => ReadSingleLittleEndian(LocationDummy.AsSpan()); }
public float DummyY { get => ReadSingleLittleEndian(LocationDummy.AsSpan()[4..]); }
public float DummyZ { get => ReadSingleLittleEndian(LocationDummy.AsSpan()[8..]); }

public void RestoreFromJson(string json)
{
var simpleOutbreak = JsonSerializer.Deserialize<JsonNode>(json)!;
var locationCenter = Convert.FromHexString(simpleOutbreak[nameof(LocationCenter)]!.GetValue<string>());
var locationDummy = Convert.FromHexString(simpleOutbreak[nameof(LocationDummy)]!.GetValue<string>());
var species = SpeciesConverter.GetInternal9(simpleOutbreak[nameof(Species)]!.GetValue<ushort>());
var form = simpleOutbreak[nameof(Form)]!.GetValue<byte>();
var maxSpawns = simpleOutbreak[nameof(MaxSpawns)]!.GetValue<int>();

LocationCenter = locationCenter;
LocationDummy = locationDummy;
Species = species;
Form = form;
MaxSpawns = maxSpawns;
}
}
22 changes: 22 additions & 0 deletions TeraFinder.Core/Classes/GameCoordinates.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using PKHeX.Core;
using static System.Buffers.Binary.BinaryPrimitives;

namespace TeraFinder.Core;

public class GameCoordinates(SCBlock coordinates)
{
protected readonly SCBlock Coordinates = coordinates;

public float X { get => ReadSingleLittleEndian(Coordinates.Data.AsSpan()); set => SetX(value); }
public float Y { get => ReadSingleLittleEndian(Coordinates.Data.AsSpan()[4..]); set => SetY(value); }
public float Z { get => ReadSingleLittleEndian(Coordinates.Data.AsSpan()[8..]); set => SetZ(value); }

private void SetX(float x) => SetCoordinates(0, x);
private void SetY(float y) => SetCoordinates(4, y);
private void SetZ(float z) => SetCoordinates(8, z);

private void SetCoordinates(int index, float value) => WriteSingleLittleEndian(Coordinates.Data.AsSpan()[index..], value);

public ReadOnlySpan<byte> GetCoordinates() => Coordinates.Data.AsSpan();
public void SetCoordinates(ReadOnlySpan<byte> coordinates) => Coordinates.ChangeData(coordinates);
}
68 changes: 8 additions & 60 deletions TeraFinder.Core/Classes/MassOutbreak.cs
Original file line number Diff line number Diff line change
@@ -1,37 +1,18 @@
using PKHeX.Core;
using System.Text.Json.Nodes;
using System.Text.Json;
using static System.Buffers.Binary.BinaryPrimitives;

namespace TeraFinder.Core;

public class GameCoordinates(SCBlock coordinates)
public class MassOutbreak : IOutbreak
{
protected readonly SCBlock Coordinates = coordinates;
protected int ID { get; init; }
protected SAV9SV SAV { get; init; }
protected string LocationMap { get; init; }

public float X { get => ReadSingleLittleEndian(Coordinates.Data.AsSpan()); set => SetX(value); }
public float Y { get => ReadSingleLittleEndian(Coordinates.Data.AsSpan()[4..]); set => SetY(value); }
public float Z { get => ReadSingleLittleEndian(Coordinates.Data.AsSpan()[8..]); set => SetZ(value); }

private void SetX(float x) => SetCoordinates(0, x);
private void SetY(float y) => SetCoordinates(4, y);
private void SetZ(float z) => SetCoordinates(8, z);

private void SetCoordinates(int index, float value) => WriteSingleLittleEndian(Coordinates.Data.AsSpan()[index..], value);

public ReadOnlySpan<byte> GetCoordinates() => Coordinates.Data.AsSpan();
public void SetCoordinates(ReadOnlySpan<byte> coordinates) => Coordinates.ChangeData(coordinates);
}

public class MassOutbreak
{
protected int ID;
protected SAV9SV SAV = null!;
protected sbyte AmountAvailable { get => GetAmountAvailable(); set => SetAmountAvailable(value); }
protected string LocationMap { get; set; }

public GameCoordinates? LocationCenter { get; private set; }
public GameCoordinates? LocationDummy { get; private set; }
public GameCoordinates? LocationCenter { get; set; }
public GameCoordinates? LocationDummy { get; set; }
public sbyte AmountAvailable { get => GetAmountAvailable(); set => SetAmountAvailable(value); }
public bool Found { get => GetFound(); set => SetFound(value); }
public bool Enabled { get => GetEnabled(); set => SetEnabled(value); }
public uint Species { get => GetSpecies(); set => SetSpecies(value); }
Expand Down Expand Up @@ -97,7 +78,7 @@ public void RestoreFromJson(string json)
MaxSpawns = maxSpawns;
}

public sbyte GetAmountAvailable()
private sbyte GetAmountAvailable()
{
var info = LocationMap switch { "DLC1" => BlockDefinitions.KOutbreakDLC1NumActive, "DLC2" => BlockDefinitions.KOutbreakDLC2NumActive, _ => BlockDefinitions.KOutbreakMainNumActive };
var block = SAV.Accessor.GetBlockSafe(info.Key);
Expand Down Expand Up @@ -234,37 +215,4 @@ private void SetMaxSpawns(int value)
if (block.Type is SCTypeCode.Int32)
block.SetValue(value);
}
}

public class FakeOutbreak(MassOutbreak outbreak)
{
private byte[] LocationCenter { get; set; } = [..outbreak.LocationCenter!.GetCoordinates()];
private byte[] LocationDummy { get; set; } = [..outbreak.LocationDummy!.GetCoordinates()];
public uint Species { get; private set; } = outbreak.Species;
public byte Form { get; private set; } = outbreak.Form;
public int MaxSpawns { get; private set; } = outbreak.MaxSpawns;

public float CenterX { get => ReadSingleLittleEndian(LocationCenter.AsSpan()); }
public float CenterY { get => ReadSingleLittleEndian(LocationCenter.AsSpan()[4..]); }
public float CenterZ { get => ReadSingleLittleEndian(LocationCenter.AsSpan()[8..]); }

public float DummyX { get => ReadSingleLittleEndian(LocationDummy.AsSpan()); }
public float DummyY { get => ReadSingleLittleEndian(LocationDummy.AsSpan()[4..]); }
public float DummyZ { get => ReadSingleLittleEndian(LocationDummy.AsSpan()[8..]); }

public void RestoreFromJson(string json)
{
var simpleOutbreak = JsonSerializer.Deserialize<JsonNode>(json)!;
var locationCenter = Convert.FromHexString(simpleOutbreak[nameof(LocationCenter)]!.GetValue<string>());
var locationDummy = Convert.FromHexString(simpleOutbreak[nameof(LocationDummy)]!.GetValue<string>());
var species = SpeciesConverter.GetInternal9(simpleOutbreak[nameof(Species)]!.GetValue<ushort>());
var form = simpleOutbreak[nameof(Form)]!.GetValue<byte>();
var maxSpawns = simpleOutbreak[nameof(MaxSpawns)]!.GetValue<int>();

LocationCenter = locationCenter;
LocationDummy = locationDummy;
Species = species;
Form = form;
MaxSpawns = maxSpawns;
}
}
2 changes: 2 additions & 0 deletions TeraFinder.Core/Enumerations/OutbreakSpecies.cs
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@ public enum KitakamiSpeciesOb : ushort
Toedscool = 948,
Toedscruel = 949,
Kingambit = 983,
Tatsugiri = 978,
Annihilape = 979,
Poltchageist = 1012,
}
Expand Down Expand Up @@ -655,5 +656,6 @@ public enum BlueberrySpeciesOb : ushort
Kleavor = 900,
Rellor = 953,
Rabsca = 954,
Tatsugiri = 978,
Farigiraf = 981,
}
Loading

0 comments on commit 6dbd8ec

Please sign in to comment.