diff --git a/Data/Ability.cs b/Data/Ability.cs index 9513153..069cd1a 100644 --- a/Data/Ability.cs +++ b/Data/Ability.cs @@ -64,6 +64,30 @@ public bool HasCharacter(string character) return false; } + public string GetCharacters() + { + return string.Join("", list.SelectMany(a => a.Characters.ToCharArray()).Distinct().OrderBy(c => "lsvzhf".ToCharArray().ToList().IndexOf(c)).Select(c => + { + switch (c) + { + case 'l': + return "L"; + case 's': + return "Sn"; + case 'v': + return "V"; + case 'z': + return "Sz"; + case 'h': + return "H"; + case 'f': + return "F"; + default: + return ""; + } + })); + } + public string GetAbility(string character) { for (int i = list.Count - 1; i >= 0; i--) @@ -71,7 +95,27 @@ public string GetAbility(string character) if (list[i].HasCharacter(character)) return list[i].ID; } - throw new InvalidCastException("Character does not have the ability!"); + throw new Exception($"{GetName(character)} cannot have the {Name} ability!"); + } + + private Character GetName(string character) + { + switch (character) + { + case "l": + return Character.Lightning; + case "s": + return Character.Snow; + case "v": + return Character.Vanille; + case "z": + return Character.Sazh; + case "h": + return Character.Hope; + case "f": + return Character.Fang; + } + return Character.Lightning; } public Ability SetStarting() diff --git a/FormMain.cs b/FormMain.cs index dc712ae..f8cb037 100644 --- a/FormMain.cs +++ b/FormMain.cs @@ -18,7 +18,7 @@ namespace FF13Randomizer { public partial class FormMain : Form { - public static string Version { get; set; } = "1.8.0.Pre"; + public static string Version { get; set; } = "1.8.0.Pre-2"; public static bool PlandoModified { get; set; } = false; @@ -714,6 +714,7 @@ private void button9_Click(object sender, EventArgs e) { flag.ResetRandom(seed); } + RandomNum.ClearRand(); foreach(string path in fileNamesModified) { @@ -732,24 +733,34 @@ private void button9_Click(object sender, EventArgs e) randomizers.Add(new RandoMusic(this, randomizers)); randomizers.Add(new RandoRunSpeed(this, randomizers)); - new ProgressForm("Loading data...", bw => LoadRandos(randomizers, bw)).ShowDialog(); - foreach(Randomizer rando in randomizers) + try { - new ProgressForm(rando.GetProgressMessage(), bw => rando.Randomize(bw)).ShowDialog(); - } + new ProgressForm("Loading data...", bw => LoadRandos(randomizers, bw)).ShowDialog(); + foreach (Randomizer rando in randomizers) + { + new ProgressForm(rando.GetProgressMessage(), bw => rando.Randomize(bw)).ShowDialog(); + } + new ProgressForm("Saving data...", bw => SaveRandos(randomizers, bw)).ShowDialog(); - new ProgressForm("Saving data...", bw => SaveRandos(randomizers, bw)).ShowDialog(); + new ProgressForm("Inserting files...", bw => insertFiles(bw, true)).ShowDialog(); - new ProgressForm("Inserting files...", bw => insertFiles(bw, true)).ShowDialog(); + UserFlagsSeed.Export(RandoPath, textBoxSeed.Text.Trim(), Version); + addHistory(); - UserFlagsSeed.Export(RandoPath, textBoxSeed.Text.Trim(), Version); - addHistory(); - - //UserFlagsSeed.Export("logs", textBoxSeed.Text.Trim(), version); + //UserFlagsSeed.Export("logs", textBoxSeed.Text.Trim(), version); - MessageBox.Show("Complete! Ready to play! Whenever you need to uninstall the rando, come back to this program and go to the Uninstall tab!"); + MessageBox.Show("Complete! Ready to play! Whenever you need to uninstall the rando, come back to this program and go to the Uninstall tab!"); + } catch(Exception ex) + { + Exception innerMost = ex; + while(innerMost.InnerException != null) + { + innerMost = innerMost.InnerException; + } + MessageBox.Show("Randomizer encountered an error:\n" + innerMost.Message, "Rando failed"); + } } public void LoadRandos(List randomizers, BackgroundWorker worker) @@ -1102,8 +1113,9 @@ private void button15_Click(object sender, EventArgs e) { PlandoFile.Write(dialog.FileName, this); Process.Start(Path.GetDirectoryName(dialog.FileName)); + MessageBox.Show("Plando exported! Opened location where file has been saved."); + PlandoModified = false; } - PlandoModified = false; } private void button14_Click(object sender, EventArgs e) @@ -1125,8 +1137,9 @@ private void button14_Click(object sender, EventArgs e) if (dialog.ShowDialog() == DialogResult.OK) { PlandoFile.Read(dialog.FileName, this); + MessageBox.Show("Plando imported!"); + PlandoModified = false; } - PlandoModified = false; } private void FormMain_FormClosing(object sender, FormClosingEventArgs e) diff --git a/Plandos/CrystariumPlando.cs b/Plandos/CrystariumPlando.cs index 1ff9064..f00f04f 100644 --- a/Plandos/CrystariumPlando.cs +++ b/Plandos/CrystariumPlando.cs @@ -71,7 +71,7 @@ private void AddEntries() dataGridView1.Columns.Add(column2); DataGridViewComboBoxColumn column = new DataGridViewComboBoxColumn(); - column.Items.AddRange(new string[] { "???" }.Concat(Abilities.abilities.Select(a => a.Name).ToList()).ToArray()); + column.Items.AddRange(GetAbilityDropdownNames()); column.HeaderText = "New Ability"; column.DisplayMember = "New Ability"; column.ValueMember = "New Ability"; @@ -87,6 +87,11 @@ private void AddEntries() dataGridView1.DataSource = dataTable; } + private static string[] GetAbilityDropdownNames() + { + return new string[] { "???" }.Concat(Abilities.abilities.Select(a => a.Name + (a.GetCharacters() != "LSnVSzHF" ? $" ({a.GetCharacters()})" : "")).ToList()).ToArray(); + } + private void AddEntry(DataStoreIDCrystarium crystId, string charName, string role, string locationName) { dataTable.Rows.Add(crystId.ID, charName, role, crystId.Stage, locationName, "Unknown", "???", "???", 0); @@ -188,7 +193,7 @@ private void dataGridView1_CellValidating(object sender, DataGridViewCellValidat string nodeId = row.Field(0); string name = row.Field(1); CrystariumType type = row.Field(6) == "???" ? CrystariumType.Unknown : ((CrystariumType[])Enum.GetValues(typeof(CrystariumType)))[Enum.GetNames(typeof(CrystariumType)).ToList().IndexOf(row.Field(6).Replace(" ", ""))]; - Ability ability = Abilities.abilities.Find(a => a.Name == row.Field(7)); + Ability ability = Abilities.abilities.Find(a => a.Name == GetAbilityName(row.Field(7))); int statAmount = row.Field(8); if (!(type == CrystariumType.Unknown && ability == null)) { @@ -209,6 +214,11 @@ private void dataGridView1_CellValidating(object sender, DataGridViewCellValidat return dict; } + private string GetAbilityName(string name) + { + return name.Contains("(") ? name.Substring(0, name.IndexOf("(") - 1).Trim() : name; + } + public class JSONPlandoCrystarium { public string ID { get; set; } @@ -240,7 +250,9 @@ public void LoadJSONPlando(List list) { JSONPlandoCrystarium json = list.Find(j => j.ID == row.Field(0)); row.SetField(6, json.Type); - row.SetField(7, json.AbilityName); + + row.SetField(7, GetAbilityDropdownNames().Where(s => s == json.AbilityName || s.StartsWith(json.AbilityName)).FirstOrDefault()); + row.SetField(8, json.Value); } } diff --git a/Plandos/ShopPlando.cs b/Plandos/ShopPlando.cs index f2b30fb..622295d 100644 --- a/Plandos/ShopPlando.cs +++ b/Plandos/ShopPlando.cs @@ -109,19 +109,20 @@ private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) } } - public Dictionary> GetShops() + public Dictionary, List> GetShops() { - Dictionary> dict = new Dictionary>(); - Shops.shops.ForEach(s => dict.Add(s, new List())); + Dictionary, List> dict = new Dictionary, List>(); + Shops.shops.ForEach(s => Enumerable.Range(0, s.Tiers).ForEach(tier => dict.Add(new Tuple(s, tier), new List()))); foreach (DataRow row in dataTable.Rows) { Shop shop = Shops.shops.Find(s => s.GetAllIds().Contains(row.Field(0))); + int tier = shop.GetAllIds().IndexOf(row.Field(0)); Item item = Items.items.Find(i => i.Name == row.Field(3) || i.ID == row.Field(3)); if (row.Field(3) == "None") item = Items.Gil; if (item != null) { - dict[shop].Add(item); + dict[new Tuple(shop, tier)].Add(item); } } return dict; diff --git a/ProgressForm.cs b/ProgressForm.cs index f8b0b1f..aa68e46 100644 --- a/ProgressForm.cs +++ b/ProgressForm.cs @@ -41,6 +41,8 @@ private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEve private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { + if (e.Error != null) + throw new Exception("Randomizer Error", e.Error); this.Close(); } } diff --git a/Randomizers/RandoCrystarium.cs b/Randomizers/RandoCrystarium.cs index 5126383..b3da2bb 100644 --- a/Randomizers/RandoCrystarium.cs +++ b/Randomizers/RandoCrystarium.cs @@ -63,6 +63,7 @@ public override void Randomize(BackgroundWorker backgroundWorker) backgroundWorker.ReportProgress(10); if (Flags.CrystariumFlags.RandStats) RandomizeStats(plando, statAverages); + backgroundWorker.ReportProgress(20); if (Tweaks.Boosts.ScaledCPCost) @@ -74,6 +75,17 @@ public override void Randomize(BackgroundWorker backgroundWorker) backgroundWorker.ReportProgress(40); RandomizeAbilities(plando); + + foreach (string name in CharNames) + { + foreach (DataStoreIDCrystarium id in crystariums[name].IdList.Where(id => !id.ID.StartsWith("!"))) + { + DataStoreCrystarium c = crystariums[name][id.ID]; + if (c.Type == CrystariumType.Unknown) + throw new Exception($"{name.Substring(0, 1).ToUpper() + name.Substring(1)} {c.Role} Stage {c.Stage} Node {Crystarium.GetDisplayNames(crystariums[name])[id]} is invalid."); + } + } + backgroundWorker.ReportProgress(100); } @@ -110,7 +122,7 @@ public void ApplyHalfCPCosts() Dictionary> abilities = new Dictionary>(); foreach (Role role in Enum.GetValues(typeof(Role))) { - abilities.Add(role, crystariums[name].DataList.Where(c => c.Role == role && c.Type == CrystariumType.Ability).Select(c => Abilities.GetAbility(name, c)).ToList()); + abilities.Add(role, crystariums[name].DataList.Where(c => c.Role == role && c.Type == CrystariumType.Ability && c.CPCost > 0 && (c.Stage > 1 || primaryRoles[name].Contains(c.Role))).Select(c => Abilities.GetAbility(name, c)).ToList()); } dict.Add(name, abilities); } @@ -189,6 +201,30 @@ public void ApplyHalfCPCosts() return statAverages; } + public void SetRemaining(List list) + { + foreach (string name in CharNames) + { + DataStoreWDB crystarium = crystariums[name]; + foreach (DataStoreCrystarium c in list) + { + if (!(c.Type == CrystariumType.HP || c.Type == CrystariumType.Strength || c.Type == CrystariumType.Magic)) + { + int stage = c.Stage; + List others; + do + { + others = new CrystariumType[] { CrystariumType.HP, CrystariumType.Strength, CrystariumType.Magic }.SelectMany(t => crystarium.DataList.Where(o => o.Role == c.Role && o.Stage == c.Stage && o.Type == t)).ToList(); + stage--; + } while (others.Count == 0); + DataStoreCrystarium other = others[RandomNum.RandInt(0, others.Count - 1)]; + c.Type = other.Type; + c.Value = other.Value; + } + } + } + } + public void RandomizeStats(Dictionary>> plando, Dictionary>> statAverages) { Flags.CrystariumFlags.RandStats.SetRand(); @@ -288,7 +324,7 @@ public void PlaceNodes(Dictionary c.CPCost > 0 && (c.Stage > 1 || primaryRoles[name].Contains(c.Role))).ForEach(c => c.Type = CrystariumType.Unknown); + List unknowns = crystariums[name].DataList.Where(c => c.CPCost > 0 && (c.Stage > 1 || primaryRoles[name].Contains(c.Role))).ToList(); foreach (string id in plando[name].Keys) { @@ -310,6 +346,7 @@ public void PlaceNodes(Dictionary possible; @@ -320,12 +357,13 @@ public void PlaceNodes(Dictionary !id.ID.StartsWith("!") && !plando[name].Keys.Contains(id.ID)).Select(id => crystariums[name][id.ID]).Where( c => c.Role == role && c.CPCost > 0 && (c.Stage > 1 || primaryRoles[name].Contains(role)) - && c.Type == CrystariumType.Unknown).ToList(); + && unknowns.Contains(c)).ToList(); for (int i = 0; i < nodes[name][role].Count; i++) { int select = RandomNum.RandInt(0, possible.Count - 1); possible[select].Type = CrystariumType.Ability; possible[select].AbilityName = nodes[name][role][i].GetAbility(Abilities.GetCharID(name)); + unknowns.Remove(possible[select]); possible.RemoveAt(select); } @@ -334,19 +372,21 @@ public void PlaceNodes(Dictionary !id.ID.StartsWith("!") && !plando[name].Keys.Contains(id.ID)).Select(id => crystariums[name][id.ID]).Where( - c => c.CPCost > 0 && (c.Stage > 1 || primaryRoles[name].Contains(c.Role)) && c.Type == CrystariumType.Unknown).ToList(); + c => c.CPCost > 0 && (c.Stage > 1 || primaryRoles[name].Contains(c.Role)) && unknowns.Contains(c)).ToList(); int atbLevelCount = crystariums[name].DataList.Where(c => c.Type == CrystariumType.ATBLevel).Count(); if (atbLevelCount == 0) { int select = RandomNum.RandInt(0, possible.Count - 1); possible[select].Type = CrystariumType.ATBLevel; + unknowns.Remove(possible[select]); possible.RemoveAt(select); } @@ -355,8 +395,27 @@ public void PlaceNodes(Dictionary shuffle = crystariums[name].IdList.Where( + id => !id.ID.StartsWith("!") && !plando[name].Keys.Contains(id.ID)).Select(id => crystariums[name][id.ID]).Where( + c => c.Role == role && + c.Stage == stage && + c.CPCost > 0 && (c.Stage > 1 || primaryRoles[name].Contains(role))).ToList(); + shuffle.Shuffle((a, b) => a.SwapStatsAbilities(b)); + } + } } RandomNum.ClearRand(); diff --git a/Randomizers/RandoShops.cs b/Randomizers/RandoShops.cs index f237a43..b54fb6c 100644 --- a/Randomizers/RandoShops.cs +++ b/Randomizers/RandoShops.cs @@ -53,7 +53,7 @@ private void RandomizeShops() Flags.ItemFlags.Shops.SetRand(); RandoEquip randoEquip = randomizers.Get("Equip"); - Dictionary> plando = main.shopPlando1.GetShops(); + Dictionary, List> plando = main.shopPlando1.GetShops(); List guaranteed = Items.items.Where(item => item.PreferredShop != null && randoEquip.equip.IdList.Where(id => id.ID == item.ID).Count() > 0 && @@ -85,8 +85,6 @@ private void RandomizeShops() List list = new List(); - list.AddRange(plando[shopID]); - if (Flags.ItemFlags.Shops.ExtraSelected) { list.AddRange(guaranteed.Where(item => item.PreferredShop == shopID)); @@ -105,7 +103,8 @@ private void RandomizeShops() } List possible = Flags.ItemFlags.Shops.ExtraSelected ? shuffled.Where(item => item.PreferredShop == shopID).ToList() : new List(shuffled); - int maxSize = RandomNum.RandInt(Math.Max(minSize, list.Count), Math.Min(list.Count + possible.Count, 32)); + int maxPlandoSize = plando.Keys.Where(k => k.Item1 == shopID).Select(key => plando[key].Count).Max(); + int maxSize = RandomNum.RandInt(Math.Min(32 - maxPlandoSize, Math.Max(minSize, list.Count)), Math.Min(list.Count + possible.Count, 32 - maxPlandoSize)); while (list.Count < maxSize && possible.Count > 0) { @@ -142,14 +141,17 @@ private void RandomizeShops() } List splits = new List(); - for (int i = 0; i < shopID.Tiers - 1; i++) + if (list.Count > 1) { - int num = -1; - do + for (int i = 0; i < shopID.Tiers - 1; i++) { - num = RandomNum.RandInt(1, list.Count - 1); - } while (splits.Contains(num)); - splits.Add(num); + int num = -1; + do + { + num = RandomNum.RandInt(1, list.Count - 1); + } while (splits.Contains(num) && splits.Count < list.Count - 1); + splits.Add(num); + } } splits.Add(list.Count); @@ -157,7 +159,13 @@ private void RandomizeShops() for (int i = 0; i < shopID.Tiers; i++) { - List itemsAtTier = list.ToArray().SubArray(0, splits[i]).OrderBy(item => Items.items.IndexOf(item)).ToList(); + List itemsAtTier = new List(plando[new Tuple(shopID, i)]); + + List remaining = list.ToArray().SubArray(0, splits[Math.Min(i, splits.Count - 1)]).OrderBy(item => Items.items.IndexOf(item)).ToList(); + itemsAtTier.AddRange(remaining.Take(Math.Min(32 - itemsAtTier.Count, remaining.Count))); + + if (itemsAtTier.Count > 32) + throw new Exception($"{shopID.Name} {i} has too many items."); for (int i2 = 0; i2 < 32; i2++) { shops[$"{shopID.ID}{i}"].SetItemID(i2, i2 < itemsAtTier.Count ? itemsAtTier[i2].ID : ""); diff --git a/Randomizers/RandoTreasure.cs b/Randomizers/RandoTreasure.cs index f94e8fe..435cc7a 100644 --- a/Randomizers/RandoTreasure.cs +++ b/Randomizers/RandoTreasure.cs @@ -63,7 +63,7 @@ public override void Randomize(BackgroundWorker backgroundWorker) index++; Item item = Items.items.Where(i => i.ID == t.ItemID).FirstOrDefault(); int rank = -1; - if (item != null) + if (item != null && Flags.ItemFlags.Treasures) { if (current != null && plando.ContainsKey(current)) { @@ -80,7 +80,7 @@ public override void Randomize(BackgroundWorker backgroundWorker) else { rank = TieredItems.manager.GetRank(item, (int)t.Count); - if (rank != -1 && Flags.ItemFlags.Treasures) + if (rank != -1) { if (rankAdj > 0) rank = RandomNum.RandInt(Math.Max(0, rank - rankAdj), Math.Min(TieredItems.manager.GetHighBound(), rank + rankAdj));