using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.Linq; using System.Windows.Forms; using pkNX.Game; using pkNX.Randomization; using pkNX.Structures; using pkNX.Structures.FlatBuffers.SWSH; namespace pkNX.WinForms; public sealed partial class SSWE : Form { private readonly EncounterArchive Symbols; private readonly EncounterArchive Hidden; private readonly GameManagerSWSH ROM; private ulong entry; private readonly EncounterList8[] SL; public SSWE(GameManagerSWSH rom, EncounterArchive sym, EncounterArchive hid) { InitializeComponent(); Symbols = sym; Hidden = hid; ROM = rom; var spec = rom.GetStrings(TextName.SpeciesNames); var species = (string[])spec.Clone(); species[0] = ""; EncounterList8.SpeciesNames = species; SL = [SL_0, SL_1, SL_2, SL_3, SL_4, SL_5, SL_6, SL_7, SL_8, SL_9, SL_10]; foreach (var z in SL) z.Initialize(); PG_Species.SelectedObject = EditUtil.Settings.Species; LoadLocations(); } private class LocationHash(ulong hash, string loc) { public ulong Hash { get; } = hash; public string LocationName { get; } = loc; } public bool Modified { get; private set; } public void LoadLocations() { static string GetLocationName(ulong id) => SWSHInfo.Zones.TryGetValue(id, out var zoneName) ? zoneName : id.ToString("X16"); var sl = Symbols.EncounterTables .Select(area => new LocationHash(area.ZoneID, GetLocationName(area.ZoneID) + " [S]")); var hl = Hidden.EncounterTables .Select(area => new LocationHash(area.ZoneID, GetLocationName(area.ZoneID) + " [H]")); var locs = sl.Concat(hl) .OrderBy(z => z.LocationName) .ToArray(); CB_Location.ValueMember = nameof(LocationHash.Hash); CB_Location.DisplayMember = nameof(LocationHash.LocationName); CB_Location.DataSource = new BindingSource(locs, null); CB_Location.SelectedIndex = 0; } private void CB_Location_SelectedIndexChanged(object sender, EventArgs e) { SaveEntry(entry); var item = (LocationHash)CB_Location.SelectedItem; entry = item.Hash; Debug.WriteLine($"Loading area data for [0x{entry:X16}] {item.LocationName}"); L_Hash.Text = entry.ToString("X16"); LoadEntry(entry); } private void LoadEntry(ulong zone) { Load(SL, Symbols, "Symbols"); Load(SL, Hidden, "Hidden"); void Load(EncounterList8[] arr, EncounterArchive arc, string name) { var table = arc.EncounterTables.FirstOrDefault(z => z.ZoneID == zone); if (table == null) return; L_Type.Text = name; var subs = table.SubTables; for (int i = 0; i < subs.Count; i++) { var t = subs[i]; arr[i].NUD_Max.Value = t.LevelMax; arr[i].NUD_Min.Value = t.LevelMin; arr[i].LoadSlots(subs[i].Slots); arr[i].Visible = true; } // some tables don't have tree/fish for (int i = subs.Count; i < arr.Length; i++) arr[i].Visible = false; } } private void SaveEntry(ulong zone) { if (zone == 0) return; Save(SL, Symbols); Save(SL, Hidden); void Save(EncounterList8[] arr, EncounterArchive arc) { var table = arc.EncounterTables.FirstOrDefault(z => z.ZoneID == zone); if (table == null) return; var subs = table.SubTables; for (int i = 0; i < subs.Count; i++) { var t = subs[i]; t.LevelMax = (byte)arr[i].NUD_Max.Value; t.LevelMin = (byte)arr[i].NUD_Min.Value; arr[i].SaveCurrent(); } } } private void B_Save_Click(object sender, EventArgs e) { SaveEntry(entry); Modified = true; Close(); } private void B_RandAll_Click(object sender, EventArgs e) { SaveEntry(entry); var settings = (SpeciesSettings)PG_Species.SelectedObject; var rand = new SpeciesRandomizer(ROM.Info, ROM.Data.PersonalData); var pt = ROM.Data.PersonalData; var ban = pt.Table.Take(ROM.Info.MaxSpeciesID + 1) .Select((z, i) => new { Species = i, Present = ((IPersonalInfoSWSH)z).IsPresentInGame }) .Where(z => !z.Present).Select(z => z.Species).ToArray(); rand.Initialize(settings, ban); RandomizeWild(rand, CHK_FillEmpty.Checked, CHK_Level.Checked); LoadEntry(entry); System.Media.SystemSounds.Asterisk.Play(); } private void RandomizeWild(SpeciesRandomizer rand, bool fill, bool boost) { var pt = ROM.Data.PersonalData; var fr = new FormRandomizer(pt); var settings = (SpeciesSettings)PG_Species.SelectedObject; foreach (var area in Symbols.EncounterTables.Concat(Hidden.EncounterTables)) { foreach (var sub in area.SubTables) { if (boost) { sub.LevelMin = (byte)Legal.GetModifiedLevel(sub.LevelMin, (double)NUD_LevelBoost.Value); sub.LevelMax = (byte)Legal.GetModifiedLevel(sub.LevelMax, (double)NUD_LevelBoost.Value); } ApplyRand(sub.Slots); } } void ApplyRand(IList slots) { if (slots[0].Species == 0) return; for (int i = 0; i < slots.Count; i++) { var s = slots[i]; if (s.Species == 0) { if (!fill) continue; s.Species = slots.FirstOrDefault(z => z.Species != 0)?.Species ?? rand.GetRandomSpecies(); s.Form = 0; // ensure it's not junk } s.Species = rand.GetRandomSpecies(s.Species); s.Form = (byte)fr.GetRandomForm(s.Species, false, settings.AllowRandomFusions, ROM.Info.Generation, ROM.Data.PersonalData.Table); if (fill) s.Probability = RandomScaledRates[slots.Count][i]; } } } public static readonly Dictionary RandomScaledRates = new() { [01] = [100], [04] = [60, 30, 7, 3], [05] = [40, 30, 18, 10, 2], [10] = [20, 15, 15, 10, 10, 10, 10, 5, 4, 1], }; private void TC_Tables_DrawItem(object sender, DrawItemEventArgs e) { var tc = (TabControl)sender; Graphics g = e.Graphics; // Get the item from the collection. TabPage _tabPage = tc.TabPages[e.Index]; // Get the real bounds for the tab rectangle. Rectangle _tabBounds = tc.GetTabRect(e.Index); Brush _textBrush; if (e.State == DrawItemState.Selected) { // Draw a different background color, and don't paint a focus rectangle. _textBrush = new SolidBrush(Color.Red); g.FillRectangle(Brushes.Beige, e.Bounds); } else { _textBrush = new SolidBrush(e.ForeColor); e.DrawBackground(); } // Use our own font. Font _tabFont = new("Arial", (float)10.0, FontStyle.Bold, GraphicsUnit.Pixel); // Draw string. Center the text. StringFormat _stringFlags = new() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center, }; g.DrawString(_tabPage.Text, _tabFont, _textBrush, _tabBounds, new StringFormat(_stringFlags)); } }