pkNX/pkNX.WinForms/Subforms/MapViewer8a.cs
JelleInfinity 4167762c44
Some bug fixes (#276)
* Replace all uses of ModelID

* Prep work to add PokeMisc data
2022-10-05 17:01:34 +01:00

277 lines
9.5 KiB
C#

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using pkNX.Containers;
using pkNX.Game;
using pkNX.Structures;
using pkNX.Structures.FlatBuffers;
namespace pkNX.WinForms.Subforms;
public partial class MapViewer8a : Form
{
private readonly GameManagerPLA ROM;
private readonly GFPack Resident;
private readonly AreaSettingsTable8a Settings;
public readonly AreaInstance8a[] Areas;
private readonly bool Loading = true;
public MapViewer8a(GameManagerPLA rom, GFPack resident)
{
ROM = rom;
Resident = resident;
var bin_settings = resident.GetDataFullPath("bin/field/resident/AreaSettings.bin");
Settings = FlatBufferConverter.DeserializeFrom<AreaSettingsTable8a>(bin_settings);
InitializeComponent();
Areas = ResidentAreaSet.AreaNames.Select(z => AreaInstance8a.Create(Resident, z, Settings)).ToArray();
CB_Map.Items.AddRange(Areas.Select(z => z.ParentArea?.FriendlyAreaName ?? z.FriendlyAreaName).ToArray());
var speciesNames = ROM.GetStrings(TextName.SpeciesNames);
var pt = rom.Data.PersonalData;
var nameList = new List<ComboItem>();
foreach (var e in pt.Table.Cast<IPersonalMisc_1>())
{
if (!e.IsPresentInGame)
continue;
var species = e.DexIndexNational;
if (nameList.All(z => z.Value != species))
nameList.Add(new(speciesNames[species], species));
}
nameList.Insert(0, new("(All)", -1));
nameList.Sort((x, y) => string.Compare(x.Text, y.Text, StringComparison.InvariantCulture));
CB_Species.DisplayMember = nameof(ComboItem.Text);
CB_Species.ValueMember = nameof(ComboItem.Value);
CB_Species.DataSource = new BindingSource(nameList, null);
CB_Species.SelectedValue = -1;
Loading = false;
CB_Map.SelectedIndex = 1;
}
private class ComboItem
{
public ComboItem(string text, int value)
{
Text = text;
Value = value;
}
public string Text { get; }
public int Value { get; }
}
private void CB_Map_SelectedIndexChanged(object sender, EventArgs e)
{
UpdateMap(CB_Map.SelectedIndex, (int)CB_Species.SelectedValue);
}
private void CB_Species_SelectedIndexChanged(object sender, EventArgs e)
{
UpdateMap(CB_Map.SelectedIndex, (int)CB_Species.SelectedValue);
}
private List<AreaDef> Defs = new();
private static string GetMapImagePath(AreaInstance8a area)
{
string mapName = MapName(area.AreaName);
return $"map_pla\\{mapName}.png";
}
private static string MapName(string name) => name switch
{
"ha_area00" => "map_lmap_pic_05_05",
"ha_area01" => "map_lmap_pic_00",
"ha_area02" => "map_lmap_pic_01",
"ha_area03" => "map_lmap_pic_02",
"ha_area04" => "map_lmap_pic_03",
"ha_area05" => "map_lmap_pic_04",
"ha_area06" => "map_lmap_pic_06",
_ => name,
};
private void UpdateMap(int map, int species)
{
if (Loading)
return;
var area = Areas[map];
var mapImagePath = System.IO.Path.GetFullPath(GetMapImagePath(area));
if (System.IO.File.Exists(mapImagePath))
{
pictureBox1.BackgroundImage = Image.FromFile(mapImagePath);
}
else
{
WinFormsUtil.Error($"Unable to find map image at path: {mapImagePath}", "Automatic extraction of the map images is not yet supported.\nYou will have to extract them manually and place them at the location above. (You can use Switch-Toolbox for this.)");
pictureBox1.BackgroundImage = new Bitmap(1024, 1024);
}
using var gr = Graphics.FromImage(pictureBox1.BackgroundImage);
var r = new SolidBrush(Color.FromArgb(100, 255, 0, 0));
var g = new SolidBrush(Color.FromArgb(20, 20, 255, 10));
var b = new SolidBrush(Color.FromArgb(100, 10, 0, 255));
var c = new SolidBrush(Color.FromArgb(100, 0, 255, 255));
var rs = new Pen(Color.FromArgb(255, 255, 0, 0)) { Width = 3 };
var gs = new Pen(Color.FromArgb(255, 20, 255, 10)) { Width = 3 };
var bs = new Pen(Color.FromArgb(255, 10, 0, 255)) { Width = 3 };
var cs = new Pen(Color.FromArgb(255, 10, 255, 255)) { Width = 3 };
var coordinates = Defs = GetSpawnerInfo(species, area);
foreach (var o in coordinates)
{
var brush = o.Type switch
{
SpawnerType.Spawner => r,
SpawnerType.Wormhole => g,
SpawnerType.Landmark => b,
SpawnerType.Unown => c,
_ => throw new ArgumentOutOfRangeException(nameof(o.Type)),
};
var penS = o.Type switch
{
SpawnerType.Spawner => rs,
SpawnerType.Wormhole => gs,
SpawnerType.Landmark => bs,
SpawnerType.Unown => cs,
_ => throw new ArgumentOutOfRangeException(nameof(o.Type)),
};
var center = o.Position;
var radius = o.Radius;
var x = center.X - radius;
var y = center.Z - radius;
var d = radius * 2;
gr.FillEllipse(brush, x, y, d, d);
gr.DrawEllipse(penS, x, y, d, d);
}
}
private static List<AreaDef> GetSpawnerInfo(int species, AreaInstance8a area)
{
var result = new List<AreaDef>();
foreach (var s in area.Spawners.Concat(area.SubAreas.SelectMany(z => z.Spawners)))
{
var table = s.Field_20_Value.EncounterTableID;
var slots = Array.Find(area.Encounters, z => z.TableID == table);
if (slots == null)
continue;
if (species != -1 && slots.Table.All(z => z.Species != species))
continue;
result.Add(new(slots.TableName, s.MinSpawnCount, s.MaxSpawnCount, s.Parameters.Coordinates, SpawnerType.Spawner, slots.Table, s.Scalar));
}
foreach (var s in area.Wormholes.Concat(area.SubAreas.SelectMany(z => z.Wormholes)))
{
var table = s.Field_20_Value.EncounterTableID;
var slots = Array.Find(area.Encounters, z => z.TableID == table);
if (slots == null)
continue;
if (species != -1 && slots.Table.All(z => z.Species != species))
continue;
result.Add(new(slots.TableName, s.MinSpawnCount, s.MaxSpawnCount, s.Parameters.Coordinates, SpawnerType.Wormhole, slots.Table, s.Scalar));
}
foreach (var a in area.LandMarks.Concat(area.SubAreas.SelectMany(z => z.LandMarks)))
{
var table = a.LandmarkItemSpawnTableID;
foreach (var l in area.LandItems.Concat(area.SubAreas.SelectMany(z => z.LandItems)))
{
if (l.LandmarkItemSpawnTableID != table)
continue;
var st = l.EncounterTableID;
var slots = Array.Find(area.Encounters, z => z.TableID == st);
if (slots == null)
continue;
if (species != -1 && slots.Table.All(z => z.Species != species))
continue;
result.Add(new(slots.TableName, 1, 1, a.Parameters.Coordinates, SpawnerType.Landmark, slots.Table, Math.Max(a.Scalar, 1) * 4));
}
}
if (species is not 201)
return result;
foreach (var u in area.Unown.Concat(area.SubAreas.SelectMany(z => z.Unown)))
{
var slots = Unown;
result.Add(new("Unown", 1, 1, u.Parameters.Coordinates, SpawnerType.Unown, slots, u.Number * 2));
}
return result;
}
private static readonly EncounterSlot8a[] Unown = { new() { Species = 201 } };
private void MapViewer8a_MouseMove(object sender, MouseEventArgs e)
{
SizeF imageSize = pictureBox1.BackgroundImage.Size;
SizeF controlSize = pictureBox1.Size;
float scaleX = imageSize.Width / controlSize.Width;
float scaleY = imageSize.Height / controlSize.Height;
var (x, z) = (e.X * scaleX, e.Y * scaleY);
L_CoordinateMouse.Text = $"{x}, {z}";
var dist = (int)NUD_Tolerance.Value;
var spawners = Defs
.Select(s => (Spawner: s, Distance: s.Position.DistanceTo(new(x, s.Position.Y, z))))
.Where(s => s.Distance <= s.Spawner.Radius + dist)
.OrderByDescending(s => s.Distance).ToArray();
if (spawners.Length == 0)
{
L_SpawnDump.Text = "";
return;
}
L_SpawnDump.Text = string.Join(Environment.NewLine, spawners.Select(s => s.Spawner.GetLine()));
}
}
public class AreaDef
{
public readonly string NameSummary;
public readonly int Min;
public readonly int Max;
public readonly PlacementV3f8a Position;
public readonly SpawnerType Type;
public readonly EncounterSlot8a[] Slots;
public readonly float Radius;
public AreaDef(string NameSummary, int min, int max, PlacementV3f8a position, SpawnerType type, EncounterSlot8a[] slots, float radius)
{
this.NameSummary = NameSummary;
Min = min;
Max = max;
Position = position;
Type = type;
Slots = slots;
Radius = radius;
}
public string GetLine()
{
var species = string.Join(",", Slots.Select(x => (Species)x.Species));
return $"{NameSummary}\r\n{Position.ToTriple()} {Min}-{Max}: {species}";
}
}