diff --git a/DDFileTypes/CurioTypeLibrary.cs b/DDFileTypes/CurioTypeLibrary.cs index 4227514..8ed68d2 100644 --- a/DDFileTypes/CurioTypeLibrary.cs +++ b/DDFileTypes/CurioTypeLibrary.cs @@ -30,12 +30,40 @@ public static async Task LoadFromFileAsync(string filename) public static CurioTypeLibrary Load(string text) { + string[] splitAllowQuotes(string str) + { + List result = new(); + + string? buffer = null; + foreach (var part in str.Split(',')) + { + if (buffer != null) + { + buffer += ',' + part; + if (part.EndsWith('"')) + { + result.Add(buffer); + buffer = null; + } + } + else if (part.StartsWith('"')) + { + buffer = part; + } + else + { + result.Add(part); + } + } + return result.ToArray(); + } + var curios = new List(); var lines = text.Split(new[] { "\n" , "\r\n" }, StringSplitOptions.RemoveEmptyEntries).ToArray(); for (int line = 0; line < lines.Length; line++) { if (lines[line].StartsWith(",,")) continue; // Not the start of a curio entry - var row1 = lines[line].Split(',')[1..]; + var row1 = splitAllowQuotes(lines[line])[1..]; var id = row1[0].TryParseInt(); // Assertion -- ID must exist if (!id.HasValue) @@ -46,16 +74,16 @@ public static CurioTypeLibrary Load(string text) CurioQuality quality = Enum.Parse(row1[3], true); line += 2; - var row2 = lines[line].Split(',')[2..]; + var row2 = splitAllowQuotes(lines[line])[2..]; var idName = row2[0]; var nothing = ParseWeightedCurioEffect(row2.AsSpan()[2..]); line += 1; - var row3 = lines[line].Split(',')[2..]; + var row3 = splitAllowQuotes(lines[line])[2..]; var loot = ParseWeightedCurioEffect(row3.AsSpan()[2..]); line += 1; - var row4 = lines[line].Split(',')[2..]; + var row4 = splitAllowQuotes(lines[line])[2..]; Region region = row4[0] switch { "Darkest Dungeon" => Region.DarkestDungeon, string x => Enum.Parse(x, true) @@ -63,11 +91,11 @@ public static CurioTypeLibrary Load(string text) var quirk = ParseWeightedCurioEffect(row4.AsSpan()[2..]); line += 1; - var row5 = lines[line].Split(',')[2..]; + var row5 = splitAllowQuotes(lines[line])[2..]; var effect = ParseWeightedCurioEffect(row5.AsSpan()[2..]); line += 1; - var row6 = lines[line].Split(',')[2..]; + var row6 = splitAllowQuotes(lines[line])[2..]; var full = row6[0] switch { "Yes" => true, @@ -77,21 +105,21 @@ public static CurioTypeLibrary Load(string text) var purge = ParseWeightedCurioEffect(row6.AsSpan()[2..]); line += 1; - var row7 = lines[line].Split(',')[2..]; + var row7 = splitAllowQuotes(lines[line])[2..]; var scouting = ParseWeightedCurioEffect(row7.AsSpan()[2..]); line += 1; - var row8 = lines[line].Split(',')[2..]; + var row8 = splitAllowQuotes(lines[line])[2..]; var tags = new string[] { row8[0], row8[1], "", "", "", "" }; var teleport = ParseWeightedCurioEffect(row8.AsSpan()[2..]); line += 1; - var row9 = lines[line].Split(',')[2..]; + var row9 = splitAllowQuotes(lines[line])[2..]; tags[2] = row9[0]; tags[3] = row9[1]; var disease = ParseWeightedCurioEffect(row9.AsSpan()[2..]); line += 1; - var row10 = lines[line].Split(',')[2..]; + var row10 = splitAllowQuotes(lines[line])[2..]; tags[4] = row10[0]; tags[5] = row10[1]; line += 1; @@ -99,7 +127,7 @@ public static CurioTypeLibrary Load(string text) while (lines.Length > line + 1 && !lines[line + 1].StartsWith(",,,,,")) // No item field { line += 1; - itemInteractions.Add(ParseItemInteraction(lines[line].Split(',').AsSpan()[4..])); + itemInteractions.Add(ParseItemInteraction(splitAllowQuotes(lines[line]).AsSpan()[4..])); } curios.Add(new Curio(id.Value, name, idName, quality, region, full) { @@ -142,6 +170,8 @@ private static WeightedCurioEffect ParseWeightedCurioEffect(ReadOnlySpan "quirk_pos" => CurioTracker.QuirkPositive, "quirk_neg" => CurioTracker.QuirkNegative, "summon" => CurioTracker.Summon, + "stress" => CurioTracker.Stress, + "heal_stress" => CurioTracker.HealStress, _ => null }, Notes = cells[13] @@ -169,6 +199,8 @@ private static (string, CurioEffect) ParseItemInteraction(ReadOnlySpan c "quirk_pos" => CurioTracker.QuirkPositive, "quirk_neg" => CurioTracker.QuirkNegative, "summon" => CurioTracker.Summon, + "stress" => CurioTracker.Stress, + "heal_stress" => CurioTracker.HealStress, _ => null }, Notes = cells[13] @@ -196,17 +228,36 @@ void addRow(params string[] cells) } string[] makeCurioEffectStrings(CurioEffect? effect) { + float totalWeight = (effect?.Result1Weight ?? 0) + (effect?.Result2Weight ?? 0) + (effect?.Result3Weight ?? 0); + + string getWeightText(int? weight) + { + if (effect!.Type == CurioEffectType.Loot) return "<- # Draws"; + if (weight == null) return ""; + return $"{weight!.Value / totalWeight * 100:N2}%"; + } + + if (effect?.Type == CurioEffectType.Nothing) + { + return Enumerable.Repeat("N/A", 9) + .Concat(new[] + { + "", + effect?.Notes ?? "" + }).ToArray(); + } + return new string[] { effect?.Result1 ?? "", - effect?.Result1Weight.ToString() ?? "", - "", + effect?.Result1Weight switch { 0 => "", null => "", var x => x.ToString()! }, + getWeightText(effect?.Result1Weight), effect?.Result2 ?? "", - effect?.Result2Weight.ToString() ?? "", - "", + effect?.Result2Weight switch { 0 => "", null => "", var x => x.ToString()! }, + getWeightText(effect?.Result2Weight), effect?.Result3 ?? "", - effect?.Result3Weight.ToString() ?? "", - "", + effect?.Result3Weight switch { 0 => "", null => "", var x => x.ToString()! }, + getWeightText(effect?.Result3Weight), effect?.CurioTrackerId switch { CurioTracker.Nothing => "nothing", @@ -218,6 +269,8 @@ string[] makeCurioEffectStrings(CurioEffect? effect) CurioTracker.QuirkPositive => "quirk_pos", CurioTracker.QuirkNegative => "quirk_neg", CurioTracker.Summon => "summon", + CurioTracker.Stress => "stress", + CurioTracker.HealStress => "heal_stress", _ => "" }, effect?.Notes ?? "" @@ -228,22 +281,34 @@ string[] makeCurioEffectStrings(CurioEffect? effect) addRow(); foreach (var curio in Curios.OrderBy(x => x.Id)) { + string getWeightText(WeightedCurioEffect effect) + { + if (effect.Weight == 0) return ""; + return effect.Weight.ToString(); + } + string getWeightPercentageText(WeightedCurioEffect effect) + { + if (effect.Weight == 0) return ""; + return $"{effect.Weight / curio!.Effects.TotalWeight * 100:N2}%"; + } + addRow("", curio.Id.ToString(), curio.Name, "", Enum.GetName(typeof(CurioQuality), curio.Quality) ?? "Mixed"); - addRow("", "", "ID STRING", "", "RESULT TYPES", "WEIGHT", "% CHANCE", "RESULT 1", "R1 WEIGHT", "R1 %", "RESULT 2", "R2 WEIGHT", "R2 %", "RESULT 3", "R3 WEIGHT", "R3 %", "CURIO TACKER ID", "STRING", "NOTES"); - addRow("", "", curio.IdString, "", "Nothing", curio.Effects.Nothing.Weight.ToString()); - addRow(new[] { "", "", "REGION FOUND", "", "Loot", curio.Effects.Loot.Weight.ToString(), "" }.Concat(makeCurioEffectStrings(curio.Effects.Loot)).ToArray()); + addRow("", "", "ID STRING", "", "RESULT TYPES", "WEIGHT", "% CHANCE", "RESULT 1", "R1 WEIGHT", "R1 %", "RESULT 2", "R2 WEIGHT", "R2 %", "RESULT 3", "R3 WEIGHT", "R3 %", "", "STRING", "NOTES"); + addRow(new[] { "", "", curio.IdString, "", "Nothing", getWeightText(curio.Effects.Nothing), getWeightPercentageText(curio.Effects.Nothing) }.Concat(makeCurioEffectStrings(curio.Effects.Nothing)).ToArray()); + addRow(new[] { "", "", "REGION FOUND", "", "Loot", getWeightText(curio.Effects.Loot), getWeightPercentageText(curio.Effects.Loot) }.Concat(makeCurioEffectStrings(curio.Effects.Loot)).ToArray()); addRow(new[] { "", "", curio.RegionFound switch { + Region.All => "ALL", Region.DarkestDungeon => "Darkest Dungeon", Region x => Enum.GetName(typeof(Region), x) ?? "" - }, "", "Quirk", curio.Effects.Quirk.Weight.ToString(), "" }.Concat(makeCurioEffectStrings(curio.Effects.Quirk)).ToArray()); - addRow(new[] { "", "", "FULL CURIO?", "", "Effect", curio.Effects.Effect.Weight.ToString(), "" }.Concat(makeCurioEffectStrings(curio.Effects.Effect)).ToArray()); - addRow(new[] { "", "", curio.FullCurio ? "Yes" : "No", "", "Purge", curio.Effects.Purge.Weight.ToString(), "" }.Concat(makeCurioEffectStrings(curio.Effects.Purge)).ToArray()); - addRow(new[] { "", "", "TAGS", "", "Scouting", curio.Effects.Scouting.Weight.ToString(), "" }.Concat(makeCurioEffectStrings(curio.Effects.Scouting)).ToArray()); - addRow(new[] { "", "", curio.Tags[0], curio.Tags[1], "Teleport", curio.Effects.Teleport.Weight.ToString(), "" }.Concat(makeCurioEffectStrings(curio.Effects.Teleport)).ToArray()); - addRow(new[] { "", "", curio.Tags[2], curio.Tags[3], "Disease", curio.Effects.Disease.Weight.ToString(), "" }.Concat(makeCurioEffectStrings(curio.Effects.Disease)).ToArray()); + }, "", "Quirk", getWeightText(curio.Effects.Quirk), getWeightPercentageText(curio.Effects.Quirk) }.Concat(makeCurioEffectStrings(curio.Effects.Quirk)).ToArray()); + addRow(new[] { "", "", "FULL CURIO?", "", "Effect", getWeightText(curio.Effects.Effect), getWeightPercentageText(curio.Effects.Effect) }.Concat(makeCurioEffectStrings(curio.Effects.Effect)).ToArray()); + addRow(new[] { "", "", curio.FullCurio ? "Yes" : "No", "", "Purge", getWeightText(curio.Effects.Purge), getWeightPercentageText(curio.Effects.Purge) }.Concat(makeCurioEffectStrings(curio.Effects.Purge)).ToArray()); + addRow(new[] { "", "", "TAGS", "", "Scouting", getWeightText(curio.Effects.Scouting), getWeightPercentageText(curio.Effects.Scouting) }.Concat(makeCurioEffectStrings(curio.Effects.Scouting)).ToArray()); + addRow(new[] { "", "", curio.Tags[0], curio.Tags[1], "Teleport", getWeightText(curio.Effects.Teleport), getWeightPercentageText(curio.Effects.Teleport) }.Concat(makeCurioEffectStrings(curio.Effects.Teleport)).ToArray()); + addRow(new[] { "", "", curio.Tags[2], curio.Tags[3], "Disease", getWeightText(curio.Effects.Disease), getWeightPercentageText(curio.Effects.Disease) }.Concat(makeCurioEffectStrings(curio.Effects.Disease)).ToArray()); addRow("", "", curio.Tags[4], curio.Tags[5]); - addRow("", "", "Item Interactions", "", "ITEM", "RESULT TYPE", "", "RESULT 1", "R1 WEIGHT", "R1 %", "RESULT 2", "R2 WEIGHT", "R2 %", "RESULT 3", "R3 WEIGHT", "R3 %", "CURIO TACKER ID", "STRING", "NOTES"); + addRow("", "", "Item Interactions", "", "ITEM", "RESULT TYPE", "", "RESULT 1", "R1 WEIGHT", "R1 %", "RESULT 2", "R2 WEIGHT", "R2 %", "RESULT 3", "R3 WEIGHT", "R3 %", "CURIO TRACKER ID", "STRING", "NOTES"); for (int interactionIndex = 0; interactionIndex < 4; interactionIndex++) { if (interactionIndex < curio.ItemIteractions.Count) diff --git a/DDTypes/Curio.cs b/DDTypes/Curio.cs index f0688b3..a3f9fa6 100644 --- a/DDTypes/Curio.cs +++ b/DDTypes/Curio.cs @@ -73,6 +73,7 @@ public enum CurioTracker Nothing, Loot, HealGeneral, + Stress, HealStress, PurgeNegative, Buff, @@ -92,6 +93,12 @@ public record CurioEffectList public WeightedCurioEffect Scouting { get; init; } = new WeightedCurioEffect(CurioEffectType.Scouting); public WeightedCurioEffect Teleport { get; init; } = new WeightedCurioEffect(CurioEffectType.Teleport); public WeightedCurioEffect Disease { get; init; } = new WeightedCurioEffect(CurioEffectType.Disease); + + public float TotalWeight { get + { + return Nothing.Weight + Loot.Weight + Quirk.Weight + Effect.Weight + + Purge.Weight + Scouting.Weight + Teleport.Weight + Disease.Weight; + } } } public record CurioEffect(CurioEffectType Type) diff --git a/DarkestDungeonRandomizer.csproj b/DarkestDungeonRandomizer.csproj index a90a4e8..c3d50ab 100644 --- a/DarkestDungeonRandomizer.csproj +++ b/DarkestDungeonRandomizer.csproj @@ -5,7 +5,7 @@ netcoreapp5.0 preview - 0.6 + 0.7 diff --git a/ModCreator.cs b/ModCreator.cs index 5686c3e..4d2c99e 100644 --- a/ModCreator.cs +++ b/ModCreator.cs @@ -57,7 +57,7 @@ public static string GetRandomizerUUID(MainViewModel options) (options.RandomizeBosses ? 1 << 6 : 0) + ((int)(options.RandomizeHeroStats * 4) << 7) + /* 3 bits */ (options.RandomizeCampingSkills ? 1 << 10 : 0); - return addin.ToString("x").Trim('0') + options.Seed.ToString("x"); + return addin.ToString("x") + options.Seed.ToString("x8"); } public static void PopulateRandomizerOptionsFromUUID(MainViewModel model, string tag) diff --git a/Randomizers/CurioShuffler.cs b/Randomizers/CurioShuffler.cs index 99556f0..d48edc2 100644 --- a/Randomizers/CurioShuffler.cs +++ b/Randomizers/CurioShuffler.cs @@ -23,6 +23,9 @@ public CurioShuffler(MainViewModel model, Random random) public void Randomize() { + // no need to do anything if nothing is enabled... + if (!(model.RandomizeCurioEffects || model.RandomizeCurioInteractions || model.RandomizeCurioRegions)) return; + var curiosFolder = model.ModDirectory.CreateSubdirectory("curios"); var curios = CurioTypeLibrary.LoadFromFile(model.GetGameDataPath(Path.Combine("curios", "curio_type_library.csv"))); var shuffledCurios = ShuffleCurioTypeLibrary(curios); @@ -56,15 +59,15 @@ private CurioTypeLibrary ShuffleCurioTypeLibrary(CurioTypeLibrary curioTypeLibra var curios = curioTypeLibrary.Curios; if (!model.IncludeShamblerAltar) { - curios = curioTypeLibrary.Curios.Where(x => x.IdString != "shamblers_altar").ToArray(); + curios = curios.Where(x => x.IdString != "shamblers_altar").ToArray(); } if (!model.IncludeStoryCurios) { - curios = curioTypeLibrary.Curios.Where(x => x.FullCurio).ToArray(); + curios = curios.Where(x => x.FullCurio).ToArray(); } - var regions = curioTypeLibrary.Curios.Select(x => x.RegionFound).ToArray(); - var curioEffectLists = curioTypeLibrary.Curios.Select(x => x.Effects); + var regions = curios.Select(x => x.RegionFound).ToArray(); + var curioEffectLists = curios.Select(x => x.Effects); if (model.RandomizeCurioRegions) { regions = regions.Shuffle(random); @@ -155,7 +158,7 @@ private CurioTypeLibrary ShuffleCurioTypeLibrary(CurioTypeLibrary curioTypeLibra if (!model.IncludeShamblerAltar) { - curios = curios.Concat(new[] { curios.First(x => x.IdString != "shamblers_altar") }).ToArray(); + curios = curios.Concat(new[] { curioTypeLibrary.Curios.First(x => x.IdString == "shamblers_altar") }).ToArray(); } if (!model.IncludeStoryCurios) {