diff --git a/ARKBreedingStats/ARKBreedingStats.csproj b/ARKBreedingStats/ARKBreedingStats.csproj index b0efff1c1..e6fc1e5c3 100644 --- a/ARKBreedingStats/ARKBreedingStats.csproj +++ b/ARKBreedingStats/ARKBreedingStats.csproj @@ -84,6 +84,7 @@ + @@ -98,6 +99,7 @@ + @@ -130,6 +132,9 @@ Component + + Form + UserControl @@ -676,6 +681,8 @@ PreserveNewest + + TextTemplatingFileGenerator _manifest.json diff --git a/ARKBreedingStats/App.config b/ARKBreedingStats/App.config index 06dd1ae2d..aa232dee9 100644 --- a/ARKBreedingStats/App.config +++ b/ARKBreedingStats/App.config @@ -511,6 +511,12 @@ True + + False + + + False + diff --git a/ARKBreedingStats/Ark.cs b/ARKBreedingStats/Ark.cs index 70dc623ea..ec557a328 100644 --- a/ARKBreedingStats/Ark.cs +++ b/ARKBreedingStats/Ark.cs @@ -91,10 +91,26 @@ public static class Ark public const byte ColorFirstId = 1; public const byte DyeFirstIdASE = 201; public const byte DyeMaxId = 255; + + /// + /// When choosing a random color for a mutation, ARK can erroneously select an undefined color. For ASE that's the color id 227 (one too high to be defined). + /// + public const byte UndefinedColorIdAse = 227; + + /// + /// When choosing a random color for a mutation, ARK can erroneously select an undefined color. For ASA that's the color id 255 (one too high to be defined). + /// + public const byte UndefinedColorIdAsa = 255; + /// /// When choosing a random color for a mutation, ARK can erroneously select an undefined color. Usually this is color id 227 (one too high to be defined). /// - public const byte UndefinedColorId = 227; + public static byte UndefinedColorId = UndefinedColorIdAse; + + /// + /// Sets the undefined color id to the one of ASE or ASA. + /// + public static void SetUndefinedColorId(bool asa) => UndefinedColorId = asa ? UndefinedColorIdAsa : UndefinedColorIdAse; /// /// Number of possible color regions for all species. diff --git a/ARKBreedingStats/AsbServer/Connection.cs b/ARKBreedingStats/AsbServer/Connection.cs index 40a49a0ce..c8bbda87b 100644 --- a/ARKBreedingStats/AsbServer/Connection.cs +++ b/ARKBreedingStats/AsbServer/Connection.cs @@ -1,13 +1,11 @@ using System; using System.IO; using System.Linq; -using System.Net; using System.Net.Http; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; -using System.Xml; using ARKBreedingStats.importExportGun; using ARKBreedingStats.Library; using Newtonsoft.Json.Linq; @@ -21,83 +19,115 @@ internal static class Connection { private const string ApiUri = "https://export.arkbreeder.com/api/v1/"; - private static SimpleCancellationToken _lastCancellationToken; + private static CancellationTokenSource _lastCancellationTokenSource; public static async void StartListeningAsync( - IProgress<(string jsonText, string serverHash, string message)> progressDataSent, string token = null) + IProgress progressDataSent, string token = null) { if (string.IsNullOrEmpty(token)) return; // stop previous listening if any StopListening(); - var cancellationToken = new SimpleCancellationToken(); - _lastCancellationToken = cancellationToken; - var requestUri = ApiUri + "listen/" + token; // "https://httpstat.us/429"; - - try + using (var cancellationTokenSource = new CancellationTokenSource()) { - var client = FileService.GetHttpClient; - using (var response = await client.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead)) + _lastCancellationTokenSource = cancellationTokenSource; + + var reconnectTries = 0; + + while (!cancellationTokenSource.Token.IsCancellationRequested) { - if (!response.IsSuccessStatusCode) - { - var statusCode = (int)response.StatusCode; - string serverMessage = await response.Content.ReadAsStringAsync(); + var requestUri = ApiUri + "listen/" + token; // "https://httpstat.us/429"; - try - { - serverMessage = JObject.Parse(serverMessage).SelectToken("error.message").ToString(); - } - catch + try + { + var client = FileService.GetHttpClient; + using (var response = await client.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead)) { - // server message in unknown format, use raw content string - } + if (!response.IsSuccessStatusCode) + { + var statusCode = (int)response.StatusCode; + string serverMessage = await response.Content.ReadAsStringAsync(); - serverMessage = Environment.NewLine + serverMessage; + try + { + serverMessage = JObject.Parse(serverMessage).SelectToken("error.message").ToString(); + } + catch + { + // server message in unknown format, use raw content string + } - switch (statusCode) - { - case 400: // Bad Request - WriteMessage($"Something went wrong with the server connection.{serverMessage}", response); - return; - case 429: // Too Many Requests - WriteMessage($"The server is currently at the rate limit and cannot process the request. Try again later.{serverMessage}", response); - return; - case 507: // Insufficient Storage - WriteMessage($"Too many connections to the server. Try again later.{serverMessage}", response); - return; - default: - var errorMessage = statusCode >= 500 - ? "Something went wrong with the server or its proxy." + Environment.NewLine - : null; - WriteMessage($"{errorMessage}{serverMessage}", response); - return; + serverMessage = Environment.NewLine + serverMessage; + + switch (statusCode) + { + case 400: // Bad Request + WriteErrorMessage($"Something went wrong with the server connection.{serverMessage}", + response); + return; + case 429: // Too Many Requests + WriteErrorMessage( + $"The server is currently at the rate limit and cannot process the request. Try again later.{serverMessage}", + response); + return; + case 507: // Insufficient Storage + WriteErrorMessage($"Too many connections to the server. Try again later.{serverMessage}", + response); + return; + default: + var errorMessage = statusCode >= 500 + ? "Something went wrong with the server or its proxy." + Environment.NewLine + : null; + WriteErrorMessage($"{errorMessage}{serverMessage}", response); + return; + } + } + + reconnectTries = 0; + + using (var stream = await response.Content.ReadAsStreamAsync()) + using (var reader = new StreamReader(stream)) + { + var report = await ReadServerSentEvents(reader, progressDataSent, token, cancellationTokenSource.Token); + if (report != null) + { + progressDataSent.Report(report); + if (report.StopListening) + { + StopListening(); + } + } + } } } - - using (var stream = await response.Content.ReadAsStreamAsync()) - using (var reader = new StreamReader(stream)) + catch (Exception ex) { - await ReadServerSentEvents(reader, progressDataSent, token, cancellationToken); + var tryToReconnect = reconnectTries++ < 3; + WriteErrorMessage( + $"ASB Server listening {ex.GetType()}: {ex.Message}{Environment.NewLine}{(tryToReconnect ? "Trying to reconnect" + Environment.NewLine : string.Empty)}Stack trace: {ex.StackTrace}", + stopListening: !tryToReconnect); + + if (!tryToReconnect) + break; + // try to reconnect after some time + Thread.Sleep(10_000); } - } - } - catch (Exception ex) - { - WriteMessage($"ASB Server listening exception:\n{ex.Message}\n\nStack trace:\n{ex.StackTrace}"); - } - finally - { + finally + { #if DEBUG - Console.WriteLine($"ASB Server listening stopped using token: {token}"); + Console.WriteLine($"ASB Server listening stopped using token: {token}"); #endif + } + } } + _lastCancellationTokenSource = null; + return; // Displays an error message in the UI, also logs on the console if in debug mode - void WriteMessage(string message, HttpResponseMessage response = null) + void WriteErrorMessage(string message, HttpResponseMessage response = null, bool stopListening = true) { if (response != null) { @@ -106,17 +136,24 @@ void WriteMessage(string message, HttpResponseMessage response = null) #if DEBUG Console.WriteLine(message); #endif - progressDataSent.Report((null, null, message)); + progressDataSent.Report(new ProgressReportAsbServer { Message = message, StopListening = stopListening, IsError = true }); } } private static Regex _eventRegex = new Regex(@"^event: (welcome|ping|replaced|export|server|closing)(?: (\-?\d+))?(?:\ndata:\s(.+))?$"); - private static async Task ReadServerSentEvents(StreamReader reader, IProgress<(string jsonText, string serverHash, string message)> progressDataSent, string token, SimpleCancellationToken cancellationToken) + private static async Task ReadServerSentEvents(StreamReader reader, IProgress progressDataSent, string token, CancellationToken cancellationToken) { #if DEBUG Console.WriteLine($"Now listening using token: {token}"); #endif + progressDataSent.Report(new ProgressReportAsbServer + { + Message = "Now listening to the export server using the token (also copied to clipboard)", + ServerToken = token, + ClipboardText = token + }); + while (!cancellationToken.IsCancellationRequested) { var received = await reader.ReadLineAsync(); @@ -133,16 +170,19 @@ private static async Task ReadServerSentEvents(StreamReader reader, IProgress<(s case "event: ping": continue; case "event: replaced": - if (!cancellationToken.IsCancellationRequested) - progressDataSent.Report((null, null, - "ASB Server listening stopped. Connection used by a different user")); - return; + if (cancellationToken.IsCancellationRequested) return null; + + return new ProgressReportAsbServer + { + Message = "ASB Server listening stopped. Connection used by a different user", + StopListening = true, + IsError = true + }; case "event: closing": // only report closing if the user hasn't done this already - if (!cancellationToken.IsCancellationRequested) - progressDataSent.Report((null, null, - "ASB Server listening stopped. Connection closed by the server")); - return; + if (cancellationToken.IsCancellationRequested) return null; + return new ProgressReportAsbServer + { Message = "ASB Server listening stopped. Connection closed by the server, trying to reconnect", StopListening = false, IsError = true }; } if (received != "event: export" && !received.StartsWith("event: server")) @@ -160,23 +200,28 @@ private static async Task ReadServerSentEvents(StreamReader reader, IProgress<(s switch (m.Groups[1].Value) { case "export": - progressDataSent.Report((m.Groups[3].Value, null, null)); + progressDataSent.Report(new ProgressReportAsbServer { JsonText = m.Groups[3].Value }); break; case "server": - progressDataSent.Report((m.Groups[3].Value, m.Groups[2].Value, null)); + progressDataSent.Report(new ProgressReportAsbServer { JsonText = m.Groups[3].Value, ServerHash = m.Groups[2].Value }); break; } } } + + return null; } + /// + /// Stops the currently running listener. Returns false if no listener was running. + /// public static void StopListening() { - if (_lastCancellationToken == null) + if (_lastCancellationTokenSource == null) return; // nothing to stop - _lastCancellationToken.Cancel(); - _lastCancellationToken = null; + _lastCancellationTokenSource.Cancel(); + _lastCancellationTokenSource = null; } /// @@ -227,12 +272,10 @@ public static string CreateNewToken() } /// - /// Simple replacement of CancellationTokenSource to avoid unnecessary complexities with disposal of CTS when the token is still in use. + /// Returns the passed token string, or wildcards if the streamer mode is enabled. /// - private class SimpleCancellationToken - { - public bool IsCancellationRequested; - public void Cancel() => IsCancellationRequested = true; - } + public static string TokenStringForDisplay(string token) => Properties.Settings.Default.StreamerMode ? "****" : token; + + public static bool IsCurrentlyListening => _lastCancellationTokenSource != null; } } diff --git a/ARKBreedingStats/AsbServer/ProgressReportAsbServer.cs b/ARKBreedingStats/AsbServer/ProgressReportAsbServer.cs new file mode 100644 index 000000000..b8218e772 --- /dev/null +++ b/ARKBreedingStats/AsbServer/ProgressReportAsbServer.cs @@ -0,0 +1,16 @@ +namespace ARKBreedingStats.AsbServer +{ + /// + /// Info of progress reports while listening to an AsbServer. + /// + internal class ProgressReportAsbServer + { + public string JsonText; + public string ServerHash; + public string Message; + public string ServerToken; + public bool IsError; + public bool StopListening; + public string ClipboardText; + } +} diff --git a/ARKBreedingStats/BreedingPlanning/BreedingPlan.cs b/ARKBreedingStats/BreedingPlanning/BreedingPlan.cs index bdb553126..3223138f2 100644 --- a/ARKBreedingStats/BreedingPlanning/BreedingPlan.cs +++ b/ARKBreedingStats/BreedingPlanning/BreedingPlan.cs @@ -52,7 +52,7 @@ public partial class BreedingPlan : UserControl private bool[] _enabledColorRegions; private TimeSpan _incubationTime; private Creature _chosenCreature; - private BreedingMode _breedingMode; + private BreedingScore.BreedingMode _breedingMode; public readonly StatWeighting StatWeighting; public bool BreedingPlanNeedsUpdate; private bool _speciesInfoNeedsUpdate; @@ -76,7 +76,7 @@ public BreedingPlan() for (int i = 0; i < Stats.StatsCount; i++) _statWeights[i] = 1; - _breedingMode = BreedingMode.TopStatsConservative; + _breedingMode = BreedingScore.BreedingMode.TopStatsConservative; _breedingPairs = new List(); pedigreeCreatureBest.SetIsVirtual(true); @@ -286,9 +286,23 @@ private void DoCalculateBreedingScoresAndDisplayPairs() bool considerMutationLimit = nudBPMutationLimit.Value >= 0; bool creaturesMutationsFilteredOut = false; + + // only consider creatures with top stats if breeding for that + Creature[] females, males; + if (_breedingMode == BreedingScore.BreedingMode.BestNextGen) + { + females = _females; + males = _males; + } + else + { + females = _females.Where(c => c.topStatsCountBP > 0).ToArray(); + males = _males?.Where(c => c.topStatsCountBP > 0).ToArray(); + } + // filter by tags - int crCountF = _females.Length; - int crCountM = _males?.Length ?? 0; + int crCountF = females.Length; + int crCountM = males?.Length ?? 0; IEnumerable selectFemales; IEnumerable selectMales = null; if (considerChosenCreature && (_chosenCreature.sex == Sex.Female || _currentSpecies.noGender)) @@ -297,10 +311,10 @@ private void DoCalculateBreedingScoresAndDisplayPairs() } else if (!cbBPMutationLimitOnlyOnePartner.Checked && considerMutationLimit) { - selectFemales = FilterByTags(_females.Where(c => c.Mutations <= nudBPMutationLimit.Value)); - creaturesMutationsFilteredOut = _females.Any(c => c.Mutations > nudBPMutationLimit.Value); + selectFemales = FilterByTags(females.Where(c => c.Mutations <= nudBPMutationLimit.Value)); + creaturesMutationsFilteredOut = females.Any(c => c.Mutations > nudBPMutationLimit.Value); } - else selectFemales = FilterByTags(_females); + else selectFemales = FilterByTags(females); if (considerChosenCreature && !_currentSpecies.noGender && _chosenCreature.sex == Sex.Male) { @@ -308,14 +322,14 @@ private void DoCalculateBreedingScoresAndDisplayPairs() } else if (!cbBPMutationLimitOnlyOnePartner.Checked && considerMutationLimit) { - if (_males != null) + if (males != null) { - selectMales = FilterByTags(_males.Where(c => c.Mutations <= nudBPMutationLimit.Value)); + selectMales = FilterByTags(males.Where(c => c.Mutations <= nudBPMutationLimit.Value)); creaturesMutationsFilteredOut = creaturesMutationsFilteredOut || - _males.Any(c => c.Mutations > nudBPMutationLimit.Value); + males.Any(c => c.Mutations > nudBPMutationLimit.Value); } } - else selectMales = FilterByTags(_males); + else selectMales = FilterByTags(males); // filter by servers if (cbServerFilterLibrary.Checked && (Settings.Default.FilterHideServers?.Any() ?? false)) @@ -401,18 +415,16 @@ private void DoCalculateBreedingScoresAndDisplayPairs() ref creaturesMutationsFilteredOut, levelLimitWithOutDomLevels, CbDontSuggestOverLimitOffspring.Checked, cbBPOnlyOneSuggestionForFemales.Checked, _statOddEvens); - //double minScore = _breedingPairs.LastOrDefault()?.BreedingScore ?? 0; - //if (minScore < 0) - //{ - // foreach (BreedingPair bp in _breedingPairs) - // bp.BreedingScore -= minScore; - //} + double minScore = _breedingPairs.LastOrDefault()?.BreedingScore.OneNumber ?? 0; + var displayScoreOffset = (minScore < 0 ? -minScore : 0) + .5; // don't display negative scores, could be confusing + + _breedingPairs = _breedingPairs.Take(CreatureCollection.maxBreedingSuggestions).ToList(); var sb = new StringBuilder(); // draw best parents using (var brush = new SolidBrush(Color.Black)) { - for (int i = 0; i < _breedingPairs.Count && i < CreatureCollection.maxBreedingSuggestions; i++) + for (int i = 0; i < _breedingPairs.Count; i++) { PedigreeCreature pc; if (2 * i < _pcs.Count) @@ -486,7 +498,7 @@ private void DoCalculateBreedingScoresAndDisplayPairs() sb.AppendLine(_breedingPairs[i].Father + " can produce a mutation."); } - var colorPercent = (int)(_breedingPairs[i].BreedingScore.OneNumber * 12.5); + var colorPercent = (int)((_breedingPairs[i].BreedingScore.OneNumber + displayScoreOffset) * 12.5); // outline brush.Color = Utils.GetColorFromPercent(colorPercent, -.2); g.FillRectangle(brush, 0, 15, 87, 5); @@ -504,7 +516,7 @@ private void DoCalculateBreedingScoresAndDisplayPairs() } // breeding score text brush.Color = Color.Black; - g.DrawString(_breedingPairs[i].BreedingScore.ToString("N4"), + g.DrawString((_breedingPairs[i].BreedingScore.Primary + displayScoreOffset).ToString("N4"), new Font("Microsoft Sans Serif", 8.25f), brush, 24, 12); pb.Image = bm; } @@ -526,7 +538,7 @@ private void DoCalculateBreedingScoresAndDisplayPairs() SetParents(0); // if breeding mode is conservative and a creature with top-stats already exists, the scoring might seem off - if (_breedingMode == BreedingMode.TopStatsConservative) + if (_breedingMode == BreedingScore.BreedingMode.TopStatsConservative) { bool bestCreatureAlreadyAvailable = true; Creature bestCreature = null; @@ -795,7 +807,7 @@ private void SetBestLevels(int[] bestLevels, IEnumerable creatures, bo crB.levelsWild[s] = bestLevels[s]; if (crB.levelsWild[s] == -1) totalLevelUnknown = true; - crB.topBreedingStats[s] = crB.levelsWild[s] > 0 && crB.levelsWild[s] == _bestLevels[s]; + crB.SetTopStat(s, crB.levelsWild[s] > 0 && crB.levelsWild[s] == _bestLevels[s]); } crB.levelsWild[Stats.Torpidity] = crB.levelsWild.Sum(); crB.RecalculateCreatureValues(levelStep); @@ -840,26 +852,26 @@ private void SetParents(int comboIndex) crW.Father = father; double probabilityBest = 1; bool totalLevelUnknown = false; // if stats are unknown, total level is as well (==> oxygen, speed) - bool topStatBreedingMode = _breedingMode == BreedingMode.TopStatsConservative || _breedingMode == BreedingMode.TopStatsLucky; + bool topStatBreedingMode = _breedingMode == BreedingScore.BreedingMode.TopStatsConservative || _breedingMode == BreedingScore.BreedingMode.TopStatsLucky; for (int s = 0; s < Stats.StatsCount; s++) { if (s == Stats.Torpidity) continue; crB.levelsWild[s] = _statWeights[s] < 0 ? Math.Min(mother.levelsWild[s], father.levelsWild[s]) : BreedingScore.GetHigherBestLevel(mother.levelsWild[s], father.levelsWild[s], _statOddEvens[s]); crB.levelsMutated[s] = (crB.levelsWild[s] == mother.levelsWild[s] ? mother : father).levelsMutated?[s] ?? 0; crB.valuesBreeding[s] = StatValueCalculation.CalculateValue(_currentSpecies, s, crB.levelsWild[s], crB.levelsMutated[s], 0, true, 1, 0); - crB.topBreedingStats[s] = (_currentSpecies.stats[s].IncPerTamedLevel != 0 && crB.levelsWild[s] == _bestLevels[s]); + crB.SetTopStat(s, _currentSpecies.stats[s].IncPerTamedLevel != 0 && crB.levelsWild[s] == _bestLevels[s]); crW.levelsWild[s] = _statWeights[s] < 0 ? Math.Max(mother.levelsWild[s], father.levelsWild[s]) : Math.Min(mother.levelsWild[s], father.levelsWild[s]); crB.levelsMutated[s] = (crW.levelsWild[s] == mother.levelsWild[s] ? mother : father).levelsMutated?[s] ?? 0; crW.valuesBreeding[s] = StatValueCalculation.CalculateValue(_currentSpecies, s, crW.levelsWild[s], crW.levelsMutated[s], 0, true, 1, 0); - crW.topBreedingStats[s] = (_currentSpecies.stats[s].IncPerTamedLevel != 0 && crW.levelsWild[s] == _bestLevels[s]); + crW.SetTopStat(s, _currentSpecies.stats[s].IncPerTamedLevel != 0 && crW.levelsWild[s] == _bestLevels[s]); if (crB.levelsWild[s] == -1 || crW.levelsWild[s] == -1) totalLevelUnknown = true; // in top stats breeding mode consider only probability of top stats if (crB.levelsWild[s] > crW.levelsWild[s] - && (!topStatBreedingMode || crB.topBreedingStats[s])) + && (!topStatBreedingMode || crB.IsTopStat(s))) probabilityBest *= Ark.ProbabilityInheritHigherLevel; else if (crB.levelsWild[s] < crW.levelsWild[s] - && (!topStatBreedingMode || crB.topBreedingStats[s])) + && (!topStatBreedingMode || crB.IsTopStat(s))) probabilityBest *= Ark.ProbabilityInheritLowerLevel; } crB.levelsWild[Stats.Torpidity] = crB.levelsWild.Sum(); @@ -984,7 +996,7 @@ private void radioButtonBPTopStatsCn_CheckedChanged(object sender, EventArgs e) { if (rbBPTopStatsCn.Checked) { - _breedingMode = BreedingMode.TopStatsConservative; + _breedingMode = BreedingScore.BreedingMode.TopStatsConservative; CalculateBreedingScoresAndDisplayPairs(); } } @@ -993,7 +1005,7 @@ private void radioButtonBPTopStats_CheckedChanged(object sender, EventArgs e) { if (rbBPTopStats.Checked) { - _breedingMode = BreedingMode.TopStatsLucky; + _breedingMode = BreedingScore.BreedingMode.TopStatsLucky; CalculateBreedingScoresAndDisplayPairs(); } } @@ -1002,7 +1014,7 @@ private void radioButtonBPHighStats_CheckedChanged(object sender, EventArgs e) { if (rbBPHighStats.Checked) { - _breedingMode = BreedingMode.BestNextGen; + _breedingMode = BreedingScore.BreedingMode.BestNextGen; CalculateBreedingScoresAndDisplayPairs(); } } @@ -1096,13 +1108,6 @@ public bool IgnoreSexInBreedingPlan set => CbIgnoreSexInPlanning.Checked = value; } - public enum BreedingMode - { - BestNextGen, - TopStatsLucky, - TopStatsConservative - } - private void cbTagExcludeDefault_CheckedChanged(object sender, EventArgs e) { CalculateBreedingScoresAndDisplayPairs(); diff --git a/ARKBreedingStats/BreedingPlanning/BreedingScore.cs b/ARKBreedingStats/BreedingPlanning/BreedingScore.cs index d5b05bc90..1c6c5415b 100644 --- a/ARKBreedingStats/BreedingPlanning/BreedingScore.cs +++ b/ARKBreedingStats/BreedingPlanning/BreedingScore.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using ARKBreedingStats.Library; -using ARKBreedingStats.Properties; using ARKBreedingStats.species; namespace ARKBreedingStats.BreedingPlanning @@ -32,7 +31,7 @@ public static class BreedingScore /// Array for each stat if the higher level should be considered for score: 0: consider any level, 1: consider only if odd, 2: consider only if even. /// public static List CalculateBreedingScores(Creature[] females, Creature[] males, Species species, - short[] bestPossLevels, double[] statWeights, int[] bestLevelsOfSpecies, BreedingPlan.BreedingMode breedingMode, + short[] bestPossLevels, double[] statWeights, int[] bestLevelsOfSpecies, BreedingMode breedingMode, bool considerChosenCreature, bool considerMutationLimit, int mutationLimit, ref bool creaturesMutationsFilteredOut, int offspringLevelLimit = 0, bool downGradeOffspringWithLevelHigherThanLimit = false, bool onlyBestSuggestionForFemale = false, byte[] anyOddEven = null) @@ -86,8 +85,8 @@ public static List CalculateBreedingScores(Creature[] females, Cre { if (s == Stats.Torpidity || !species.UsesStat(s)) continue; bestPossLevels[s] = 0; - int higherLevel = Math.Max(female.levelsWild[s] + (female.levelsMutated?[s] ?? 0), male.levelsWild[s] + (male.levelsMutated?[s] ?? 0)); - int lowerLevel = Math.Min(female.levelsWild[s] + (female.levelsMutated?[s] ?? 0), male.levelsWild[s] + (male.levelsMutated?[s] ?? 0)); + int higherLevel = Math.Max(female.levelsWild[s], male.levelsWild[s]); + int lowerLevel = Math.Min(female.levelsWild[s], male.levelsWild[s]); if (higherLevel < 0) higherLevel = 0; if (lowerLevel < 0) lowerLevel = 0; maxPossibleOffspringLevel += higherLevel; @@ -112,7 +111,7 @@ public static List CalculateBreedingScores(Creature[] females, Cre double weightedExpectedStatLevel = statWeights[s] * (Ark.ProbabilityInheritHigherLevel * higherLevel + Ark.ProbabilityInheritLowerLevel * lowerLevel) / 40; if (weightedExpectedStatLevel != 0) { - if (breedingMode == BreedingPlan.BreedingMode.TopStatsLucky) + if (breedingMode == BreedingMode.TopStatsLucky) { if (!ignoreTopStats && (female.levelsWild[s] == bestLevelsOfSpecies[s] || male.levelsWild[s] == bestLevelsOfSpecies[s])) { @@ -122,7 +121,7 @@ public static List CalculateBreedingScores(Creature[] females, Cre else if (bestLevelsOfSpecies[s] > 0) weightedExpectedStatLevel *= .01; } - else if (breedingMode == BreedingPlan.BreedingMode.TopStatsConservative && bestLevelsOfSpecies[s] > 0) + else if (breedingMode == BreedingMode.TopStatsConservative && bestLevelsOfSpecies[s] > 0) { bool higherIsBetter = statWeights[s] >= 0; bestPossLevels[s] = (short)(higherIsBetter ? Math.Max(female.levelsWild[s], male.levelsWild[s]) : Math.Min(female.levelsWild[s], male.levelsWild[s])); @@ -141,7 +140,7 @@ public static List CalculateBreedingScores(Creature[] females, Cre } } - if (breedingMode == BreedingPlan.BreedingMode.TopStatsConservative) + if (breedingMode == BreedingMode.TopStatsConservative) { if (topStatsMother < offspringPotentialTopStatCount && topStatsFather < offspringPotentialTopStatCount) t += offspringExpectedTopStatCount; @@ -275,5 +274,12 @@ public static int GetHigherBestLevel(int level1, int level2, byte anyOddEven) default: return Math.Max(level1, level2); } } + + public enum BreedingMode + { + BestNextGen, + TopStatsLucky, + TopStatsConservative + } } } diff --git a/ARKBreedingStats/CreatureInfoInput.cs b/ARKBreedingStats/CreatureInfoInput.cs index 56f15bc04..4b226c548 100644 --- a/ARKBreedingStats/CreatureInfoInput.cs +++ b/ARKBreedingStats/CreatureInfoInput.cs @@ -720,7 +720,7 @@ private void SetAdd2LibColor(bool buttonEnabled) { btAdd2Library.BackColor = !buttonEnabled ? SystemColors.Control - : _alreadyExistingCreature != null ? Color.LightGreen + : _alreadyExistingCreature == null ? Color.LightGreen : Color.LightSkyBlue; } diff --git a/ARKBreedingStats/Extraction.cs b/ARKBreedingStats/Extraction.cs index 933ed9e01..745ae8cf1 100644 --- a/ARKBreedingStats/Extraction.cs +++ b/ARKBreedingStats/Extraction.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using ARKBreedingStats.uiControls; namespace ARKBreedingStats { diff --git a/ARKBreedingStats/FileService.cs b/ARKBreedingStats/FileService.cs index c46b620bd..405e705c7 100644 --- a/ARKBreedingStats/FileService.cs +++ b/ARKBreedingStats/FileService.cs @@ -285,7 +285,7 @@ internal static bool IsValidJsonFile(string filePath) private static HttpClient _httpClient; /// - /// Returns a static HttpClient. It's apparently better to reuse on object per app only. + /// Returns a static HttpClient. It's apparently better to reuse one object per app only. /// public static HttpClient GetHttpClient { diff --git a/ARKBreedingStats/Form1.Designer.cs b/ARKBreedingStats/Form1.Designer.cs index 68e2741b4..e97111173 100644 --- a/ARKBreedingStats/Form1.Designer.cs +++ b/ARKBreedingStats/Form1.Designer.cs @@ -385,6 +385,7 @@ private void InitializeComponent() this.toolStripSeparator27 = new System.Windows.Forms.ToolStripSeparator(); this.resetColumnOrderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.speciesSelector1 = new ARKBreedingStats.SpeciesSelector(); + this.currentTokenToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.groupBox1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.numericUpDownImprintingBonusTester)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.NumericUpDownTestingTE)).BeginInit(); @@ -1342,6 +1343,7 @@ private void InitializeComponent() // this.serverToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.listenToolStripMenuItem, + this.currentTokenToolStripMenuItem, this.listenWithNewTokenToolStripMenuItem, this.sendExampleCreatureToolStripMenuItem}); this.serverToolStripMenuItem.Name = "serverToolStripMenuItem"; @@ -3781,6 +3783,13 @@ private void InitializeComponent() this.speciesSelector1.SplitterDistance = 500; this.speciesSelector1.TabIndex = 0; // + // currentTokenToolStripMenuItem + // + this.currentTokenToolStripMenuItem.Name = "currentTokenToolStripMenuItem"; + this.currentTokenToolStripMenuItem.Size = new System.Drawing.Size(194, 22); + this.currentTokenToolStripMenuItem.Text = "Current token"; + this.currentTokenToolStripMenuItem.Click += new System.EventHandler(this.currentTokenToolStripMenuItem_Click); + // // Form1 // this.AcceptButton = this.btExtractLevels; @@ -4241,5 +4250,6 @@ private void InitializeComponent() private System.Windows.Forms.Label label5; private System.Windows.Forms.CheckBox CbLinkWildMutatedLevelsTester; private System.Windows.Forms.ToolStripMenuItem toolStripMenuItemMutationColumns; + private System.Windows.Forms.ToolStripMenuItem currentTokenToolStripMenuItem; } } diff --git a/ARKBreedingStats/Form1.collection.cs b/ARKBreedingStats/Form1.collection.cs index c938fc068..d2f3af6af 100644 --- a/ARKBreedingStats/Form1.collection.cs +++ b/ARKBreedingStats/Form1.collection.cs @@ -15,6 +15,8 @@ using ARKBreedingStats.importExportGun; using ARKBreedingStats.uiControls; using ARKBreedingStats.utils; +using ARKBreedingStats.AsbServer; +using Newtonsoft.Json.Linq; namespace ARKBreedingStats { @@ -945,24 +947,40 @@ private void UpdateListsAfterCreaturesAdded() } /// - /// Imports a creature when listening to a server. + /// Handle reports from the AsbServer listening, e.g. importing creatures or handle errors. /// - private void AsbServerDataSent((string jsonData, string serverHash, string errorMessage) data) + private void AsbServerDataSent(ProgressReportAsbServer data) { - if (!string.IsNullOrEmpty(data.errorMessage)) + if (!string.IsNullOrEmpty(data.Message)) { - SetMessageLabelText(data.errorMessage, MessageBoxIcon.Error); - // don't remove the error message with the stop listening message - _ignoreNextMessageLabel = true; - listenToolStripMenuItem.Checked = false; + var displayPopup = false; + var message = data.Message; + if (!string.IsNullOrEmpty(data.ServerToken)) + { + message += Environment.NewLine + Connection.TokenStringForDisplay(data.ServerToken); + displayPopup = !Properties.Settings.Default.StreamerMode; + } + + SetMessageLabelText(message, data.IsError ? MessageBoxIcon.Error : MessageBoxIcon.Information, clipboardText: data.ClipboardText, displayPopup: displayPopup); + + if (!string.IsNullOrEmpty(data.ClipboardText)) + Clipboard.SetText(data.ClipboardText); + + if (data.StopListening) + { + // don't remove the error message with the stop listening message + _ignoreNextMessageLabel = true; + listenToolStripMenuItem.Checked = false; + } + return; } string resultText; - if (string.IsNullOrEmpty(data.serverHash)) + if (string.IsNullOrEmpty(data.ServerHash)) { // import creature - var creature = ImportExportGun.ImportCreatureFromJson(data.jsonData, null, out resultText, out _); + var creature = ImportExportGun.ImportCreatureFromJson(data.JsonText, null, out resultText, out _); if (creature == null) { SetMessageLabelText(resultText, MessageBoxIcon.Error); @@ -987,7 +1005,7 @@ private void AsbServerDataSent((string jsonData, string serverHash, string error } // import server settings - var success = ImportExportGun.ImportServerMultipliersFromJson(_creatureCollection, data.jsonData, data.serverHash, out resultText); + var success = ImportExportGun.ImportServerMultipliersFromJson(_creatureCollection, data.JsonText, data.ServerHash, out resultText); SetMessageLabelText(resultText, success ? MessageBoxIcon.Information : MessageBoxIcon.Error, resultText); } } diff --git a/ARKBreedingStats/Form1.cs b/ARKBreedingStats/Form1.cs index 4e2dd11b3..caca52f1b 100644 --- a/ARKBreedingStats/Form1.cs +++ b/ARKBreedingStats/Form1.cs @@ -21,6 +21,7 @@ using ARKBreedingStats.utils; using static ARKBreedingStats.settings.Settings; using Color = System.Drawing.Color; +using ARKBreedingStats.AsbServer; namespace ARKBreedingStats { @@ -31,11 +32,12 @@ public partial class Form1 : Form private bool _collectionDirty; /// - /// List of all top stats per species + /// List of all highest stats per species /// - private readonly Dictionary _topLevels = new Dictionary(); - - private readonly Dictionary _lowestLevels = new Dictionary(); + private readonly Dictionary _highestSpeciesLevels = new Dictionary(); + private readonly Dictionary _lowestSpeciesLevels = new Dictionary(); + private readonly Dictionary _highestSpeciesMutationLevels = new Dictionary(); + private readonly Dictionary _lowestSpeciesMutationLevels = new Dictionary(); private readonly StatIO[] _statIOs = new StatIO[Stats.StatsCount]; private readonly StatIO[] _testingIOs = new StatIO[Stats.StatsCount]; private int _activeStatIndex = -1; @@ -53,8 +55,8 @@ public delegate void Species species = null, // if null is passed for species, breeding-related controls are not updated bool triggeredByFileWatcher = false); - public delegate void SetMessageLabelTextEventHandler(string text = null, - MessageBoxIcon icon = MessageBoxIcon.None, string path = null, string clipboardContent = null); + public delegate void SetMessageLabelTextEventHandler(string text = null, MessageBoxIcon icon = MessageBoxIcon.None, + string path = null, string clipboardContent = null, bool displayPopup = false); private bool _updateTorporInTester; private bool _filterListAllowed; @@ -631,7 +633,7 @@ private void ToggleViewSpeciesSelector(bool showSpeciesSelector) private void TbSpeciesGlobal_KeyUp(object sender, KeyEventArgs e) { if (e.KeyCode != Keys.Enter && e.KeyCode != Keys.Tab) return; - if (speciesSelector1.SetSpeciesByName(tbSpeciesGlobal.Text)) + if (speciesSelector1.SetSpeciesByEntryName(tbSpeciesGlobal.Text)) ToggleViewSpeciesSelector(false); } @@ -734,7 +736,7 @@ private void SpeciesSelector1OnSpeciesSelected(bool speciesChanged) breedingPlan1.SetSpecies(species); } } - hatching1.SetSpecies(species, _topLevels.TryGetValue(species, out var bl) ? bl : null, _lowestLevels.TryGetValue(species, out var ll) ? ll : null); + hatching1.SetSpecies(species, _highestSpeciesLevels.TryGetValue(species, out var bl) ? bl : null, _lowestSpeciesLevels.TryGetValue(species, out var ll) ? ll : null); _hiddenLevelsCreatureTester = 0; @@ -1350,6 +1352,7 @@ private void Form1_FormClosed(object sender, FormClosedEventArgs e) // remove old cache-files CreatureColored.CleanupCache(); + AsbServerStopListening(false); _tt?.Dispose(); _timerGlobal?.Dispose(); } @@ -1362,7 +1365,7 @@ private void Form1_FormClosed(object sender, FormClosedEventArgs e) /// If valid path to file or folder, the user can click on the message to display the path in the explorer /// If not null, user can copy this text to the clipboard by clicking on the label private void SetMessageLabelText(string text = null, MessageBoxIcon icon = MessageBoxIcon.None, - string path = null, string clipboardText = null) + string path = null, string clipboardText = null, bool displayPopup = false) { if (_ignoreNextMessageLabel) { @@ -1388,6 +1391,8 @@ private void SetMessageLabelText(string text = null, MessageBoxIcon icon = Messa TbMessageLabel.BackColor = SystemColors.Control; break; } + if (displayPopup && !string.IsNullOrEmpty(text)) + PopupMessage.Show(this, text, 20); } /// @@ -3049,8 +3054,8 @@ private void CreatureInfoInput_CreatureDataRequested(CreatureInfoInput input, bo if (openPatternEditor) { - input.OpenNamePatternEditor(cr, _topLevels.TryGetValue(cr.Species, out var tl) ? tl : null, - _lowestLevels.TryGetValue(cr.Species, out var ll) ? ll : null, + input.OpenNamePatternEditor(cr, _highestSpeciesLevels.TryGetValue(cr.Species, out var tl) ? tl : null, + _lowestSpeciesLevels.TryGetValue(cr.Species, out var ll) ? ll : null, _customReplacingNamingPattern, namingPatternIndex, ReloadNamePatternCustomReplacings); UpdatePatternButtons(); @@ -3069,8 +3074,8 @@ private void CreatureInfoInput_CreatureDataRequested(CreatureInfoInput input, bo colorAlreadyExistingInformation = _creatureCollection.ColorAlreadyAvailable(cr.Species, input.RegionColors, out _); input.ColorAlreadyExistingInformation = colorAlreadyExistingInformation; - input.GenerateCreatureName(cr, alreadyExistingCreature, _topLevels.TryGetValue(cr.Species, out var tl) ? tl : null, - _lowestLevels.TryGetValue(cr.Species, out var ll) ? ll : null, + input.GenerateCreatureName(cr, alreadyExistingCreature, _highestSpeciesLevels.TryGetValue(cr.Species, out var tl) ? tl : null, + _lowestSpeciesLevels.TryGetValue(cr.Species, out var ll) ? ll : null, _customReplacingNamingPattern, showDuplicateNameWarning, namingPatternIndex); if (Properties.Settings.Default.PatternNameToClipboardAfterManualApplication) { @@ -3097,8 +3102,9 @@ private Creature CreateCreatureFromExtractorOrTester(CreatureInfoInput input) cr.imprintingBonus = _extractor.ImprintingBonus; cr.tamingEff = _extractor.UniqueTamingEffectiveness(); cr.isBred = rbBredExtractor.Checked; - cr.topBreedingStats = _statIOs.Select(s => - s.TopLevel.HasFlag(LevelStatus.TopLevel) || s.TopLevel.HasFlag(LevelStatus.NewTopLevel)).ToArray(); + for (int s = 0; s < Stats.StatsCount; s++) + cr.SetTopStat(s, _statIOs[s].TopLevel.HasFlag(LevelStatusFlags.LevelStatus.TopLevel) || _statIOs[s].TopLevel.HasFlag(LevelStatusFlags.LevelStatus.NewTopLevel)); + } else { @@ -3516,14 +3522,15 @@ private void GenerateCreatureNames() foreach (int i in listViewLibrary.SelectedIndices) { var cr = _creaturesDisplayed[i]; + if (cr.Species == null) continue; if (sameSpecies?.FirstOrDefault()?.Species != cr.Species) sameSpecies = _creatureCollection.creatures.Where(c => c.Species == cr.Species).ToArray(); // set new name cr.name = NamePattern.GenerateCreatureName(cr, cr, sameSpecies, - _topLevels.ContainsKey(cr.Species) ? _topLevels[cr.Species] : null, - _lowestLevels.ContainsKey(cr.Species) ? _lowestLevels[cr.Species] : null, + _highestSpeciesLevels.TryGetValue(cr.Species, out var highestSpeciesLevels) ? highestSpeciesLevels : null, + _lowestSpeciesLevels.TryGetValue(cr.Species, out var lowestSpeciesLevels) ? lowestSpeciesLevels : null, _customReplacingNamingPattern, false, 0, libraryCreatureCount: libraryCreatureCount); creaturesToUpdate.Add(cr); @@ -3878,25 +3885,41 @@ private void listenWithNewTokenToolStripMenuItem_Click(object sender, EventArgs private void AsbServerStartListening() { - AsbServer.Connection.StopListening(); - var progressDataSent = new Progress<(string jsonText, string serverHash, string message)>(AsbServerDataSent); + var progressReporter = new Progress(AsbServerDataSent); if (string.IsNullOrEmpty(Properties.Settings.Default.ExportServerToken)) Properties.Settings.Default.ExportServerToken = AsbServer.Connection.CreateNewToken(); - Task.Factory.StartNew(() => AsbServer.Connection.StartListeningAsync(progressDataSent, Properties.Settings.Default.ExportServerToken)); - MessageServerListening(Properties.Settings.Default.ExportServerToken); + Task.Factory.StartNew(() => AsbServer.Connection.StartListeningAsync(progressReporter, Properties.Settings.Default.ExportServerToken)); } - private void AsbServerStopListening() + private void AsbServerStopListening(bool displayMessage = true) { AsbServer.Connection.StopListening(); - SetMessageLabelText($"ASB Server listening stopped using token: {Properties.Settings.Default.ExportServerToken}", MessageBoxIcon.Error); + if (displayMessage) + SetMessageLabelText($"ASB Server listening stopped using token: {Connection.TokenStringForDisplay(Properties.Settings.Default.ExportServerToken)}", MessageBoxIcon.Error); } - private void MessageServerListening(string token) + private void currentTokenToolStripMenuItem_Click(object sender, EventArgs e) { - SetMessageLabelText($"Now listening to the export server using the token (also copied to clipboard){Environment.NewLine}{token}", MessageBoxIcon.Information, clipboardText: token); - if (!string.IsNullOrEmpty(token)) - Clipboard.SetText(token); + var tokenIsSet = !string.IsNullOrEmpty(Properties.Settings.Default.ExportServerToken); + string message; + bool isError; + if (tokenIsSet) + { + message = $"Currently {(Connection.IsCurrentlyListening ? string.Empty : "not ")}listening to the server." + + " The current token is " + Environment.NewLine + Connection.TokenStringForDisplay(Properties.Settings.Default.ExportServerToken) + + Environment.NewLine + "(token copied to clipboard)"; + + Clipboard.SetText(Properties.Settings.Default.ExportServerToken); + isError = false; + } + else + { + message = "Currently no token set. A token is created once you start listening to the server."; + isError = true; + } + + SetMessageLabelText(message, isError ? MessageBoxIcon.Error : MessageBoxIcon.Information, + clipboardText: Properties.Settings.Default.ExportServerToken, displayPopup: !Properties.Settings.Default.StreamerMode); } private void sendExampleCreatureToolStripMenuItem_Click(object sender, EventArgs e) @@ -3906,6 +3929,5 @@ private void sendExampleCreatureToolStripMenuItem_Click(object sender, EventArgs } #endregion - } } diff --git a/ARKBreedingStats/Form1.extractor.cs b/ARKBreedingStats/Form1.extractor.cs index 31a174581..e489d1331 100644 --- a/ARKBreedingStats/Form1.extractor.cs +++ b/ARKBreedingStats/Form1.extractor.cs @@ -9,8 +9,10 @@ using System.Linq; using System.Threading; using System.Windows.Forms; +using ARKBreedingStats.library; using ARKBreedingStats.utils; using ARKBreedingStats.ocr; +using ARKBreedingStats.uiControls; namespace ARKBreedingStats { @@ -65,7 +67,7 @@ private void ShowSumOfChosenLevels() valid = false; break; } - _statIOs[s].TopLevel = LevelStatus.Neutral; + _statIOs[s].TopLevel = LevelStatusFlags.LevelStatus.Neutral; } if (valid) { @@ -116,80 +118,33 @@ private void ShowSumOfChosenLevels() radarChartExtractor.SetLevels(_statIOs.Select(s => s.LevelWild).ToArray(), _statIOs.Select(s => s.LevelMut).ToArray(), speciesSelector1.SelectedSpecies); cbExactlyImprinting.BackColor = Color.Transparent; var species = speciesSelector1.SelectedSpecies; - var checkTopLevels = _topLevels.TryGetValue(species, out int[] topSpeciesLevels); - var checkLowLevels = _lowestLevels.TryGetValue(species, out int[] lowSpeciesLevels); + _highestSpeciesLevels.TryGetValue(species, out int[] highSpeciesLevels); + _lowestSpeciesLevels.TryGetValue(species, out int[] lowSpeciesLevels); + _highestSpeciesMutationLevels.TryGetValue(species, out int[] highSpeciesMutationLevels); + //_lowestSpeciesMutationLevels.TryGetValue(species, out int[] lowSpeciesMutationLevels); - var customStatNames = species.statNames; var statWeights = breedingPlan1.StatWeighting.GetWeightingForSpecies(species); - if (statWeights.Item1 == null) checkLowLevels = false; - var analysisState = LevelStatus.Neutral; - var newTopStatsText = new List(); - var topStatsText = new List(); - for (int s = 0; s < Stats.StatsCount; s++) - { - if (s == Stats.Torpidity - || _statIOs[s].LevelWild <= 0) - continue; - - var levelStatus = LevelStatus.Neutral; - - if (checkTopLevels && (statWeights.Item1?[s] ?? 0) >= 0) - { - // higher stats are considered to be good. If no custom weightings are available, consider higher levels to be better. + LevelStatusFlags.DetermineLevelStatus(species, highSpeciesLevels, lowSpeciesLevels, highSpeciesMutationLevels, + statWeights, GetCurrentWildLevels(), GetCurrentMutLevels(),GetCurrentBreedingValues(), + out var topStatsText, out var newTopStatsText); - // check if higher level is only considered if even or odd - if ((statWeights.Item2?[s] ?? 0) == 0 // even/odd doesn't matter - || (statWeights.Item2[s] == 1 && _statIOs[s].LevelWild % 2 == 1) - || (statWeights.Item2[s] == 2 && _statIOs[s].LevelWild % 2 == 0) - ) - { - if (_statIOs[s].LevelWild == topSpeciesLevels[s]) - { - levelStatus = LevelStatus.TopLevel; - topStatsText.Add(Utils.StatName(s, false, customStatNames)); - if (analysisState != LevelStatus.NewTopLevel) - analysisState = LevelStatus.TopLevel; - } - else if (topSpeciesLevels[s] != -1 && _statIOs[s].LevelWild > topSpeciesLevels[s]) - { - levelStatus = LevelStatus.NewTopLevel; - newTopStatsText.Add(Utils.StatName(s, false, customStatNames)); - analysisState = LevelStatus.NewTopLevel; - } - } - } - else if (checkLowLevels && statWeights.Item1[s] < 0) - { - // lower stats are considered to be good - if (_statIOs[s].LevelWild == lowSpeciesLevels[s]) - { - levelStatus = LevelStatus.TopLevel; - topStatsText.Add(Utils.StatName(s, false, customStatNames)); - if (analysisState != LevelStatus.NewTopLevel) - analysisState = LevelStatus.TopLevel; - } - else if (_statIOs[s].LevelWild < lowSpeciesLevels[s]) - { - levelStatus = LevelStatus.NewTopLevel; - newTopStatsText.Add(Utils.StatName(s, false, customStatNames)); - analysisState = LevelStatus.NewTopLevel; - } - } + for (var s = 0; s < Stats.StatsCount; s++) + { + var levelStatusForStatIo = LevelStatusFlags.LevelStatusFlagsCurrentNewCreature[s]; // ASA can have up to 511 levels because 255 mutation levels also contribute to the wild value. TODO separate to mutation levels - if (_creatureCollection.Game != Ark.Asa) + if (_creatureCollection.Game != Ark.Asa && s != Stats.Torpidity) { if (_statIOs[s].LevelWild > 255) - levelStatus |= LevelStatus.UltraMaxLevel; + levelStatusForStatIo |= LevelStatusFlags.LevelStatus.UltraMaxLevel; else if (_statIOs[s].LevelWild == 255) - levelStatus |= LevelStatus.MaxLevel; + levelStatusForStatIo |= LevelStatusFlags.LevelStatus.MaxLevel; else if (_statIOs[s].LevelWild == 254) - levelStatus |= LevelStatus.MaxLevelForLevelUp; + levelStatusForStatIo |= LevelStatusFlags.LevelStatus.MaxLevelForLevelUp; } - if (levelStatus != LevelStatus.Neutral) - _statIOs[s].TopLevel = levelStatus; + _statIOs[s].TopLevel = levelStatusForStatIo; } string infoText = null; @@ -204,7 +159,7 @@ private void ShowSumOfChosenLevels() if (infoText == null) infoText = "No top stats"; - creatureAnalysis1.SetStatsAnalysis(analysisState, infoText); + creatureAnalysis1.SetStatsAnalysis(LevelStatusFlags.CombinedLevelStatusFlags, infoText); } creatureInfoInputExtractor.ButtonEnabled = allValid; groupBoxRadarChartExtractor.Visible = allValid; @@ -414,7 +369,7 @@ private bool ExtractLevels(bool autoExtraction = false, bool statInputsHighPreci int domLevelsChosenSum = 0; for (int s = 0; s < Stats.StatsCount; s++) { - if (s != Stats.Torpidity) + if (s != Stats.Torpidity && _extractor.Results[s].Any()) domLevelsChosenSum += _extractor.Results[s][_extractor.ChosenResults[s]].levelDom; } if (domLevelsChosenSum != _extractor.LevelDomSum) @@ -762,17 +717,18 @@ private void SetLevelCombination(int s, int i, bool validateCombination = false) /// private void SetWildUnknownLevelsAccordingToOthers() { + var species = speciesSelector1.SelectedSpecies; // wild speed level is wildTotalLevels - determinedWildLevels. sometimes the oxygen level cannot be determined as well var unknownLevelIndices = new List(); int notDeterminedLevels = _statIOs[Stats.Torpidity].LevelWild; for (int s = 0; s < Stats.StatsCount; s++) { - if (s == Stats.Torpidity || !speciesSelector1.SelectedSpecies.UsesStat(s)) + if (s == Stats.Torpidity || !species.UsesStat(s)) { continue; } - if (_statIOs[s].LevelWild < 0) + if (_statIOs[s].LevelWild < 0 || species.stats[s].IncPerWildLevel == 0) { unknownLevelIndices.Add(s); continue; @@ -1219,7 +1175,7 @@ private void CreatureInfoInputColorsChanged(CreatureInfoInput input) input.ColorAlreadyExistingInformation = colorAlreadyExisting; if (input == creatureInfoInputExtractor) - creatureAnalysis1.SetColorAnalysis(newColorStatus.newInSpecies ? LevelStatus.NewTopLevel : newColorStatus.newInRegion ? LevelStatus.TopLevel : LevelStatus.Neutral, infoText); + creatureAnalysis1.SetColorAnalysis(newColorStatus.newInSpecies ? LevelStatusFlags.LevelStatus.NewTopLevel : newColorStatus.newInRegion ? LevelStatusFlags.LevelStatus.TopLevel : LevelStatusFlags.LevelStatus.Neutral, infoText); } private void copyLibrarydumpToClipboardToolStripMenuItem_Click(object sender, EventArgs e) diff --git a/ARKBreedingStats/Form1.importExported.cs b/ARKBreedingStats/Form1.importExported.cs index 2ae5f5dda..6539b4853 100644 --- a/ARKBreedingStats/Form1.importExported.cs +++ b/ARKBreedingStats/Form1.importExported.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Text; using System.Windows.Forms; +using ARKBreedingStats.library; using ARKBreedingStats.NamePatterns; using ARKBreedingStats.species; using ARKBreedingStats.utils; @@ -232,7 +233,8 @@ private Creature ImportExportedAddIfPossible(string filePath) creature = GetCreatureFromInput(true, species, levelStep); } - OverlayFeedbackForImport(creature, uniqueExtraction, alreadyExists, addedToLibrary, copiedNameToClipboard, out bool hasTopLevels, out bool hasNewTopLevels); + OverlayFeedbackForImport(creature, uniqueExtraction, alreadyExists, addedToLibrary, copiedNameToClipboard, + out bool hasTopLevels, out bool hasNewTopLevels, out var newMutationStatFlags); if (addedToLibrary) { @@ -296,7 +298,9 @@ private Creature ImportExportedAddIfPossible(string filePath) if (uniqueExtraction) { if (alreadyExists) - SoundFeedback.BeepSignal(SoundFeedback.FeedbackSounds.Indifferent); + SoundFeedback.BeepSignal(SoundFeedback.FeedbackSounds.Updated); + else if (newMutationStatFlags != 0) + SoundFeedback.BeepSignal(SoundFeedback.FeedbackSounds.NewMutation); else if (hasNewTopLevels) SoundFeedback.BeepSignal(SoundFeedback.FeedbackSounds.Great); else if (hasTopLevels) @@ -339,8 +343,8 @@ private bool SetNameOfImportedCreature(Creature creature, Creature[] creaturesOf creaturesOfSpecies = _creatureCollection.creatures.Where(c => c.Species == creature.Species) .ToArray(); creature.name = NamePattern.GenerateCreatureName(creature, alreadyExistingCreature, creaturesOfSpecies, - _topLevels.TryGetValue(creature.Species, out var topLevels) ? topLevels : null, - _lowestLevels.TryGetValue(creature.Species, out var lowestLevels) ? lowestLevels : null, + _highestSpeciesLevels.TryGetValue(creature.Species, out var topLevels) ? topLevels : null, + _lowestSpeciesLevels.TryGetValue(creature.Species, out var lowestLevels) ? lowestLevels : null, _customReplacingNamingPattern, false, 0, libraryCreatureCount: totalCreatureCount); if (alreadyExistingCreature != null) alreadyExistingCreature.name = creature.name; // if alreadyExistingCreature was already updated and creature is not used anymore make sure name is not lost @@ -377,10 +381,12 @@ private bool CopyCreatureNameToClipboardOnImportIfSetting(string creatureName) /// /// Give feedback in overlay for imported creature. /// - private void OverlayFeedbackForImport(Creature creature, bool uniqueExtraction, bool alreadyExists, bool addedToLibrary, bool copiedNameToClipboard, out bool topLevels, out bool newTopLevels) + private void OverlayFeedbackForImport(Creature creature, bool uniqueExtraction, bool alreadyExists, bool addedToLibrary, + bool copiedNameToClipboard, out bool topLevels, out bool newTopLevels, out int newMutationStatFlags) { topLevels = false; newTopLevels = false; + newMutationStatFlags = 0; string infoText; Color textColor; const int colorSaturation = 200; @@ -391,24 +397,27 @@ private void OverlayFeedbackForImport(Creature creature, bool uniqueExtraction, if (addedToLibrary && copiedNameToClipboard) sb.AppendLine("Name copied to clipboard."); - for (int s = 0; s < Stats.StatsCount; s++) - { - int statIndex = Stats.DisplayOrder[s]; - if (!creature.Species.UsesStat(statIndex)) continue; - - sb.Append($"{Utils.StatName(statIndex, true, creature.Species.statNames)}: {creature.levelsWild[statIndex]} ({creature.valuesBreeding[statIndex]})"); - if (_statIOs[statIndex].TopLevel.HasFlag(LevelStatus.NewTopLevel)) - { - sb.Append($" {Loc.S("newTopLevel")}"); - newTopLevels = true; - } - else if (creature.topBreedingStats[statIndex]) - { - sb.Append($" {Loc.S("topLevel")}"); - topLevels = true; - } - sb.AppendLine(); - } + var checkMutations = _highestSpeciesMutationLevels.TryGetValue(creature.Species, out var highestMutations) && creature.levelsMutated != null; + var species = speciesSelector1.SelectedSpecies; + _highestSpeciesLevels.TryGetValue(species, out int[] highSpeciesLevels); + _lowestSpeciesLevels.TryGetValue(species, out int[] lowSpeciesLevels); + _highestSpeciesMutationLevels.TryGetValue(species, out int[] highSpeciesMutationLevels); + + var statWeights = breedingPlan1.StatWeighting.GetWeightingForSpecies(species); + + LevelStatusFlags.DetermineLevelStatus(species, highSpeciesLevels, lowSpeciesLevels, highSpeciesMutationLevels, + statWeights, creature.levelsWild, creature.levelsMutated, creature.valuesBreeding, + out _, out _, sb); + + topLevels = LevelStatusFlags.CombinedLevelStatusFlags.HasFlag(LevelStatusFlags.LevelStatus.TopLevel); + newTopLevels = LevelStatusFlags.CombinedLevelStatusFlags.HasFlag(LevelStatusFlags.LevelStatus.NewTopLevel); + newMutationStatFlags = Enumerable.Range(0, Stats.StatsCount) + .Aggregate(0, + (flags, statIndex) => + flags | (LevelStatusFlags.LevelStatusFlagsCurrentNewCreature[statIndex] + .HasFlag(LevelStatusFlags.LevelStatus.NewMutation) + ? (1 << statIndex) + : 0)); infoText = sb.ToString(); textColor = Color.FromArgb(colorSaturation, 255, colorSaturation); @@ -417,6 +426,7 @@ private void OverlayFeedbackForImport(Creature creature, bool uniqueExtraction, { infoText = $"Creature \"{creature.name}\" couldn't be extracted uniquely, manual level selection is necessary."; textColor = Color.FromArgb(255, colorSaturation, colorSaturation); + LevelStatusFlags.Clear(); } if (_overlay != null) diff --git a/ARKBreedingStats/Form1.library.cs b/ARKBreedingStats/Form1.library.cs index 209d1ffd3..c83e5a80a 100644 --- a/ARKBreedingStats/Form1.library.cs +++ b/ARKBreedingStats/Form1.library.cs @@ -196,40 +196,25 @@ private bool IsArkIdUniqueOrOnlyPlaceHolder(Creature creature) /// Returns the wild levels from the extractor or tester in an array. /// private int[] GetCurrentWildLevels(bool fromExtractor = true) - { - int[] levelsWild = new int[Stats.StatsCount]; - for (int s = 0; s < Stats.StatsCount; s++) - { - levelsWild[s] = fromExtractor ? _statIOs[s].LevelWild : _testingIOs[s].LevelWild; - } - return levelsWild; - } + => (fromExtractor ? _statIOs : _testingIOs).Select(i => i.LevelWild).ToArray(); /// /// Returns the mutated levels from the extractor or tester in an array. /// private int[] GetCurrentMutLevels(bool fromExtractor = true) - { - int[] levelsMut = new int[Stats.StatsCount]; - for (int s = 0; s < Stats.StatsCount; s++) - { - levelsMut[s] = fromExtractor ? _statIOs[s].LevelMut : _testingIOs[s].LevelMut; - } - return levelsMut; - } + => (fromExtractor ? _statIOs : _testingIOs).Select(i => i.LevelMut).ToArray(); /// /// Returns the domesticated levels from the extractor or tester in an array. /// private int[] GetCurrentDomLevels(bool fromExtractor = true) - { - int[] levelsDom = new int[Stats.StatsCount]; - for (int s = 0; s < Stats.StatsCount; s++) - { - levelsDom[s] = fromExtractor ? _statIOs[s].LevelDom : _testingIOs[s].LevelDom; - } - return levelsDom; - } + => (fromExtractor ? _statIOs : _testingIOs).Select(i => i.LevelDom).ToArray(); + + /// + /// Returns the breeding values from the extractor or tester in an array. + /// + private double[] GetCurrentBreedingValues(bool fromExtractor = true) + => (fromExtractor ? _statIOs : _testingIOs).Select(i => i.BreedingValue).ToArray(); /// /// Call after the creatureCollection-object was created anew (e.g. after loading a file) @@ -295,6 +280,11 @@ private static void ApplySpeciesObjectsToCollection(CreatureCollection cc) /// creatures to consider private void CalculateTopStats(List creatures) { + _highestSpeciesLevels.Clear(); + _lowestSpeciesLevels.Clear(); + _highestSpeciesMutationLevels.Clear(); + _lowestSpeciesMutationLevels.Clear(); + var filteredCreaturesHash = Properties.Settings.Default.useFiltersInTopStatCalculation ? new HashSet(ApplyLibraryFilterSettings(creatures)) : null; var speciesCreaturesGroups = creatures.GroupBy(c => c.Species); @@ -308,13 +298,15 @@ private void CalculateTopStats(List creatures) List usedStatIndices = new List(Stats.StatsCount); List usedAndConsideredStatIndices = new List(Stats.StatsCount); - int[] bestStat = new int[Stats.StatsCount]; - int[] lowestStat = new int[Stats.StatsCount]; + var highestLevels = new int[Stats.StatsCount]; + var lowestLevels = new int[Stats.StatsCount]; + var highestMutationLevels = new int[Stats.StatsCount]; + var lowestMutationLevels = new int[Stats.StatsCount]; var statWeights = breedingPlan1.StatWeighting.GetWeightingForSpecies(species); for (int s = 0; s < Stats.StatsCount; s++) { - bestStat[s] = -1; - lowestStat[s] = -1; + highestLevels[s] = -1; + lowestLevels[s] = -1; if (species.UsesStat(s)) { usedStatIndices.Add(s); @@ -322,17 +314,24 @@ private void CalculateTopStats(List creatures) usedAndConsideredStatIndices.Add(s); } } - List[] bestCreatures = new List[Stats.StatsCount]; - int usedStatsCount = usedStatIndices.Count; - int usedAndConsideredStatsCount = usedAndConsideredStatIndices.Count; + List[] bestCreaturesWildLevels = new List[Stats.StatsCount]; + List[] bestCreaturesMutatedLevels = new List[Stats.StatsCount]; + var statPreferences = new StatWeighting.StatValuePreference[Stats.StatsCount]; + for (int s = 0; s < Stats.StatsCount; s++) + { + var statWeight = statWeights.Item1[s]; + statPreferences[s] = statWeight > 0 ? StatWeighting.StatValuePreference.High : + statWeight < 0 ? StatWeighting.StatValuePreference.Low : + StatWeighting.StatValuePreference.Indifferent; + } foreach (var c in speciesCreatures) { if (c.flags.HasFlag(CreatureFlags.Placeholder)) continue; - // reset topBreeding stats for this creature - c.topBreedingStats = new bool[Stats.StatsCount]; + c.ResetTopStats(); + c.ResetTopMutationStats(); c.topBreedingCreature = false; if ( @@ -348,47 +347,110 @@ private void CalculateTopStats(List creatures) continue; } - for (int s = 0; s < usedStatsCount; s++) + foreach (var s in usedStatIndices) { - int si = usedStatIndices[s]; - if (c.levelsWild[si] != -1 && (lowestStat[si] == -1 || c.levelsWild[si] < lowestStat[si])) + if (c.levelsWild[s] >= 0) { - lowestStat[si] = c.levelsWild[si]; - } - - if (c.levelsWild[si] <= 0) continue; + if (statPreferences[s] == StatWeighting.StatValuePreference.Low) + { + if (lowestLevels[s] == -1 || c.levelsWild[s] < lowestLevels[s]) + { + bestCreaturesWildLevels[s] = new List { c }; + lowestLevels[s] = c.levelsWild[s]; + } + else if (c.levelsWild[s] == lowestLevels[s]) + { + bestCreaturesWildLevels[s].Add(c); + } - if (c.levelsWild[si] == bestStat[si]) - { - bestCreatures[si].Add(c); + if (c.levelsWild[s] > highestLevels[s]) + { + highestLevels[s] = c.levelsWild[s]; + } + } + else if (statPreferences[s] == StatWeighting.StatValuePreference.High) + { + if (c.levelsWild[s] > highestLevels[s]) + { + // creature has a higher level than the current highest level + // check if highest stats are only counted if odd or even + if ((statWeights.Item2?[s] ?? 0) == 0 // even/odd doesn't matter + || (statWeights.Item2[s] == 1 && c.levelsWild[s] % 2 == 1) + || (statWeights.Item2[s] == 2 && c.levelsWild[s] % 2 == 0) + ) + { + bestCreaturesWildLevels[s] = new List { c }; + highestLevels[s] = c.levelsWild[s]; + } + } + else if (c.levelsWild[s] == highestLevels[s]) + { + bestCreaturesWildLevels[s].Add(c); + } + if (lowestLevels[s] == -1 || c.levelsWild[s] < lowestLevels[s]) + { + lowestLevels[s] = c.levelsWild[s]; + } + } } - else if (c.levelsWild[si] > bestStat[si]) + + if (c.levelsMutated != null && c.levelsMutated[s] >= 0) { - // check if highest stats are only counted if odd or even - if ((statWeights.Item2?[s] ?? 0) == 0 // even/odd doesn't matter - || (statWeights.Item2[s] == 1 && c.levelsWild[si] % 2 == 1) - || (statWeights.Item2[s] == 2 && c.levelsWild[si] % 2 == 0) - ) + if (statPreferences[s] == StatWeighting.StatValuePreference.Low) { - bestCreatures[si] = new List { c }; - bestStat[si] = c.levelsWild[si]; + if (c.levelsMutated[s] < lowestMutationLevels[s]) + { + bestCreaturesMutatedLevels[s] = new List { c }; + lowestMutationLevels[s] = c.levelsMutated[s]; + } + else if (c.levelsMutated[s] == lowestMutationLevels[s]) + { + if (bestCreaturesMutatedLevels[s] == null) + bestCreaturesMutatedLevels[s] = new List { c }; + else bestCreaturesMutatedLevels[s].Add(c); + } + } + else if (statPreferences[s] == StatWeighting.StatValuePreference.High + && c.levelsMutated[s] > 0) + { + if (c.levelsMutated[s] > 0 && c.levelsMutated[s] > highestMutationLevels[s]) + { + bestCreaturesMutatedLevels[s] = new List { c }; + highestMutationLevels[s] = c.levelsMutated[s]; + } + else if (c.levelsMutated[s] == highestMutationLevels[s]) + { + bestCreaturesMutatedLevels[s].Add(c); + } } } } } - _topLevels[species] = bestStat; - _lowestLevels[species] = lowestStat; + _highestSpeciesLevels[species] = highestLevels; + _lowestSpeciesLevels[species] = lowestLevels; + _highestSpeciesMutationLevels[species] = highestMutationLevels; + _lowestSpeciesMutationLevels[species] = lowestMutationLevels; // bestStat and bestCreatures now contain the best stats and creatures for each stat. // set topness of each creature (== mean wildLevels/mean top wildLevels in permille) int sumTopLevels = 0; - for (int s = 0; s < usedAndConsideredStatsCount; s++) + foreach (var s in usedAndConsideredStatIndices) { - int si = usedAndConsideredStatIndices[s]; - if (bestStat[si] > 0) - sumTopLevels += bestStat[si]; + switch (statPreferences[s]) + { + case StatWeighting.StatValuePreference.Indifferent: + continue; + case StatWeighting.StatValuePreference.Low: + if (highestLevels[s] > 0 && lowestLevels[s] != 0) + sumTopLevels += highestLevels[s] - lowestLevels[s]; + break; + case StatWeighting.StatValuePreference.High: + if (highestLevels[s] > 0) + sumTopLevels += highestLevels[s]; + break; + } } if (sumTopLevels > 0) { @@ -396,10 +458,18 @@ private void CalculateTopStats(List creatures) { if (c.levelsWild == null || c.flags.HasFlag(CreatureFlags.Placeholder)) continue; int sumCreatureLevels = 0; - for (int s = 0; s < usedAndConsideredStatsCount; s++) + foreach (var s in usedAndConsideredStatIndices) { - int si = usedAndConsideredStatIndices[s]; - sumCreatureLevels += c.levelsWild[si] > 0 ? c.levelsWild[si] : 0; + switch (statPreferences[s]) + { + case StatWeighting.StatValuePreference.Low: + if (c.levelsWild[s] >= 0) + sumCreatureLevels += highestLevels[s] - c.levelsWild[s]; + break; + case StatWeighting.StatValuePreference.High: + sumCreatureLevels += c.levelsWild[s] > 0 ? c.levelsWild[s] : 0; + break; + } } c.topness = (short)(1000 * sumCreatureLevels / sumTopLevels); } @@ -408,54 +478,59 @@ private void CalculateTopStats(List creatures) // if any male is in more than 1 category, remove any male from the topBreedingCreatures that is not top in at least 2 categories himself for (int s = 0; s < Stats.StatsCount; s++) { - if (bestCreatures[s] == null || bestCreatures[s].Count == 0) + if (bestCreaturesMutatedLevels[s] != null) { - continue; // no creature has levelups in this stat or the stat is not used for this species + foreach (var c in bestCreaturesMutatedLevels[s]) + c.topBreedingCreature = true; } - var crCount = bestCreatures[s].Count; + if (bestCreaturesWildLevels[s] == null || bestCreaturesWildLevels[s].Count == 0) + continue; // no creature has levelups in this stat or the stat is not used for this species + + var crCount = bestCreaturesWildLevels[s].Count; if (crCount == 1) { - bestCreatures[s][0].topBreedingCreature = true; + bestCreaturesWildLevels[s][0].topBreedingCreature = true; continue; } - for (int c = 0; c < crCount; c++) + foreach (var currentCreature in bestCreaturesWildLevels[s]) { - bestCreatures[s][c].topBreedingCreature = true; - if (bestCreatures[s][c].sex != Sex.Male) + currentCreature.topBreedingCreature = true; + if (currentCreature.sex != Sex.Male) continue; - Creature currentCreature = bestCreatures[s][c]; // check how many best stat the male has int maxval = 0; for (int cs = 0; cs < Stats.StatsCount; cs++) { - if (currentCreature.levelsWild[cs] == bestStat[cs]) + if (currentCreature.levelsWild[cs] == highestLevels[cs]) maxval++; } if (maxval > 1) { // check now if the other males have only 1. - for (int oc = 0; oc < crCount; oc++) + foreach (var otherMale in bestCreaturesWildLevels[s]) { - if (bestCreatures[s][oc].sex != Sex.Male) - continue; - - if (oc == c) + if (otherMale.sex != Sex.Male + || currentCreature.Equals(otherMale)) continue; - Creature otherMale = bestCreatures[s][oc]; - int othermaxval = 0; for (int ocs = 0; ocs < Stats.StatsCount; ocs++) { - if (otherMale.levelsWild[ocs] == bestStat[ocs]) + if (otherMale.levelsWild[ocs] == highestLevels[ocs]) othermaxval++; + if (otherMale.IsTopMutationStat(ocs)) + { + // if this creature has top mutation levels, don't remove it from breeding pool + othermaxval = 99; + break; + } } if (othermaxval == 1) - bestCreatures[s][oc].topBreedingCreature = false; + otherMale.topBreedingCreature = false; } } } @@ -464,13 +539,16 @@ private void CalculateTopStats(List creatures) // now we have a list of all candidates for breeding. Iterate on stats. for (int s = 0; s < Stats.StatsCount; s++) { - if (bestCreatures[s] != null) + if (bestCreaturesWildLevels[s] != null) { - for (int c = 0; c < bestCreatures[s].Count; c++) - { - // flag topStats in creatures - bestCreatures[s][c].topBreedingStats[s] = true; - } + foreach (var c in bestCreaturesWildLevels[s]) + c.SetTopStat(s, true); + } + + if (bestCreaturesMutatedLevels[s] != null) + { + foreach (var c in bestCreaturesMutatedLevels[s]) + c.SetTopMutationStat(s, true); } } } @@ -481,7 +559,7 @@ private void CalculateTopStats(List creatures) var selectedSpecies = speciesSelector1.SelectedSpecies; if (selectedSpecies != null) - hatching1.SetSpecies(selectedSpecies, _topLevels.TryGetValue(selectedSpecies, out var tl) ? tl : null, _lowestLevels.TryGetValue(selectedSpecies, out var ll) ? ll : null); + hatching1.SetSpecies(selectedSpecies, _highestSpeciesLevels.TryGetValue(selectedSpecies, out var tl) ? tl : null, _lowestSpeciesLevels.TryGetValue(selectedSpecies, out var ll) ? ll : null); } /// @@ -757,7 +835,8 @@ private Creature[] InsertDividers(IList creatures) private void ListViewLibrary_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e) { // check to see if the requested item is currently in the cache - if (_libraryListViewItemCache != null && e.ItemIndex >= _libraryItemCacheFirstIndex && e.ItemIndex < _libraryItemCacheFirstIndex + _libraryListViewItemCache.Length) + if (_libraryListViewItemCache != null && e.ItemIndex >= _libraryItemCacheFirstIndex && + e.ItemIndex < _libraryItemCacheFirstIndex + _libraryListViewItemCache.Length) { // get the ListViewItem from the cache instead of making a new one. e.Item = _libraryListViewItemCache[e.ItemIndex - _libraryItemCacheFirstIndex]; @@ -765,7 +844,14 @@ private void ListViewLibrary_RetrieveVirtualItem(object sender, RetrieveVirtualI else if (_creaturesDisplayed?.Length > e.ItemIndex) { // create item not available in the cache - e.Item = CreateCreatureLvItem(_creaturesDisplayed[e.ItemIndex], Properties.Settings.Default.DisplayLibraryCreatureIndex); + e.Item = CreateCreatureLvItem(_creaturesDisplayed[e.ItemIndex], + Properties.Settings.Default.DisplayLibraryCreatureIndex); + } + else + { + throw new Exception($"ListViewItem could not be retrieved. ItemIndex: {e.ItemIndex}." + + $"_creaturesDisplayedLength: {_creaturesDisplayed?.Length}." + + $"_libraryListViewItemCacheLength: {_libraryListViewItemCache?.Length}"); } } @@ -988,7 +1074,7 @@ private ListViewItem CreateCreatureLvItem(Creature cr, bool displayIndex = false Utils.SexSymbol(cr.sex), cr.domesticatedAt?.ToString("yyyy'-'MM'-'dd HH':'mm':'ss") ?? string.Empty, (cr.topness / 10).ToString(), - cr.topStatsCount.ToString(), + cr.topStatsConsideredCount.ToString(), cr.generation.ToString(), cr.levelFound.ToString(), cr.Mutations.ToString(), @@ -1013,6 +1099,7 @@ private ListViewItem CreateCreatureLvItem(Creature cr, bool displayIndex = false ListViewItem lvi = new ListViewItem(subItems) { Tag = cr }; // apply colors to the subItems + var displayZeroMutationLevels = Properties.Settings.Default.LibraryDisplayZeroMutationLevels; for (int s = 0; s < Stats.StatsCount; s++) { @@ -1030,17 +1117,17 @@ private ListViewItem CreateCreatureLvItem(Creature cr, bool displayIndex = false } else lvi.SubItems[ColumnIndexFirstStat + s].BackColor = Utils.GetColorFromPercent((int)(cr.levelsWild[s] * (s == Stats.Torpidity ? colorFactor / 7 : colorFactor)), // TODO set factor to number of other stats (flyers have 6, Gacha has 8?) - _considerStatHighlight[s] ? cr.topBreedingStats[s] ? 0.2 : 0.7 : 0.93); + _considerStatHighlight[s] ? cr.IsTopStat(s) ? 0.2 : 0.75 : 0.93); // mutated levels - if (cr.levelsMutated == null || cr.levelsMutated[s] == 0) + if (cr.levelsMutated == null || (!displayZeroMutationLevels && cr.levelsMutated[s] == 0)) { lvi.SubItems[ColumnIndexFirstStat + Stats.StatsCount + s].ForeColor = Color.White; lvi.SubItems[ColumnIndexFirstStat + Stats.StatsCount + s].BackColor = Color.White; } else - lvi.SubItems[ColumnIndexFirstStat + Stats.StatsCount + s].BackColor = Utils.GetColorFromPercent((int)(cr.levelsMutated[s] * (s == Stats.Torpidity ? colorFactor / 7 : colorFactor)), - _considerStatHighlight[s] ? 0.7 : 0.93, true); + lvi.SubItems[ColumnIndexFirstStat + Stats.StatsCount + s].BackColor = Utils.GetColorFromPercent((int)(cr.levelsMutated[s] * colorFactor), + _considerStatHighlight[s] ? cr.IsTopMutationStat(s) ? 0.5 : 0.8 : 0.93, true); } lvi.SubItems[ColumnIndexSex].BackColor = cr.flags.HasFlag(CreatureFlags.Neutered) ? Color.FromArgb(220, 220, 220) : cr.sex == Sex.Female ? Color.FromArgb(255, 230, 255) : @@ -1072,7 +1159,7 @@ private ListViewItem CreateCreatureLvItem(Creature cr, bool displayIndex = false lvi.UseItemStyleForSubItems = false; // color for top-stats-nr - if (cr.topStatsCount > 0) + if (cr.topStatsConsideredCount > 0) { if (Properties.Settings.Default.LibraryHighlightTopCreatures && cr.topBreedingCreature) { @@ -1081,7 +1168,7 @@ private ListViewItem CreateCreatureLvItem(Creature cr, bool displayIndex = false else lvi.BackColor = Color.LightGreen; } - lvi.SubItems[ColumnIndexTopStats].BackColor = Utils.GetColorFromPercent(cr.topStatsCount * 8 + 44, 0.7); + lvi.SubItems[ColumnIndexTopStats].BackColor = Utils.GetColorFromPercent(cr.topStatsConsideredCount * 8 + 44, 0.7); } else { @@ -1106,7 +1193,7 @@ private ListViewItem CreateCreatureLvItem(Creature cr, bool displayIndex = false if (cr.levelFound == 0) lvi.SubItems[ColumnIndexWildLevel].ForeColor = Color.LightGray; - // color for mutation + // color for mutations counter if (cr.Mutations > 0) { if (cr.Mutations < Ark.MutationPossibleWithLessThan) diff --git a/ARKBreedingStats/Form1.tester.cs b/ARKBreedingStats/Form1.tester.cs index e4cb127d2..8148ee3d3 100644 --- a/ARKBreedingStats/Form1.tester.cs +++ b/ARKBreedingStats/Form1.tester.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Windows.Forms; using ARKBreedingStats.library; +using ARKBreedingStats.uiControls; using ARKBreedingStats.utils; namespace ARKBreedingStats @@ -353,6 +354,7 @@ private void pictureBoxColorRegionsTester_Click(object sender, EventArgs e) { Species = speciesSelector1.SelectedSpecies, levelsWild = GetCurrentWildLevels(false), + levelsMutated = CreatureCollection.CurrentCreatureCollection.Game == Ark.Asa ? GetCurrentMutLevels(false) : null, levelsDom = GetCurrentDomLevels(false), tamingEff = TamingEffectivenessTester, isBred = rbBredTester.Checked, @@ -373,6 +375,7 @@ private void PbCreatureColorsExtractor_Click(object sender, EventArgs e) { Species = speciesSelector1.SelectedSpecies, levelsWild = GetCurrentWildLevels(true), + levelsMutated = CreatureCollection.CurrentCreatureCollection.Game == Ark.Asa ? GetCurrentMutLevels(true) : null, levelsDom = GetCurrentDomLevels(true), tamingEff = _extractor.UniqueTamingEffectiveness(), isBred = rbBredExtractor.Checked, diff --git a/ARKBreedingStats/Pedigree/PedigreeCreature.cs b/ARKBreedingStats/Pedigree/PedigreeCreature.cs index 7cf3c6a1a..d8e804e6b 100644 --- a/ARKBreedingStats/Pedigree/PedigreeCreature.cs +++ b/ARKBreedingStats/Pedigree/PedigreeCreature.cs @@ -215,7 +215,7 @@ public Creature Creature { _labels[s].Text = _creature.levelsWild[si].ToString(); if (Properties.Settings.Default.Highlight255Level && _creature.levelsWild[si] > 253) // 255 is max, 254 is the highest that allows dom leveling - _labels[s].BackColor = Utils.AdjustColorLight(_creature.levelsWild[si] == 254 ? Utils.Level254 : Utils.Level255, _creature.topBreedingStats[si] ? 0.2 : 0.7); + _labels[s].BackColor = Utils.AdjustColorLight(_creature.levelsWild[si] == 254 ? Utils.Level254 : Utils.Level255, _creature.IsTopStat(si) ? 0.2 : 0.7); else if (Properties.Settings.Default.HighlightEvenOdd) { var levelForColor = Math.Min(maxChartLevel, Math.Max(minChartLevel, _creature.levelsWild[si])); @@ -228,10 +228,10 @@ public Creature Creature { hue = Properties.Settings.Default.ChartHueOddMin + levelForColor * hueRangeOdd / chartLevelRange; } - _labels[s].BackColor = Utils.ColorFromHue(hue, _creature.topBreedingStats[si] ? 0.4 : 0.7); + _labels[s].BackColor = Utils.ColorFromHue(hue, _creature.IsTopStat(si) ? 0.4 : 0.7); } else - _labels[s].BackColor = Utils.GetColorFromPercent((int)(_creature.levelsWild[si] * 2.5), _creature.topBreedingStats[si] ? 0.2 : 0.7); + _labels[s].BackColor = Utils.GetColorFromPercent((int)(_creature.levelsWild[si] * 2.5), _creature.IsTopStat(si) ? 0.2 : 0.7); _labels[s].ForeColor = Parent?.ForeColor ?? Color.Black; // needed so text is not transparent on overlay _ttMonospaced.SetToolTip(_labels[s], Utils.StatName(si, false, _creature.Species?.statNames) + ": " + $"{_creature.valuesBreeding[si] * (Utils.Precision(si) == 3 ? 100 : 1),7:#,0.0}" @@ -241,7 +241,7 @@ public Creature Creature )); } // fonts are strange, and this seems to work. The assigned font-object is probably only used to read out the properties and then not used anymore. - using (var font = new Font("Microsoft Sans Serif", 8.25F, (_creature.topBreedingStats?[si]).GetValueOrDefault() ? FontStyle.Bold : FontStyle.Regular, GraphicsUnit.Point, 0)) + using (var font = new Font("Microsoft Sans Serif", 8.25F, _creature.IsTopStat(si) ? FontStyle.Bold : FontStyle.Regular, GraphicsUnit.Point, 0)) _labels[s].Font = font; } if (OnlyLevels) diff --git a/ARKBreedingStats/Pedigree/PedigreeCreatureCompact.cs b/ARKBreedingStats/Pedigree/PedigreeCreatureCompact.cs index f21b5afca..8acf3985a 100644 --- a/ARKBreedingStats/Pedigree/PedigreeCreatureCompact.cs +++ b/ARKBreedingStats/Pedigree/PedigreeCreatureCompact.cs @@ -162,7 +162,7 @@ private void DrawData(Creature creature, bool highlight, int highlightStatIndex, var pieRadius = (int)(radiusInnerCircle + (centerCoord - radiusInnerCircle - borderWidth) * statSize); var leftTop = centerCoord - pieRadius; var angle = AngleOffset + anglePerStat * i++; - brush.Color = Utils.GetColorFromPercent((int)(100 * statSize), creature.topBreedingStats[si] ? 0 : 0.7); + brush.Color = Utils.GetColorFromPercent((int)(100 * statSize), creature.IsTopStat(si) ? 0 : 0.7); g.FillPie(brush, leftTop, leftTop, 2 * pieRadius, 2 * pieRadius, angle, anglePerStat); pen.Width = highlightStatIndex == si ? 2 : 1; diff --git a/ARKBreedingStats/Properties/AssemblyInfo.cs b/ARKBreedingStats/Properties/AssemblyInfo.cs index 50ab4ac2f..1a2a4a781 100644 --- a/ARKBreedingStats/Properties/AssemblyInfo.cs +++ b/ARKBreedingStats/Properties/AssemblyInfo.cs @@ -30,6 +30,6 @@ // Revision // [assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("0.59.6.0")] +[assembly: AssemblyFileVersion("0.60.0.0")] [assembly: NeutralResourcesLanguage("en")] diff --git a/ARKBreedingStats/Properties/Resources.Designer.cs b/ARKBreedingStats/Properties/Resources.Designer.cs index 168f7e4ac..db5458304 100644 --- a/ARKBreedingStats/Properties/Resources.Designer.cs +++ b/ARKBreedingStats/Properties/Resources.Designer.cs @@ -19,7 +19,7 @@ namespace ARKBreedingStats.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { @@ -98,6 +98,15 @@ internal static System.Drawing.Bitmap locked { } } + /// + /// Looks up a localized resource of type System.IO.UnmanagedMemoryStream similar to System.IO.MemoryStream. + /// + internal static System.IO.UnmanagedMemoryStream newMutation { + get { + return ResourceManager.GetStream("newMutation", resourceCulture); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -184,5 +193,14 @@ internal static System.Drawing.Bitmap unlocked { return ((System.Drawing.Bitmap)(obj)); } } + + /// + /// Looks up a localized resource of type System.IO.UnmanagedMemoryStream similar to System.IO.MemoryStream. + /// + internal static System.IO.UnmanagedMemoryStream updated { + get { + return ResourceManager.GetStream("updated", resourceCulture); + } + } } } diff --git a/ARKBreedingStats/Properties/Resources.resx b/ARKBreedingStats/Properties/Resources.resx index cba3c906c..d3252ce0a 100644 --- a/ARKBreedingStats/Properties/Resources.resx +++ b/ARKBreedingStats/Properties/Resources.resx @@ -157,4 +157,10 @@ ..\Resources\topstat.wav;System.IO.MemoryStream, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Resources\updated.wav;System.IO.MemoryStream, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\Resources\newMutation.wav;System.IO.MemoryStream, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + \ No newline at end of file diff --git a/ARKBreedingStats/Properties/Settings.Designer.cs b/ARKBreedingStats/Properties/Settings.Designer.cs index 41c269f08..06aaf611e 100644 --- a/ARKBreedingStats/Properties/Settings.Designer.cs +++ b/ARKBreedingStats/Properties/Settings.Designer.cs @@ -2278,5 +2278,29 @@ public bool LibraryShowMutationLevelColumns { this["LibraryShowMutationLevelColumns"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool StreamerMode { + get { + return ((bool)(this["StreamerMode"])); + } + set { + this["StreamerMode"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool LibraryDisplayZeroMutationLevels { + get { + return ((bool)(this["LibraryDisplayZeroMutationLevels"])); + } + set { + this["LibraryDisplayZeroMutationLevels"] = value; + } + } } } diff --git a/ARKBreedingStats/Properties/Settings.settings b/ARKBreedingStats/Properties/Settings.settings index 1b15c4dfd..92abc3e12 100644 --- a/ARKBreedingStats/Properties/Settings.settings +++ b/ARKBreedingStats/Properties/Settings.settings @@ -572,5 +572,11 @@ True + + False + + + False + \ No newline at end of file diff --git a/ARKBreedingStats/Resources/newMutation.wav b/ARKBreedingStats/Resources/newMutation.wav new file mode 100644 index 000000000..82faae579 Binary files /dev/null and b/ARKBreedingStats/Resources/newMutation.wav differ diff --git a/ARKBreedingStats/Resources/updated.wav b/ARKBreedingStats/Resources/updated.wav new file mode 100644 index 000000000..cf03f3275 Binary files /dev/null and b/ARKBreedingStats/Resources/updated.wav differ diff --git a/ARKBreedingStats/SpeciesSelector.cs b/ARKBreedingStats/SpeciesSelector.cs index 4a21c20b2..c526a81d8 100644 --- a/ARKBreedingStats/SpeciesSelector.cs +++ b/ARKBreedingStats/SpeciesSelector.cs @@ -313,14 +313,26 @@ private void lvSpeciesInLibrary_SelectedIndexChanged(object sender, EventArgs e) SetSpecies((Species)lvSpeciesInLibrary.SelectedItems[0].Tag, true); } + /// + /// Return species by entry string. + /// + public bool SetSpeciesByEntryName(string entryString) + { + if (_entryList == null || string.IsNullOrEmpty(entryString)) return false; + var species = _entryList.FirstOrDefault(e => e.DisplayName.Equals(entryString, StringComparison.OrdinalIgnoreCase))?.Species; + if (species == null) return false; + SetSpeciesByName(null, species); + return true; + } + /// /// Sets the species with the speciesName. This may not be unique. /// - /// /// True if the species was recognized and was already or is set. - public bool SetSpeciesByName(string speciesName) + public bool SetSpeciesByName(string speciesName, Species species = null) { - if (Values.V.TryGetSpeciesByName(speciesName, out Species species)) + if (species != null + || (!string.IsNullOrEmpty(speciesName) && Values.V.TryGetSpeciesByName(speciesName, out species))) { var speciesWasSet = SetSpecies(species); if (speciesWasSet) diff --git a/ARKBreedingStats/_manifest.json b/ARKBreedingStats/_manifest.json index 66fe0e5fa..1ee774ddc 100644 --- a/ARKBreedingStats/_manifest.json +++ b/ARKBreedingStats/_manifest.json @@ -4,7 +4,7 @@ "ARK Smart Breeding": { "Id": "ARK Smart Breeding", "Category": "main", - "version": "0.59.6.0" + "version": "0.60.0.0" }, "SpeciesColorImages": { "Id": "SpeciesColorImages", diff --git a/ARKBreedingStats/json/ocr/ocr_1920x1080_100.json b/ARKBreedingStats/json/ocr/ocr_1920x1080_100.json index 23da53e40..e06d6e711 100644 --- a/ARKBreedingStats/json/ocr/ocr_1920x1080_100.json +++ b/ARKBreedingStats/json/ocr/ocr_1920x1080_100.json @@ -1 +1 @@ -{"Version":"2.0","description":null,"resize":1.0,"resolutionWidth":1920,"resolutionHeight":1080,"statDistance":0,"guiZoom":100,"RecognitionPatterns":{"Texts":[{"Text":"!","Patterns":[{"y":0,"Data":[2,12,14679551]},{"y":0,"Data":[1,10,895]}]},{"Text":"\"","Patterns":[{"y":0,"Data":[5,4,987377]},{"y":0,"Data":[4,3,3595]}]},{"Text":"#","Patterns":[{"y":0,"Data":[13,12,-5675593754190184176,1806490977058232337,1577345]},{"y":0,"Data":[11,10,-4526032829485600692,829739179836]}]},{"Text":"$","Patterns":[{"y":0,"Data":[7,12,-3573634383000125384,248894]},{"y":0,"Data":[6,10,259439581955807260]}]},{"Text":"%","Patterns":[{"y":0,"Data":[11,12,134599147163596804,132918339478960134,7]},{"y":0,"Data":[10,11,-7492051260306076666,30841146759792]},{"y":0,"Data":[9,10,7449013377828664838,63017188]},{"y":0,"Data":[9,10,8011956633315583495,62951652]}]},{"Text":"&","Patterns":[{"y":0,"Data":[10,12,4351539627639693576,1693112599339974]},{"y":0,"Data":[9,10,-8338676649610969914,1063967]}]},{"Text":"'","Patterns":[{"y":0,"Data":[2,4,241]},{"y":0,"Data":[2,2,7]}]},{"Text":"(","Patterns":[{"y":0,"Data":[4,15,576528938667213248]},{"y":0,"Data":[3,13,412417515760]},{"y":0,"Data":[3,15,26396868939768]}]},{"Text":")","Patterns":[{"y":0,"Data":[4,15,15780187594014721]},{"y":0,"Data":[3,13,68516179969]}]},{"Text":"*","Patterns":[{"y":0,"Data":[5,5,4595332]},{"y":0,"Data":[4,4,42850]}]},{"Text":"+","Patterns":[{"y":5,"Data":[6,6,13102793484]},{"y":3,"Data":[5,6,204731148]}]},{"Text":",","Patterns":[{"y":10,"Data":[3,4,508]},{"y":10,"Data":[3,3,126]},{"y":9,"Data":[2,3,30]}]},{"Text":"-","Patterns":[{"y":7,"Data":[4,2,255]},{"y":5,"Data":[3,2,63]}]},{"Text":".","Patterns":[{"y":10,"Data":[2,2,15]},{"y":8,"Data":[2,2,15]},{"y":8,"Data":[1,2,3]}]},{"Text":"/","Patterns":[{"y":0,"Data":[8,12,-2290065002308040704,1049344]},{"y":0,"Data":[7,11,252695124297384960,4]},{"y":0,"Data":[7,10,1156314657855504896,0]},{"y":0,"Data":[6,10,1133626670908160]}]},{"Text":"0","Patterns":[{"y":0,"Data":[10,12,4324511409900601584,17952408180884416]},{"y":0,"Data":[10,11,135173988541264120,4140321273871]},{"y":0,"Data":[9,10,4325427893140715640,16547824]}]},{"Text":"1","Patterns":[{"y":0,"Data":[3,12,68702707714]},{"y":0,"Data":[3,11,8585746434]},{"y":0,"Data":[3,10,1073740801]}]},{"Text":"2","Patterns":[{"y":0,"Data":[8,12,4432650607404264448,3287056076]},{"y":0,"Data":[8,11,3597319504896466432,12654843]},{"y":0,"Data":[7,10,-1373771675889563904,48]}]},{"Text":"3","Patterns":[{"y":0,"Data":[8,12,4351539627643911170,969408198]},{"y":0,"Data":[7,11,4171244095319055875,3963]},{"y":0,"Data":[7,10,-1153148225409202431,28]}]},{"Text":"4","Patterns":[{"y":0,"Data":[9,12,3534782280039661952,1103790862608]},{"y":0,"Data":[8,11,-4568775273204481600,3153888]},{"y":0,"Data":[8,10,-8078117213996597056,8255]}]},{"Text":"5","Patterns":[{"y":0,"Data":[7,12,4351535228523789375,246654]},{"y":0,"Data":[7,11,-1088995471009935809,513]},{"y":0,"Data":[6,10,542597737130510111]}]},{"Text":"6","Patterns":[{"y":0,"Data":[9,12,4338869619491013056,4125283328707]},{"y":0,"Data":[8,11,1792780293042585824,8132803]},{"y":0,"Data":[8,10,893429643454443760,14367]}]},{"Text":"7","Patterns":[{"y":0,"Data":[8,12,3585833139966062595,15736583]},{"y":0,"Data":[8,11,2129700729988847619,24636]},{"y":0,"Data":[7,10,8085150145732674561,0]},{"y":0,"Data":[8,10,8103226357411480577,64]}]},{"Text":"8","Patterns":[{"y":0,"Data":[9,12,4351539627975107456,8300023018438]},{"y":0,"Data":[8,11,1865401086104304064,8116719]},{"y":0,"Data":[8,10,-223190121080963900,29118]}]},{"Text":"9","Patterns":[{"y":0,"Data":[9,12,4378567770993319960,533110932332]},{"y":0,"Data":[8,11,-5717851056935669732,1034125]},{"y":0,"Data":[8,10,8252179774253890572,3975]}]},{"Text":":","Patterns":[{"y":3,"Data":[1,9,387]},{"y":2,"Data":[1,8,195]},{"y":3,"Data":[2,9,198531]}]},{"Text":";","Patterns":[{"y":3,"Data":[3,11,3774350336]},{"y":2,"Data":[3,10,138284544]}]},{"Text":"<","Patterns":[{"y":4,"Data":[7,7,438925902941704]},{"y":3,"Data":[6,6,55605576460]}]},{"Text":"=","Patterns":[{"y":5,"Data":[6,5,935194491]},{"y":4,"Data":[5,4,768955]}]},{"Text":">","Patterns":[{"y":4,"Data":[7,7,124121447510499]},{"y":3,"Data":[6,6,13360639203]}]},{"Text":"?","Patterns":[{"y":0,"Data":[8,12,3486637399386107906,8404486]},{"y":0,"Data":[7,10,4646607660775228417,0]}]},{"Text":"@","Patterns":[{"y":0,"Data":[16,15,7350093424881304000,-7270718866723136000,-9195228645226820212,17318379831393]},{"y":0,"Data":[14,13,-7199565064100151056,-62648989679651173,1108839793629196]}]},{"Text":"A","Patterns":[{"y":0,"Data":[12,12,8078903044008315904,33779127974727448,32782]},{"y":0,"Data":[10,10,-2194305236006927616,51568975367]},{"y":0,"Data":[12,12,8087373147937966080,-9205918423200987376,49167]}]},{"Text":"B","Patterns":[{"y":0,"Data":[8,12,4351533028967710719,2112815046]},{"y":0,"Data":[7,10,-238952719835199489,30]}]},{"Text":"C","Patterns":[{"y":0,"Data":[10,12,4324406062942765152,54091590150128576]},{"y":0,"Data":[9,10,2019584885671589944,50446448]}]},{"Text":"D","Patterns":[{"y":0,"Data":[10,12,4324511431203487743,4367244623348672]},{"y":0,"Data":[8,10,4327679692952569855,16280]}]},{"Text":"E","Patterns":[{"y":0,"Data":[8,12,4351539627644420095,3222037446]},{"y":0,"Data":[6,10,920759402994911231]}]},{"Text":"F","Patterns":[{"y":0,"Data":[7,12,3486637341404561407,25350]},{"y":0,"Data":[6,10,55223024169830399]}]},{"Text":"G","Patterns":[{"y":0,"Data":[10,12,4324546800431120480,69858037136622528]},{"y":0,"Data":[9,10,2019584885671589944,65140848]}]},{"Text":"H","Patterns":[{"y":0,"Data":[10,12,27028196461379583,72057589843648518]},{"y":0,"Data":[8,10,54096023676568575,65475]}]},{"Text":"I","Patterns":[{"y":0,"Data":[2,12,16777215]},{"y":0,"Data":[1,10,1023]}]},{"Text":"J","Patterns":[{"y":0,"Data":[4,12,70334380248064]},{"y":0,"Data":[3,10,536609536]}]},{"Text":"K","Patterns":[{"y":0,"Data":[10,12,-9155811445357674497,36059599995080221]},{"y":0,"Data":[9,10,3681811502760723455,33603704]}]},{"Text":"L","Patterns":[{"y":0,"Data":[6,12,864902286244052991,192]},{"y":0,"Data":[5,10,845250369946623]}]},{"Text":"M","Patterns":[{"y":0,"Data":[12,12,252218072276991999,-71810821926223648,65535]},{"y":0,"Data":[10,10,1009791719497015295,68652828430]}]},{"Text":"N","Patterns":[{"y":0,"Data":[10,12,31526846893948927,72057591622238220]},{"y":0,"Data":[9,10,216225584456409087,67108824]}]},{"Text":"O","Patterns":[{"y":0,"Data":[12,12,4324511684778508384,-256445677905902656,3843]},{"y":0,"Data":[10,10,2019584883524106296,17075519728]}]},{"Text":"P","Patterns":[{"y":0,"Data":[8,12,3513656738551169023,65044230]},{"y":0,"Data":[7,10,-2275389783044782081,0]}]},{"Text":"Q","Patterns":[{"y":0,"Data":[12,15,3567099134693212256,249956857632790720,32989629351804]},{"y":0,"Data":[10,13,3463690901644099640,2288329816673371650,0]}]},{"Text":"R","Patterns":[{"y":0,"Data":[9,12,3513656738551169023,8799346177854]},{"y":0,"Data":[8,10,-689911607977834497,32816]}]},{"Text":"S","Patterns":[{"y":0,"Data":[9,12,4351539627644149788,4133876425670]},{"y":0,"Data":[8,10,2073680907601738766,30815]}]},{"Text":"T","Patterns":[{"y":0,"Data":[8,12,4611685949758255107,3146496]},{"y":0,"Data":[7,10,1154049602464252929,0]}]},{"Text":"U","Patterns":[{"y":0,"Data":[10,12,864902286235661311,4494800850780352]},{"y":0,"Data":[8,10,865536378825212415,32728]}]},{"Text":"V","Patterns":[{"y":0,"Data":[12,12,1116925695017218051,504949032470118624,16]},{"y":0,"Data":[10,10,1009791994408483843,67571471]}]},{"Text":"W","Patterns":[{"y":0,"Data":[14,12,-9097007296847810545,-9214646046281429245,8455516175]},{"y":0,"Data":[13,10,3466707627345442831,76560158593910656,0]}]},{"Text":"X","Patterns":[{"y":0,"Data":[11,12,141926911075956737,126231692548632591,8]},{"y":0,"Data":[10,10,-4476516203142312447,34477269452]}]},{"Text":"Y","Patterns":[{"y":0,"Data":[10,12,1143918154112593921,52841012031740]},{"y":0,"Data":[9,10,-2241684246565483519,65728]}]},{"Text":"Z","Patterns":[{"y":0,"Data":[8,12,-4885334407164969469,3229355969]},{"y":0,"Data":[7,10,4332196512590137217,48]}]},{"Text":"[","Patterns":[{"y":0,"Data":[4,15,864823074145435647]},{"y":0,"Data":[4,13,3378661927419903]}]},{"Text":"\\","Patterns":[{"y":0,"Data":[8,12,126108486617591811,2148270192]},{"y":0,"Data":[7,10,865183829952830465,32]}]},{"Text":"]","Patterns":[{"y":0,"Data":[4,15,1152921504338534403]},{"y":0,"Data":[3,13,549739051009]}]},{"Text":"^","Patterns":[{"y":0,"Data":[7,6,2224894561824]},{"y":0,"Data":[6,5,820088208]}]},{"Text":"_","Patterns":[{"y":12,"Data":[8,2,65535]},{"y":10,"Data":[7,2,16383]}]},{"Text":"`","Patterns":[{"y":0,"Data":[4,2,181]},{"y":0,"Data":[3,1,7]}]},{"Text":"a","Patterns":[{"y":3,"Data":[7,9,9192507906305549536]},{"y":2,"Data":[6,8,279669406167664]}]},{"Text":"b","Patterns":[{"y":0,"Data":[7,12,871659335216861183,254071]},{"y":0,"Data":[6,10,568465942083544063]}]},{"Text":"c","Patterns":[{"y":3,"Data":[7,9,6967200823140547704]},{"y":2,"Data":[6,8,215245570342460]}]},{"Text":"d","Patterns":[{"y":0,"Data":[8,12,871659335749403584,4294967233]},{"y":0,"Data":[7,10,-271840546660112,63]}]},{"Text":"e","Patterns":[{"y":3,"Data":[8,9,7472132848649632824,14]},{"y":2,"Data":[7,8,8126335215697468]},{"y":3,"Data":[7,7,55476904689468]}]},{"Text":"f","Patterns":[{"y":0,"Data":[5,12,283193416728574]},{"y":0,"Data":[4,10,1087387647]},{"y":0,"Data":[4,10,9676258300]}]},{"Text":"g","Patterns":[{"y":3,"Data":[8,12,4432624217029075064,1072168904]},{"y":2,"Data":[7,11,-5561846539751364,2041]}]},{"Text":"h","Patterns":[{"y":0,"Data":[7,12,6757048977133567,1044735]},{"y":0,"Data":[6,10,1143940706524472319]}]},{"Text":"i","Patterns":[{"y":0,"Data":[1,12,4091]},{"y":0,"Data":[1,10,1021]},{"y":0,"Data":[3,12,1090502643]},{"y":1,"Data":[1,9,509]},{"y":1,"Data":[2,9,261117]},{"y":0,"Data":[2,12,16760827]}]},{"Text":"j","Patterns":[{"y":0,"Data":[2,15,1073602560]},{"y":0,"Data":[2,13,33537024]}]},{"Text":"k","Patterns":[{"y":0,"Data":[8,12,-9000424613577814017,2215440633]},{"y":0,"Data":[7,10,928810467592250367,32]}]},{"Text":"l","Patterns":[{"y":0,"Data":[1,12,4095]},{"y":0,"Data":[1,10,1023]}]},{"Text":"m","Patterns":[{"y":3,"Data":[12,9,9205287476162727423,17488973005569]},{"y":2,"Data":[10,8,217016098992816895,65027]},{"y":3,"Data":[11,7,-9006623177486319745,3903]}]},{"Text":"n","Patterns":[{"y":3,"Data":[7,9,9205287476162727423]},{"y":2,"Data":[6,8,279301773722367]}]},{"Text":"o","Patterns":[{"y":3,"Data":[8,9,3580493903357934712,126]},{"y":2,"Data":[7,8,35684390097092156]}]},{"Text":"p","Patterns":[{"y":3,"Data":[7,12,-2196885592294801409,31758]},{"y":2,"Data":[6,11,4471618708997283839,0]}]},{"Text":"q","Patterns":[{"y":3,"Data":[8,12,3567721930789216376,4293918488]},{"y":2,"Data":[7,11,-32596644889104324,8187]}]},{"Text":"r","Patterns":[{"y":3,"Data":[4,9,403181055]},{"y":2,"Data":[3,8,197375]},{"y":3,"Data":[5,9,137709223935]}]},{"Text":"s","Patterns":[{"y":3,"Data":[7,9,4088841016286592012]},{"y":2,"Data":[6,8,126287534086670]},{"y":3,"Data":[8,9,8986505593863748616,112]}]},{"Text":"t","Patterns":[{"y":2,"Data":[4,10,831888817407]},{"y":1,"Data":[4,9,52447411455]}]},{"Text":"u","Patterns":[{"y":3,"Data":[7,9,9214338500961435903]},{"y":2,"Data":[6,8,280922012303615]}]},{"Text":"v","Patterns":[{"y":3,"Data":[8,9,-8948760151530128377,1]},{"y":2,"Data":[7,8,861161896549895]}]},{"Text":"w","Patterns":[{"y":3,"Data":[12,9,270466176792985095,107370102844]},{"y":2,"Data":[11,8,-2288946752006357497,69624]}]},{"Text":"x","Patterns":[{"y":3,"Data":[8,9,-2244543304241541373,128]},{"y":2,"Data":[7,8,36525150153008771]}]},{"Text":"y","Patterns":[{"y":3,"Data":[8,12,-9088127652882948089,3149575]},{"y":2,"Data":[7,11,542546870131552263,12]}]},{"Text":"z","Patterns":[{"y":3,"Data":[7,9,6985639089849468800]},{"y":2,"Data":[6,8,144652815819715]}]},{"Text":"{","Patterns":[{"y":0,"Data":[5,15,2290062676612612480,1024]},{"y":0,"Data":[4,13,3378519994007648]}]},{"Text":"|","Patterns":[{"y":0,"Data":[2,15,1073741823]},{"y":0,"Data":[1,13,8191]}]},{"Text":"}","Patterns":[{"y":0,"Data":[5,15,15771391554994177,24]},{"y":0,"Data":[4,13,52792730841089]}]},{"Text":"~","Patterns":[{"y":6,"Data":[6,3,222362]},{"y":5,"Data":[5,2,703]}]},{"Text":"♀","Patterns":[{"y":0,"Data":[22,15,72023508120469630,15763114108125432,-4607463764923645892,2233851387752603655,-1143931348285667392,3]}]},{"Text":"♂","Patterns":[{"y":0,"Data":[21,15,-33812185335986240,216179379686882816,13511211203166336,-1144054909694640104,15784582485901119]}]}],"TrainingSettings":{"IsTrainingEnabled":false,"SkipName":false,"SkipTribe":false,"SkipOwner":false}},"labelRectangles":["989, 509, 129, 14","989, 552, 129, 14","989, 595, 129, 14","989, 638, 129, 14","989, 681, 129, 14","989, 724, 129, 14","989, 767, 129, 14","989, 810, 129, 14","989, 853, 129, 14","857, 199, 206, 15","850, 164, 219, 15","877, 233, 168, 13","892, 273, 150, 13"]} \ No newline at end of file +{"Version":"2.0","description":null,"resize":1.0,"resolutionWidth":1920,"resolutionHeight":1080,"statDistance":0,"guiZoom":100,"RecognitionPatterns":{"Texts":[{"Text":"!","Patterns":[{"y":0,"Data":[2,12,14679551]},{"y":0,"Data":[1,10,895]}]},{"Text":"\"","Patterns":[{"y":0,"Data":[5,4,987377]},{"y":0,"Data":[4,3,3595]}]},{"Text":"#","Patterns":[{"y":0,"Data":[13,12,-5675593754190184176,1806490977058232337,1577345]},{"y":0,"Data":[11,10,-4526032829485600692,829739179836]}]},{"Text":"$","Patterns":[{"y":0,"Data":[7,12,-3573634383000125384,248894]},{"y":0,"Data":[6,10,259439581955807260]}]},{"Text":"%","Patterns":[{"y":0,"Data":[11,12,134599147163596804,132918339478960134,7]},{"y":0,"Data":[10,11,-7492051260306076666,30841146759792]},{"y":0,"Data":[9,10,7449013377828664838,63017188]},{"y":0,"Data":[9,10,8011956633315583495,62951652]}]},{"Text":"&","Patterns":[{"y":0,"Data":[10,12,4351539627639693576,1693112599339974]},{"y":0,"Data":[9,10,-8338676649610969914,1063967]}]},{"Text":"'","Patterns":[{"y":0,"Data":[2,4,241]},{"y":0,"Data":[2,2,7]}]},{"Text":"(","Patterns":[{"y":0,"Data":[4,15,576528938667213248]},{"y":0,"Data":[3,13,412417515760]},{"y":0,"Data":[3,15,26396868939768]}]},{"Text":")","Patterns":[{"y":0,"Data":[4,15,15780187594014721]},{"y":0,"Data":[3,13,68516179969]}]},{"Text":"*","Patterns":[{"y":0,"Data":[5,5,4595332]},{"y":0,"Data":[4,4,42850]}]},{"Text":"+","Patterns":[{"y":5,"Data":[6,6,13102793484]},{"y":3,"Data":[5,6,204731148]}]},{"Text":",","Patterns":[{"y":10,"Data":[3,4,508]},{"y":10,"Data":[3,3,126]},{"y":9,"Data":[2,3,30]}]},{"Text":"-","Patterns":[{"y":7,"Data":[4,2,255]},{"y":5,"Data":[3,2,63]}]},{"Text":".","Patterns":[{"y":10,"Data":[2,2,15]},{"y":8,"Data":[2,2,15]},{"y":8,"Data":[1,2,3]}]},{"Text":"/","Patterns":[{"y":0,"Data":[8,12,-2290065002308040704,1049344]},{"y":0,"Data":[7,11,252695124297384960,4]},{"y":0,"Data":[7,10,1156314657855504896,0]},{"y":0,"Data":[6,10,1133626670908160]}]},{"Text":"0","Patterns":[{"y":0,"Data":[10,12,4324511409900601584,17952408180884416]},{"y":0,"Data":[10,11,135173988541264120,4140321273871]},{"y":0,"Data":[9,10,4325427893140715640,16547824]}]},{"Text":"1","Patterns":[{"y":0,"Data":[3,12,68702707714]},{"y":0,"Data":[3,11,8585746434]},{"y":0,"Data":[3,10,1073740801]}]},{"Text":"2","Patterns":[{"y":0,"Data":[8,12,4432650607404264448,3287056076]},{"y":0,"Data":[8,11,3597319504896466432,12654843]},{"y":0,"Data":[7,10,-1373771675889563904,48]}]},{"Text":"3","Patterns":[{"y":0,"Data":[8,12,4351539627643911170,969408198]},{"y":0,"Data":[7,11,4171244095319055875,3963]},{"y":0,"Data":[7,10,-1153148225409202431,28]}]},{"Text":"4","Patterns":[{"y":0,"Data":[9,12,3534782280039661952,1103790862608]},{"y":0,"Data":[8,11,-4568775273204481600,3153888]},{"y":0,"Data":[8,10,-8078117213996597056,8255]}]},{"Text":"5","Patterns":[{"y":0,"Data":[7,12,4351535228523789375,246654]},{"y":0,"Data":[7,11,-1088995471009935809,513]},{"y":0,"Data":[6,10,542597737130510111]}]},{"Text":"6","Patterns":[{"y":0,"Data":[9,12,4338869619491013056,4125283328707]},{"y":0,"Data":[8,11,1792780293042585824,8132803]},{"y":0,"Data":[8,10,893429643454443760,14367]}]},{"Text":"7","Patterns":[{"y":0,"Data":[8,12,3585833139966062595,15736583]},{"y":0,"Data":[8,11,2129700729988847619,24636]},{"y":0,"Data":[7,10,8085150145732674561,0]},{"y":0,"Data":[8,10,8103226357411480577,64]}]},{"Text":"8","Patterns":[{"y":0,"Data":[9,12,4351539627975107456,8300023018438]},{"y":0,"Data":[8,11,1865401086104304064,8116719]},{"y":0,"Data":[8,10,-223190121080963900,29118]}]},{"Text":"9","Patterns":[{"y":0,"Data":[9,12,4378567770993319960,533110932332]},{"y":0,"Data":[8,11,-5717851056935669732,1034125]},{"y":0,"Data":[8,10,8252179774253890572,3975]}]},{"Text":":","Patterns":[{"y":3,"Data":[1,9,387]},{"y":2,"Data":[1,8,195]},{"y":3,"Data":[2,9,198531]}]},{"Text":";","Patterns":[{"y":3,"Data":[3,11,3774350336]},{"y":2,"Data":[3,10,138284544]}]},{"Text":"<","Patterns":[{"y":4,"Data":[7,7,438925902941704]},{"y":3,"Data":[6,6,55605576460]}]},{"Text":"=","Patterns":[{"y":5,"Data":[6,5,935194491]},{"y":4,"Data":[5,4,768955]}]},{"Text":">","Patterns":[{"y":4,"Data":[7,7,124121447510499]},{"y":3,"Data":[6,6,13360639203]}]},{"Text":"?","Patterns":[{"y":0,"Data":[8,12,3486637399386107906,8404486]},{"y":0,"Data":[7,10,4646607660775228417,0]}]},{"Text":"@","Patterns":[{"y":0,"Data":[16,15,7350093424881304000,-7270718866723136000,-9195228645226820212,17318379831393]},{"y":0,"Data":[14,13,-7199565064100151056,-62648989679651173,1108839793629196]}]},{"Text":"A","Patterns":[{"y":0,"Data":[12,12,8078903044008315904,33779127974727448,32782]},{"y":0,"Data":[10,10,-2194305236006927616,51568975367]},{"y":0,"Data":[12,12,8087373147937966080,-9205918423200987376,49167]}]},{"Text":"B","Patterns":[{"y":0,"Data":[8,12,4351533028967710719,2112815046]},{"y":0,"Data":[7,10,-238952719835199489,30]}]},{"Text":"C","Patterns":[{"y":0,"Data":[10,12,4324406062942765152,54091590150128576]},{"y":0,"Data":[9,10,2019584885671589944,50446448]}]},{"Text":"D","Patterns":[{"y":0,"Data":[10,12,4324511431203487743,4367244623348672]},{"y":0,"Data":[8,10,4327679692952569855,16280]}]},{"Text":"E","Patterns":[{"y":0,"Data":[8,12,4351539627644420095,3222037446]},{"y":0,"Data":[6,10,920759402994911231]}]},{"Text":"F","Patterns":[{"y":0,"Data":[7,12,3486637341404561407,25350]},{"y":0,"Data":[6,10,55223024169830399]}]},{"Text":"G","Patterns":[{"y":0,"Data":[10,12,4324546800431120480,69858037136622528]},{"y":0,"Data":[9,10,2019584885671589944,65140848]}]},{"Text":"H","Patterns":[{"y":0,"Data":[10,12,27028196461379583,72057589843648518]},{"y":0,"Data":[8,10,54096023676568575,65475]}]},{"Text":"I","Patterns":[{"y":0,"Data":[2,12,16777215]},{"y":0,"Data":[1,10,1023]}]},{"Text":"J","Patterns":[{"y":0,"Data":[4,12,70334380248064]},{"y":0,"Data":[3,10,536609536]}]},{"Text":"K","Patterns":[{"y":0,"Data":[10,12,-9155811445357674497,36059599995080221]},{"y":0,"Data":[9,10,3681811502760723455,33603704]}]},{"Text":"L","Patterns":[{"y":0,"Data":[6,12,864902286244052991,192]},{"y":0,"Data":[5,10,845250369946623]}]},{"Text":"M","Patterns":[{"y":0,"Data":[12,12,252218072276991999,-71810821926223648,65535]},{"y":0,"Data":[10,10,1009791719497015295,68652828430]}]},{"Text":"N","Patterns":[{"y":0,"Data":[10,12,31526846893948927,72057591622238220]},{"y":0,"Data":[9,10,216225584456409087,67108824]}]},{"Text":"O","Patterns":[{"y":0,"Data":[12,12,4324511684778508384,-256445677905902656,3843]},{"y":0,"Data":[10,10,2019584883524106296,17075519728]}]},{"Text":"P","Patterns":[{"y":0,"Data":[8,12,3513656738551169023,65044230]},{"y":0,"Data":[7,10,-2275389783044782081,0]}]},{"Text":"Q","Patterns":[{"y":0,"Data":[12,15,3567099134693212256,249956857632790720,32989629351804]},{"y":0,"Data":[10,13,3463690901644099640,2288329816673371650,0]}]},{"Text":"R","Patterns":[{"y":0,"Data":[9,12,3513656738551169023,8799346177854]},{"y":0,"Data":[8,10,-689911607977834497,32816]}]},{"Text":"S","Patterns":[{"y":0,"Data":[9,12,4351539627644149788,4133876425670]},{"y":0,"Data":[8,10,2073680907601738766,30815]}]},{"Text":"T","Patterns":[{"y":0,"Data":[8,12,4611685949758255107,3146496]},{"y":0,"Data":[7,10,1154049602464252929,0]}]},{"Text":"U","Patterns":[{"y":0,"Data":[10,12,864902286235661311,4494800850780352]},{"y":0,"Data":[8,10,865536378825212415,32728]}]},{"Text":"V","Patterns":[{"y":0,"Data":[12,12,1116925695017218051,504949032470118624,16]},{"y":0,"Data":[10,10,1009791994408483843,67571471]}]},{"Text":"W","Patterns":[{"y":0,"Data":[14,12,-9097007296847810545,-9214646046281429245,8455516175]},{"y":0,"Data":[13,10,3466707627345442831,76560158593910656,0]}]},{"Text":"X","Patterns":[{"y":0,"Data":[11,12,141926911075956737,126231692548632591,8]},{"y":0,"Data":[10,10,-4476516203142312447,34477269452]}]},{"Text":"Y","Patterns":[{"y":0,"Data":[10,12,1143918154112593921,52841012031740]},{"y":0,"Data":[9,10,-2241684246565483519,65728]}]},{"Text":"Z","Patterns":[{"y":0,"Data":[8,12,-4885334407164969469,3229355969]},{"y":0,"Data":[7,10,4332196512590137217,48]}]},{"Text":"[","Patterns":[{"y":0,"Data":[4,15,864823074145435647]},{"y":0,"Data":[4,13,3378661927419903]}]},{"Text":"\\","Patterns":[{"y":0,"Data":[8,12,126108486617591811,2148270192]},{"y":0,"Data":[7,10,865183829952830465,32]}]},{"Text":"]","Patterns":[{"y":0,"Data":[4,15,1152921504338534403]},{"y":0,"Data":[3,13,549739051009]}]},{"Text":"^","Patterns":[{"y":0,"Data":[7,6,2224894561824]},{"y":0,"Data":[6,5,820088208]}]},{"Text":"_","Patterns":[{"y":12,"Data":[8,2,65535]},{"y":10,"Data":[7,2,16383]}]},{"Text":"`","Patterns":[{"y":0,"Data":[4,2,181]},{"y":0,"Data":[3,1,7]}]},{"Text":"a","Patterns":[{"y":3,"Data":[7,9,9192507906305549536]},{"y":2,"Data":[6,8,279669406167664]}]},{"Text":"b","Patterns":[{"y":0,"Data":[7,12,871659335216861183,254071]},{"y":0,"Data":[6,10,568465942083544063]}]},{"Text":"c","Patterns":[{"y":3,"Data":[7,9,6967200823140547704]},{"y":2,"Data":[6,8,215245570342460]}]},{"Text":"d","Patterns":[{"y":0,"Data":[8,12,871659335749403584,4294967233]},{"y":0,"Data":[7,10,-271840546660112,63]}]},{"Text":"e","Patterns":[{"y":3,"Data":[8,9,7472132848649632824,14]},{"y":2,"Data":[7,8,8126335215697468]},{"y":3,"Data":[7,7,55476904689468]}]},{"Text":"f","Patterns":[{"y":0,"Data":[5,12,283193416728574]},{"y":0,"Data":[4,10,1087387647]},{"y":0,"Data":[4,10,9676258300]}]},{"Text":"g","Patterns":[{"y":3,"Data":[8,12,4432624217029075064,1072168904]},{"y":2,"Data":[7,11,-5561846539751364,2041]}]},{"Text":"h","Patterns":[{"y":0,"Data":[7,12,6757048977133567,1044735]},{"y":0,"Data":[6,10,1143940706524472319]}]},{"Text":"i","Patterns":[{"y":0,"Data":[1,12,4091]},{"y":0,"Data":[1,10,1021]},{"y":0,"Data":[3,12,1090502643]},{"y":1,"Data":[1,9,509]},{"y":1,"Data":[2,9,261117]},{"y":0,"Data":[2,12,16760827]}]},{"Text":"j","Patterns":[{"y":0,"Data":[2,15,1073602560]},{"y":0,"Data":[2,13,33537024]}]},{"Text":"k","Patterns":[{"y":0,"Data":[8,12,-9000424613577814017,2215440633]},{"y":0,"Data":[7,10,928810467592250367,32]}]},{"Text":"l","Patterns":[{"y":0,"Data":[1,12,4095]},{"y":0,"Data":[1,10,1023]}]},{"Text":"m","Patterns":[{"y":3,"Data":[12,9,9205287476162727423,17488973005569]},{"y":2,"Data":[10,8,217016098992816895,65027]},{"y":3,"Data":[11,7,-9006623177486319745,3903]}]},{"Text":"n","Patterns":[{"y":3,"Data":[7,9,9205287476162727423]},{"y":2,"Data":[6,8,279301773722367]}]},{"Text":"o","Patterns":[{"y":3,"Data":[8,9,3580493903357934712,126]},{"y":2,"Data":[7,8,35684390097092156]}]},{"Text":"p","Patterns":[{"y":3,"Data":[7,12,-2196885592294801409,31758]},{"y":2,"Data":[6,11,4471618708997283839,0]}]},{"Text":"q","Patterns":[{"y":3,"Data":[8,12,3567721930789216376,4293918488]},{"y":2,"Data":[7,11,-32596644889104324,8187]}]},{"Text":"r","Patterns":[{"y":3,"Data":[4,9,403181055]},{"y":2,"Data":[3,8,197375]},{"y":3,"Data":[5,9,137709223935]}]},{"Text":"s","Patterns":[{"y":3,"Data":[7,9,4088841016286592012]},{"y":2,"Data":[6,8,126287534086670]},{"y":3,"Data":[8,9,8986505593863748616,112]}]},{"Text":"t","Patterns":[{"y":2,"Data":[4,10,831888817407]},{"y":1,"Data":[4,9,52447411455]}]},{"Text":"u","Patterns":[{"y":3,"Data":[7,9,9214338500961435903]},{"y":2,"Data":[6,8,280922012303615]}]},{"Text":"v","Patterns":[{"y":3,"Data":[8,9,-8948760151530128377,1]},{"y":2,"Data":[7,8,861161896549895]}]},{"Text":"w","Patterns":[{"y":3,"Data":[12,9,270466176792985095,107370102844]},{"y":2,"Data":[11,8,-2288946752006357497,69624]}]},{"Text":"x","Patterns":[{"y":3,"Data":[8,9,-2244543304241541373,128]},{"y":2,"Data":[7,8,36525150153008771]}]},{"Text":"y","Patterns":[{"y":3,"Data":[8,12,-9088127652882948089,3149575]},{"y":2,"Data":[7,11,542546870131552263,12]}]},{"Text":"z","Patterns":[{"y":3,"Data":[7,9,6985639089849468800]},{"y":2,"Data":[6,8,144652815819715]}]},{"Text":"{","Patterns":[{"y":0,"Data":[5,15,2290062676612612480,1024]},{"y":0,"Data":[4,13,3378519994007648]}]},{"Text":"|","Patterns":[{"y":0,"Data":[2,15,1073741823]},{"y":0,"Data":[1,13,8191]}]},{"Text":"}","Patterns":[{"y":0,"Data":[5,15,15771391554994177,24]},{"y":0,"Data":[4,13,52792730841089]}]},{"Text":"~","Patterns":[{"y":6,"Data":[6,3,222362]},{"y":5,"Data":[5,2,703]}]},{"Text":"♀","Patterns":[{"y":0,"Data":[22,15,72023508120469630,15763114108125432,-4607463764923645892,2233851387752603655,-1143931348285667392,3]}]},{"Text":"♂","Patterns":[{"y":0,"Data":[21,15,-33812185335986240,216179379686882816,13511211203166336,-1144054909694640104,15784582485901119]}]}],"TrainingSettings":{"IsTrainingEnabled":false,"SkipName":false,"SkipTribe":false,"SkipOwner":false}},"LabelRectangles":{"default":["989, 509, 129, 14","989, 552, 129, 14","989, 595, 129, 14","989, 638, 129, 14","989, 681, 129, 14","989, 724, 129, 14","989, 767, 129, 14","989, 810, 129, 14","989, 853, 129, 14","857, 199, 206, 15","850, 164, 219, 15","877, 233, 168, 13","892, 273, 150, 13"]},"SelectedLabelSetName":"default"} \ No newline at end of file diff --git a/ARKBreedingStats/json/ocr/ocr_2560x1440_100.json b/ARKBreedingStats/json/ocr/ocr_2560x1440_100.json index 2588099b5..8b4175b99 100644 --- a/ARKBreedingStats/json/ocr/ocr_2560x1440_100.json +++ b/ARKBreedingStats/json/ocr/ocr_2560x1440_100.json @@ -1 +1 @@ -{"Version":"2.0","description":null,"resize":1.0,"resolutionWidth":2560,"resolutionHeight":1440,"statDistance":0,"guiZoom":100,"RecognitionPatterns":{"Texts":[{"Text":"!","Patterns":[{"y":1,"Data":[3,18,16325542206742527]}]},{"Text":"\"","Patterns":[{"y":1,"Data":[7,5,34326184959]}]},{"Text":"#","Patterns":[{"y":1,"Data":[21,18,1730233282148184064,287684887449722892,432558372080782590,-9151450814992345085,-4503546425407192193,105553519117824]}]},{"Text":"$","Patterns":[{"y":1,"Data":[10,18,-4103278981860531728,1022826792737775416,273643088650183]}]},{"Text":"%","Patterns":[{"y":1,"Data":[16,18,4106163815056277566,137325641983386488,-8680719338870668825,2049171967118085937,1006657408]},{"y":0,"Data":[12,14,-7053536677925691362,-932582802203840509,481169521857]},{"y":0,"Data":[12,14,4483561862185410590,-6693201297471932665,515452713155]},{"y":1,"Data":[15,16,8079985718278946828,270224490505649185,-4174900503865950992,61574731646467]}]},{"Text":"&","Patterns":[{"y":1,"Data":[15,18,-2170735123539362692,-560559554484271135,-286244522801241887,3941197286469663,56]}]},{"Text":"'","Patterns":[{"y":1,"Data":[2,5,1023]}]},{"Text":"(","Patterns":[{"y":1,"Data":[5,22,-8796109668416,35184438149247]}]},{"Text":")","Patterns":[{"y":1,"Data":[5,22,-549488427005,1097368338403]},{"y":4,"Data":[3,14,272864638983]}]},{"Text":"*","Patterns":[{"y":1,"Data":[7,7,21318136116748]}]},{"Text":"+","Patterns":[{"y":8,"Data":[9,9,1010811825620545592,14364]}]},{"Text":",","Patterns":[{"y":17,"Data":[5,5,1310680]},{"y":12,"Data":[3,4,2044]}]},{"Text":"-","Patterns":[{"y":11,"Data":[6,3,262143]}]},{"Text":".","Patterns":[{"y":16,"Data":[3,3,511]},{"y":12,"Data":[2,2,15]}]},{"Text":"/","Patterns":[{"y":1,"Data":[12,18,17451508685733888,35466388239679614,31525729975795838,64]},{"y":0,"Data":[9,14,-2297396698093182976,281595267259905]},{"y":0,"Data":[9,13,2234876663345188864,1100451660024]},{"y":0,"Data":[8,14,-572096859246413824,51555340160]}]},{"Text":"0","Patterns":[{"y":1,"Data":[15,18,549439034279084016,-576322213305643144,35465982357528577,288214982963234748,1023]},{"y":0,"Data":[12,14,531453342862213312,-5185965275232861960,136935630595]},{"y":0,"Data":[13,16,-1150819108452032520,-2304787461407776761,4610696728277934087,8184]}]},{"Text":"1","Patterns":[{"y":1,"Data":[5,18,-68717903866,67108863]},{"y":0,"Data":[3,14,4398046494722]},{"y":0,"Data":[4,16,-131070]},{"y":0,"Data":[5,14,-144115188344258558,31]}]},{"Text":"2","Patterns":[{"y":1,"Data":[12,18,142989833631924238,-306105273587595272,2300811624938727297,14687800]},{"y":0,"Data":[9,14,276988695431673862,3465733197579215095]},{"y":0,"Data":[10,16,-575352410490806266,-2031150885676778493,3766280702]}]},{"Text":"3","Patterns":[{"y":1,"Data":[11,18,-2163917507132424185,-560559554484271136,-3474527130504666655,15]},{"y":0,"Data":[8,14,-4340609070631161853,137413182501360]},{"y":0,"Data":[10,16,-4502507245899620345,-33226378460797,1044152190]}]},{"Text":"4","Patterns":[{"y":1,"Data":[14,18,-2304734697466349568,-4357302029505535985,-139365245363745273,54043401703651391]},{"y":0,"Data":[11,14,4331267114076734976,4607463637696742278,4194688]},{"y":0,"Data":[13,16,2296870445095328768,2019613877842222320,1729663598741028835,4096]},{"y":0,"Data":[10,13,7053547462563727232,4620676722868667406,0]},{"y":0,"Data":[11,14,4326763239554679552,4607322899134579650,2099196]}]},{"Text":"5","Patterns":[{"y":1,"Data":[12,18,7059427591953679328,-569566788098881568,-1119148769023631135,2031631]},{"y":0,"Data":[9,14,7188183737201324287,504541764850036976]},{"y":0,"Data":[10,16,-4556586399423274498,-899627269675040573,1057193859]}]},{"Text":"6","Patterns":[{"y":1,"Data":[13,18,9088262965693546368,-568317737051243280,-572504694404685711,541174251551]},{"y":0,"Data":[10,14,7404405454224101344,2288078762587986160,480]},{"y":0,"Data":[12,16,-2243794301736697920,-2250743424589840178,864760949582651840]}]},{"Text":"7","Patterns":[{"y":1,"Data":[12,18,141863903660081159,-4327833965794162696,283731157457503217,960]},{"y":0,"Data":[9,14,-4360593020886654973,1970857541925063]},{"y":0,"Data":[11,16,-574244103575371769,71780409994067463,30066802751]},{"y":0,"Data":[10,14,-8937376417146945533,-4607462811190103857,0]}]},{"Text":"8","Patterns":[{"y":1,"Data":[13,18,-1018095025189749700,-560559554484271135,-528729742253855,1083346763679]},{"y":0,"Data":[11,14,-4340449831568833024,-5044098038478655248,15730671]},{"y":0,"Data":[13,16,-2022257527479334912,-4484527756880387641,4556657105958855111,3072]}]},{"Text":"9","Patterns":[{"y":1,"Data":[13,18,-4485444628543700488,-2566983514540603583,-873139651416196736,34226044803]},{"y":0,"Data":[10,14,-8951452811812437764,287700518790717689,62]},{"y":0,"Data":[12,16,4829833003767038204,4252368931551175427,27025978899177351]}]},{"Text":":","Patterns":[{"y":6,"Data":[3,13,481564883975]},{"y":4,"Data":[2,12,14712327]},{"y":5,"Data":[2,11,3153411]}]},{"Text":";","Patterns":[{"y":6,"Data":[5,16,4037468304070197248,2055]}]},{"Text":"<","Patterns":[{"y":7,"Data":[11,11,-1288660680781348752,126655199102223928]}]},{"Text":"=","Patterns":[{"y":9,"Data":[9,7,8351872316837001715]}]},{"Text":">","Patterns":[{"y":7,"Data":[11,11,-1288901282071298297,7885151801377648]}]},{"Text":"?","Patterns":[{"y":1,"Data":[11,18,-4469276791359668217,-4598052022172842009,558455115594203361,0]}]},{"Text":"@","Patterns":[{"y":1,"Data":[24,22,-139638043770944,1015949255508464,-222989876083621778,3571126657511528947,-3571245546502069492,-4357232883757245416,8950904744193352703,18012208076031744,508]}]},{"Text":"A","Patterns":[{"y":1,"Data":[19,18,17732987957411840,-4602749052621193153,-4327835838431952865,35747459213246209,1090719796170720,2097166]},{"y":1,"Data":[16,16,2287967153330118656,1010776774528467952,1143923067194377743,-4611422131408846976]}]},{"Text":"B","Patterns":[{"y":1,"Data":[14,18,144115188075855871,-562811414427727904,7997845516770074817,135215734493003772]}]},{"Text":"C","Patterns":[{"y":1,"Data":[14,18,544935288621768672,-576321113827570052,35465982357528577,1008840951279387128]},{"y":0,"Data":[11,13,-9192401818209025568,24773646711058439,24587]}]},{"Text":"D","Patterns":[{"y":1,"Data":[16,18,144115188075855871,-576322213309839392,35465982357528577,-8935157122074672196,133695487]}]},{"Text":"E","Patterns":[{"y":1,"Data":[13,18,-2161727821137838081,-560559554484271136,4070706641703002337,3848305435128]},{"y":0,"Data":[11,16,-2195504818343116801,-2195538319599214201,246324453171591]}]},{"Text":"F","Patterns":[{"y":1,"Data":[12,18,-2161727821137838081,-4595800213829744896,4066765976996610273,448]}]},{"Text":"G","Patterns":[{"y":1,"Data":[14,18,544935288621768672,-576321113827570052,35465982357528577,1148453072303817208]}]},{"Text":"H","Patterns":[{"y":1,"Data":[16,18,-2287828610704211969,15762658825568256,4035240659345473760,-4383014068224,4294967295]}]},{"Text":"I","Patterns":[{"y":1,"Data":[3,18,18014398509481983]}]},{"Text":"J","Patterns":[{"y":1,"Data":[7,18,15762658825568256,288217181978623856]}]},{"Text":"K","Patterns":[{"y":1,"Data":[17,18,18014398509481983,15762598695796736,-8952890114301754376,4539663471578187655,562953174677504]}]},{"Text":"L","Patterns":[{"y":1,"Data":[11,18,18014398509481983,4035240659345473760,3940664706392064,56]},{"y":0,"Data":[9,16,-2305561534236983297,-2305596714850918400,57344]},{"y":0,"Data":[10,16,-4611404543450807296,-4611474908973580288,3221274624]}]},{"Text":"M","Patterns":[{"y":1,"Data":[19,18,1152921504606846975,141863455907970048,4362879184674688,17733194124034110,-4293951457,4194303]},{"y":1,"Data":[17,16,16888636041592831,-576391482806631952,279257265985351680,-4293000968,32767]}]},{"Text":"N","Patterns":[{"y":1,"Data":[16,18,576460752303423487,4222132703739392,-4611549678859714320,-2267740766205,4294967295]}]},{"Text":"O","Patterns":[{"y":1,"Data":[17,18,544935288621768672,-576322213339197572,35465982357528577,-1765274989098958344,70301098381311]}]},{"Text":"P","Patterns":[{"y":1,"Data":[14,18,144115188075855871,-4584541274891090176,4391042742412050881,527774137778048]}]},{"Text":"Q","Patterns":[{"y":1,"Data":[17,22,1152851273268076512,-2305348503606935432,-9221386318381580176,8435455118803395,-5497524924182530,70300091806239]}]},{"Text":"R","Patterns":[{"y":1,"Data":[15,18,144115188075855871,-4580037675263719680,4391570508932907969,864941546506059743,8192]}]},{"Text":"S","Patterns":[{"y":1,"Data":[13,18,-2163911528271986180,-560559554484271136,-1117141061865053983,1091030729182]},{"y":1,"Data":[13,16,-2177665249145257968,-2196699421590953529,4541738951479910787,7680]},{"y":3,"Data":[9,12,4351539558966616088,8531888333766]}]},{"Text":"T","Patterns":[{"y":1,"Data":[13,18,126101270604546055,-67107072,31525317651202047,117440960]},{"y":0,"Data":[9,13,-549554462717,3298937602047]},{"y":1,"Data":[12,16,844437815230467,2251799813619715,844437815230467]},{"y":4,"Data":[9,11,72057585452189697,16785412]}]},{"Text":"U","Patterns":[{"y":1,"Data":[16,18,4503539497568255,4035240659349667964,3940664706392064,-864693464901615560,67094527]}]},{"Text":"V","Patterns":[{"y":1,"Data":[18,18,9187351967213289475,1148419000197183488,-9219009158072697344,-2296870857963749313,3377764146069519,0]},{"y":0,"Data":[16,16,142989833631891459,-1152644426611290144,283761688132515840,281539405349118]}]},{"Text":"W","Patterns":[{"y":1,"Data":[23,18,-285978644923547641,1134924148594442495,139615917841582048,2234209758348224,-4610564516032282370,-285979126106427377,4096]}]},{"Text":"X","Patterns":[{"y":1,"Data":[18,18,285979108914888705,274442371254468344,-144045918579062792,-594342142184309247,1970341480102912,8]}]},{"Text":"Y","Patterns":[{"y":1,"Data":[16,18,1116893738381869057,34902930398182400,4472072248118804416,8070586873770180096,16384]}]},{"Text":"Z","Patterns":[{"y":1,"Data":[13,18,143834260709539847,-542544975582459906,287669485667082481,3848557037560]}]},{"Text":"[","Patterns":[{"y":1,"Data":[6,22,-1,545357897400351,12]}]},{"Text":"\\","Patterns":[{"y":1,"Data":[12,18,2269816342500343809,141863523553769472,4362870594740096,8388664]}]},{"Text":"]","Patterns":[{"y":1,"Data":[6,22,136339474350087,-4194273,15]}]},{"Text":"^","Patterns":[{"y":1,"Data":[12,9,270464346063307008,8821925771295]}]},{"Text":"_","Patterns":[{"y":19,"Data":[12,3,68719476735]}]},{"Text":"`","Patterns":[{"y":1,"Data":[5,3,20441]}]},{"Text":"a","Patterns":[{"y":6,"Data":[11,13,-8773520101673996352,-13511472200486713,32755]},{"y":5,"Data":[10,12,4351539642671965120,72004810608894914]},{"y":4,"Data":[8,9,9201541476357498866,254]}]},{"Text":"b","Patterns":[{"y":1,"Data":[12,18,3476778912330022911,4036929515648245984,-285979109972975560,2080783]},{"y":0,"Data":[9,13,218451384737988606,1056076742799457]}]},{"Text":"c","Patterns":[{"y":6,"Data":[11,13,-2272189569753448352,-9188464878614939633,28703]}]},{"Text":"d","Patterns":[{"y":1,"Data":[11,18,4043737719489200000,4036929515648246000,-2132746184,31]},{"y":0,"Data":[9,13,-9003794678155574400,9006099710353505]}]},{"Text":"e","Patterns":[{"y":6,"Data":[11,13,-3585300985993509892,-6927398350325483065,29683]},{"y":4,"Data":[9,9,4963654244503518264,7375]},{"y":5,"Data":[11,12,3919106358481240160,8703184834156848070,0]}]},{"Text":"f","Patterns":[{"y":0,"Data":[9,19,-7061644490596417544,224054508811743233,100663520]},{"y":0,"Data":[5,13,229711622032064508,0]},{"y":0,"Data":[6,17,234187163443265528,207619632]}]},{"Text":"g","Patterns":[{"y":6,"Data":[12,17,-1135403539355663364,137079359490605180,-288230376152889402,255]},{"y":5,"Data":[11,16,-4105374115425419168,-1872435300412439033,70362301691655]}]},{"Text":"h","Patterns":[{"y":1,"Data":[12,18,3476778912330022911,1688856302764032,-283727326265475048,16769087]}]},{"Text":"i","Patterns":[{"y":1,"Data":[3,18,18012749235748839]},{"y":1,"Data":[3,16,140677358026739]},{"y":0,"Data":[2,13,67010546]},{"y":1,"Data":[2,16,4294180851]}]},{"Text":"j","Patterns":[{"y":1,"Data":[4,22,-422212566777856,8388511]}]},{"Text":"k","Patterns":[{"y":1,"Data":[13,18,3476778912330022911,217861638416556032,-139766061361783272,2199035965496]},{"y":1,"Data":[11,16,27303072740933631,8948683452206547040,215370730370672]}]},{"Text":"l","Patterns":[{"y":1,"Data":[3,18,18014398509481983]},{"y":1,"Data":[2,16,4294967295]}]},{"Text":"m","Patterns":[{"y":6,"Data":[19,13,31529045615181823,-1098572054522,54049794477490171,36024398972387384]},{"y":7,"Data":[12,8,107803820880396031,4278124801]}]},{"Text":"n","Patterns":[{"y":6,"Data":[12,13,27025445987811327,-8999502270644218,268337147]},{"y":7,"Data":[8,8,-72337965189759223]}]},{"Text":"o","Patterns":[{"y":6,"Data":[12,13,-4594230461768678404,-1117240732616697,33300473]},{"y":4,"Data":[9,9,7057263864975326460,31871]}]},{"Text":"p","Patterns":[{"y":6,"Data":[12,17,6926536226895822847,254172743642234928,-4602687477891856626,31]},{"y":5,"Data":[11,16,433330726646054910,506107431554845699,412383709182]},{"y":7,"Data":[8,11,2417326350311358463,229884]}]},{"Text":"q","Patterns":[{"y":6,"Data":[12,17,-2290013906707675140,110057555566379120,-32766194,4095]}]},{"Text":"r","Patterns":[{"y":6,"Data":[6,13,31533443661692927,6]},{"y":4,"Data":[5,9,69122916351]},{"y":4,"Data":[4,9,403439615]}]},{"Text":"s","Patterns":[{"y":6,"Data":[10,13,-3585302962172334978,-508933149943072313,1]},{"y":5,"Data":[10,12,4351539911567073304,16932358779069382]}]},{"Text":"t","Patterns":[{"y":4,"Data":[6,15,-3602422308280483841,58746624]},{"y":3,"Data":[5,14,918791497648693247,48]}]},{"Text":"u","Patterns":[{"y":6,"Data":[12,13,-4607744819031186433,-7317937027270655,268435455]},{"y":5,"Data":[10,12,864902294825596927,72057591889789024]}]},{"Text":"v","Patterns":[{"y":6,"Data":[13,13,-143554428622610429,2297954004820311553,268664956]}]},{"Text":"w","Patterns":[{"y":6,"Data":[19,13,-1148422234373103613,135177291909578241,-9205919497360375556,4414723063783]}]},{"Text":"x","Patterns":[{"y":6,"Data":[13,13,9207485709806497793,-4472182045208214544,1099981451295]}]},{"Text":"y","Patterns":[{"y":6,"Data":[13,17,2297963900303179779,-2296976410543129076,4035361614088894479,4096]},{"y":5,"Data":[12,16,-2018526881273413629,283761412197613536,281505045610748]}]},{"Text":"z","Patterns":[{"y":6,"Data":[10,13,-2431976792454562813,-9152422883697427993,3]}]},{"Text":"{","Patterns":[{"y":1,"Data":[7,22,1150669737005423616,1125779647750136,30]}]},{"Text":"|","Patterns":[{"y":1,"Data":[3,22,-1,3]}]},{"Text":"}","Patterns":[{"y":1,"Data":[7,22,-126105187583524863,1116901503563456511,114688]}]},{"Text":"~","Patterns":[{"y":11,"Data":[9,3,131856091]}]},{"Text":"♂","Patterns":[{"y":0,"Data":[27,23,-1123701151957248,284835151957982979,1143914579693173728,-576458621999386624,30786333442048,2111062576988190,142989305080447968,-4499238087823872,-8070451356881715709,133156700131]}]},{"Text":"♀","Patterns":[{"y":0,"Data":[29,23,1152851170214019580,-2303573626071285792,2216615573716999,1292533238815785952,-144106409162115072,-4611405093173002237,5048957996630143,8866462806575228,-9151350718244714528,144080072419065855,8128]}]}],"TrainingSettings":{"IsTrainingEnabled":false,"SkipName":false,"SkipTribe":false,"SkipOwner":false}},"labelRectangles":["1294, 679, 195, 18","1294, 736, 195, 18","1294, 793, 195, 18","1294, 851, 195, 18","1294, 908, 195, 18","1294, 965, 195, 18","1294, 1023, 195, 18","1294, 1080, 195, 18","1294, 1137, 195, 18","1166, 265, 231, 20","1125, 218, 308, 23","1179, 311, 216, 18","1212, 357, 150, 18"]} \ No newline at end of file +{"Version":"2.0","description":null,"resize":1.0,"resolutionWidth":2560,"resolutionHeight":1440,"statDistance":0,"guiZoom":100,"RecognitionPatterns":{"Texts":[{"Text":"!","Patterns":[{"y":1,"Data":[3,18,16325542206742527]}]},{"Text":"\"","Patterns":[{"y":1,"Data":[7,5,34326184959]}]},{"Text":"#","Patterns":[{"y":1,"Data":[21,18,1730233282148184064,287684887449722892,432558372080782590,-9151450814992345085,-4503546425407192193,105553519117824]}]},{"Text":"$","Patterns":[{"y":1,"Data":[10,18,-4103278981860531728,1022826792737775416,273643088650183]}]},{"Text":"%","Patterns":[{"y":1,"Data":[16,18,4106163815056277566,137325641983386488,-8680719338870668825,2049171967118085937,1006657408]},{"y":0,"Data":[12,14,-7053536677925691362,-932582802203840509,481169521857]},{"y":0,"Data":[12,14,4483561862185410590,-6693201297471932665,515452713155]},{"y":1,"Data":[15,16,8079985718278946828,270224490505649185,-4174900503865950992,61574731646467]}]},{"Text":"&","Patterns":[{"y":1,"Data":[15,18,-2170735123539362692,-560559554484271135,-286244522801241887,3941197286469663,56]}]},{"Text":"'","Patterns":[{"y":1,"Data":[2,5,1023]}]},{"Text":"(","Patterns":[{"y":1,"Data":[5,22,-8796109668416,35184438149247]}]},{"Text":")","Patterns":[{"y":1,"Data":[5,22,-549488427005,1097368338403]},{"y":4,"Data":[3,14,272864638983]}]},{"Text":"*","Patterns":[{"y":1,"Data":[7,7,21318136116748]}]},{"Text":"+","Patterns":[{"y":8,"Data":[9,9,1010811825620545592,14364]}]},{"Text":",","Patterns":[{"y":17,"Data":[5,5,1310680]},{"y":12,"Data":[3,4,2044]}]},{"Text":"-","Patterns":[{"y":11,"Data":[6,3,262143]}]},{"Text":".","Patterns":[{"y":16,"Data":[3,3,511]},{"y":12,"Data":[2,2,15]},{"y":12,"Data":[2,1,3]}]},{"Text":"/","Patterns":[{"y":1,"Data":[12,18,17451508685733888,35466388239679614,31525729975795838,64]},{"y":0,"Data":[9,14,-2297396698093182976,281595267259905]},{"y":0,"Data":[9,13,2234876663345188864,1100451660024]},{"y":0,"Data":[8,14,-572096859246413824,51555340160]}]},{"Text":"0","Patterns":[{"y":1,"Data":[15,18,549439034279084016,-576322213305643144,35465982357528577,288214982963234748,1023]},{"y":0,"Data":[12,14,531453342862213312,-5185965275232861960,136935630595]},{"y":0,"Data":[13,16,-1150819108452032520,-2304787461407776761,4610696728277934087,8184]}]},{"Text":"1","Patterns":[{"y":1,"Data":[5,18,-68717903866,67108863]},{"y":0,"Data":[3,14,4398046494722]},{"y":0,"Data":[4,16,-131070]},{"y":0,"Data":[5,14,-144115188344258558,31]}]},{"Text":"2","Patterns":[{"y":1,"Data":[12,18,142989833631924238,-306105273587595272,2300811624938727297,14687800]},{"y":0,"Data":[9,14,276988695431673862,3465733197579215095]},{"y":0,"Data":[10,16,-575352410490806266,-2031150885676778493,3766280702]}]},{"Text":"3","Patterns":[{"y":1,"Data":[11,18,-2163917507132424185,-560559554484271136,-3474527130504666655,15]},{"y":0,"Data":[8,14,-4340609070631161853,137413182501360]},{"y":0,"Data":[10,16,-4502507245899620345,-33226378460797,1044152190]}]},{"Text":"4","Patterns":[{"y":1,"Data":[14,18,-2304734697466349568,-4357302029505535985,-139365245363745273,54043401703651391]},{"y":0,"Data":[11,14,4331267114076734976,4607463637696742278,4194688]},{"y":0,"Data":[13,16,2296870445095328768,2019613877842222320,1729663598741028835,4096]},{"y":0,"Data":[10,13,7053547462563727232,4620676722868667406,0]},{"y":0,"Data":[11,14,4326763239554679552,4607322899134579650,2099196]}]},{"Text":"5","Patterns":[{"y":1,"Data":[12,18,7059427591953679328,-569566788098881568,-1119148769023631135,2031631]},{"y":0,"Data":[9,14,7188183737201324287,504541764850036976]},{"y":0,"Data":[10,16,-4556586399423274498,-899627269675040573,1057193859]},{"y":0,"Data":[9,13,439154572344160256,4365052808814787]}]},{"Text":"6","Patterns":[{"y":1,"Data":[13,18,9088262965693546368,-568317737051243280,-572504694404685711,541174251551]},{"y":0,"Data":[10,14,7404405454224101344,2288078762587986160,480]},{"y":0,"Data":[12,16,-2243794301736697920,-2250743424589840178,864760949582651840]}]},{"Text":"7","Patterns":[{"y":1,"Data":[12,18,141863903660081159,-4327833965794162696,283731157457503217,960]},{"y":0,"Data":[9,14,-4360593020886654973,1970857541925063]},{"y":0,"Data":[11,16,-574244103575371769,71780409994067463,30066802751]},{"y":0,"Data":[10,14,-8937376417146945533,-4607462811190103857,0]},{"y":1,"Data":[10,13,8655637970969174017,9014899998868418,0]}]},{"Text":"8","Patterns":[{"y":1,"Data":[13,18,-1018095025189749700,-560559554484271135,-528729742253855,1083346763679]},{"y":0,"Data":[11,14,-4340449831568833024,-5044098038478655248,15730671]},{"y":0,"Data":[13,16,-2022257527479334912,-4484527756880387641,4556657105958855111,3072]}]},{"Text":"9","Patterns":[{"y":1,"Data":[13,18,-4485444628543700488,-2566983514540603583,-873139651416196736,34226044803]},{"y":0,"Data":[10,14,-8951452811812437764,287700518790717689,62]},{"y":0,"Data":[12,16,4829833003767038204,4252368931551175427,27025978899177351]}]},{"Text":":","Patterns":[{"y":6,"Data":[3,13,481564883975]},{"y":4,"Data":[2,12,14712327]},{"y":5,"Data":[2,11,3153411]}]},{"Text":";","Patterns":[{"y":6,"Data":[5,16,4037468304070197248,2055]}]},{"Text":"<","Patterns":[{"y":7,"Data":[11,11,-1288660680781348752,126655199102223928]}]},{"Text":"=","Patterns":[{"y":9,"Data":[9,7,8351872316837001715]}]},{"Text":">","Patterns":[{"y":7,"Data":[11,11,-1288901282071298297,7885151801377648]}]},{"Text":"?","Patterns":[{"y":1,"Data":[11,18,-4469276791359668217,-4598052022172842009,558455115594203361,0]}]},{"Text":"@","Patterns":[{"y":1,"Data":[24,22,-139638043770944,1015949255508464,-222989876083621778,3571126657511528947,-3571245546502069492,-4357232883757245416,8950904744193352703,18012208076031744,508]}]},{"Text":"A","Patterns":[{"y":1,"Data":[19,18,17732987957411840,-4602749052621193153,-4327835838431952865,35747459213246209,1090719796170720,2097166]},{"y":1,"Data":[16,16,2287967153330118656,1010776774528467952,1143923067194377743,-4611422131408846976]}]},{"Text":"B","Patterns":[{"y":1,"Data":[14,18,144115188075855871,-562811414427727904,7997845516770074817,135215734493003772]},{"y":1,"Data":[12,16,-2304717109306851329,-2178649838201872381,4475592036103184835]}]},{"Text":"C","Patterns":[{"y":1,"Data":[14,18,544935288621768672,-576321113827570052,35465982357528577,1008840951279387128]},{"y":0,"Data":[11,13,-9192401818209025568,24773646711058439,24587]}]},{"Text":"D","Patterns":[{"y":1,"Data":[16,18,144115188075855871,-576322213309839392,35465982357528577,-8935157122074672196,133695487]}]},{"Text":"E","Patterns":[{"y":1,"Data":[13,18,-2161727821137838081,-560559554484271136,4070706641703002337,3848305435128]},{"y":0,"Data":[11,16,-2195504818343116801,-2195538319599214201,246324453171591]}]},{"Text":"F","Patterns":[{"y":1,"Data":[12,18,-2161727821137838081,-4595800213829744896,4066765976996610273,448]}]},{"Text":"G","Patterns":[{"y":1,"Data":[14,18,544935288621768672,-576321113827570052,35465982357528577,1148453072303817208]}]},{"Text":"H","Patterns":[{"y":1,"Data":[16,18,-2287828610704211969,15762658825568256,4035240659345473760,-4383014068224,4294967295]}]},{"Text":"I","Patterns":[{"y":1,"Data":[3,18,18014398509481983]}]},{"Text":"J","Patterns":[{"y":1,"Data":[7,18,15762658825568256,288217181978623856]}]},{"Text":"K","Patterns":[{"y":1,"Data":[17,18,18014398509481983,15762598695796736,-8952890114301754376,4539663471578187655,562953174677504]}]},{"Text":"L","Patterns":[{"y":1,"Data":[11,18,18014398509481983,4035240659345473760,3940664706392064,56]},{"y":0,"Data":[9,16,-2305561534236983297,-2305596714850918400,57344]},{"y":0,"Data":[10,16,-4611404543450807296,-4611474908973580288,3221274624]}]},{"Text":"M","Patterns":[{"y":1,"Data":[19,18,1152921504606846975,141863455907970048,4362879184674688,17733194124034110,-4293951457,4194303]},{"y":1,"Data":[17,16,16888636041592831,-576391482806631952,279257265985351680,-4293000968,32767]}]},{"Text":"N","Patterns":[{"y":1,"Data":[16,18,576460752303423487,4222132703739392,-4611549678859714320,-2267740766205,4294967295]}]},{"Text":"O","Patterns":[{"y":1,"Data":[17,18,544935288621768672,-576322213339197572,35465982357528577,-1765274989098958344,70301098381311]}]},{"Text":"P","Patterns":[{"y":1,"Data":[14,18,144115188075855871,-4584541274891090176,4391042742412050881,527774137778048]}]},{"Text":"Q","Patterns":[{"y":1,"Data":[17,22,1152851273268076512,-2305348503606935432,-9221386318381580176,8435455118803395,-5497524924182530,70300091806239]}]},{"Text":"R","Patterns":[{"y":1,"Data":[15,18,144115188075855871,-4580037675263719680,4391570508932907969,864941546506059743,8192]},{"y":1,"Data":[13,16,1125899906842623,1117745391757099011,-4594533093838209597,32768]},{"y":1,"Data":[12,16,844442110001151,2288681294915371267,-4611439184761176857]},{"y":1,"Data":[12,16,844442110001151,2270666896405889027,-4604683785185837881]}]},{"Text":"S","Patterns":[{"y":1,"Data":[13,18,-2163911528271986180,-560559554484271136,-1117141061865053983,1091030729182]},{"y":1,"Data":[13,16,-2177665249145257968,-2196699421590953529,4541738951479910787,7680]},{"y":3,"Data":[9,12,4351539558966616088,8531888333766]}]},{"Text":"T","Patterns":[{"y":1,"Data":[13,18,126101270604546055,-67107072,31525317651202047,117440960]},{"y":0,"Data":[9,13,-549554462717,3298937602047]},{"y":1,"Data":[12,16,844437815230467,2251799813619715,844437815230467]},{"y":4,"Data":[9,11,72057585452189697,16785412]},{"y":0,"Data":[9,13,-7146624229373,2199291740167]}]},{"Text":"U","Patterns":[{"y":1,"Data":[16,18,4503539497568255,4035240659349667964,3940664706392064,-864693464901615560,67094527]}]},{"Text":"V","Patterns":[{"y":1,"Data":[18,18,9187351967213289475,1148419000197183488,-9219009158072697344,-2296870857963749313,3377764146069519,0]},{"y":0,"Data":[16,16,142989833631891459,-1152644426611290144,283761688132515840,281539405349118]}]},{"Text":"W","Patterns":[{"y":1,"Data":[23,18,-285978644923547641,1134924148594442495,139615917841582048,2234209758348224,-4610564516032282370,-285979126106427377,4096]}]},{"Text":"X","Patterns":[{"y":1,"Data":[18,18,285979108914888705,274442371254468344,-144045918579062792,-594342142184309247,1970341480102912,8]}]},{"Text":"Y","Patterns":[{"y":1,"Data":[16,18,1116893738381869057,34902930398182400,4472072248118804416,8070586873770180096,16384]}]},{"Text":"Z","Patterns":[{"y":1,"Data":[13,18,143834260709539847,-542544975582459906,287669485667082481,3848557037560]}]},{"Text":"[","Patterns":[{"y":1,"Data":[6,22,-1,545357897400351,12]}]},{"Text":"\\","Patterns":[{"y":1,"Data":[12,18,2269816342500343809,141863523553769472,4362870594740096,8388664]}]},{"Text":"]","Patterns":[{"y":1,"Data":[6,22,136339474350087,-4194273,15]}]},{"Text":"^","Patterns":[{"y":1,"Data":[12,9,270464346063307008,8821925771295]}]},{"Text":"_","Patterns":[{"y":19,"Data":[12,3,68719476735]},{"y":17,"Data":[10,2,1048575]}]},{"Text":"`","Patterns":[{"y":1,"Data":[5,3,20441]}]},{"Text":"a","Patterns":[{"y":6,"Data":[11,13,-8773520101673996352,-13511472200486713,32755]},{"y":5,"Data":[10,12,4351539642671965120,72004810608894914]},{"y":4,"Data":[8,9,9201541476357498866,254]}]},{"Text":"b","Patterns":[{"y":1,"Data":[12,18,3476778912330022911,4036929515648245984,-285979109972975560,2080783]},{"y":0,"Data":[9,13,218451384737988606,1056076742799457]}]},{"Text":"c","Patterns":[{"y":6,"Data":[11,13,-2272189569753448352,-9188464878614939633,28703]}]},{"Text":"d","Patterns":[{"y":1,"Data":[11,18,4043737719489200000,4036929515648246000,-2132746184,31]},{"y":0,"Data":[9,13,-9003794678155574400,9006099710353505]}]},{"Text":"e","Patterns":[{"y":6,"Data":[11,13,-3585300985993509892,-6927398350325483065,29683]},{"y":4,"Data":[9,9,4963654244503518264,7375]},{"y":5,"Data":[11,12,3919106358481240160,8703184834156848070,0]}]},{"Text":"f","Patterns":[{"y":0,"Data":[9,19,-7061644490596417544,224054508811743233,100663520]},{"y":0,"Data":[5,13,229711622032064508,0]},{"y":0,"Data":[6,17,234187163443265528,207619632]}]},{"Text":"g","Patterns":[{"y":6,"Data":[12,17,-1135403539355663364,137079359490605180,-288230376152889402,255]},{"y":5,"Data":[11,16,-4105374115425419168,-1872435300412439033,70362301691655]}]},{"Text":"h","Patterns":[{"y":1,"Data":[12,18,3476778912330022911,1688856302764032,-283727326265475048,16769087]}]},{"Text":"i","Patterns":[{"y":1,"Data":[3,18,18012749235748839]},{"y":1,"Data":[3,16,140677358026739]},{"y":0,"Data":[2,13,67010546]},{"y":1,"Data":[2,16,4294180851]}]},{"Text":"j","Patterns":[{"y":1,"Data":[4,22,-422212566777856,8388511]}]},{"Text":"k","Patterns":[{"y":1,"Data":[13,18,3476778912330022911,217861638416556032,-139766061361783272,2199035965496]},{"y":1,"Data":[11,16,27303072740933631,8948683452206547040,215370730370672]}]},{"Text":"l","Patterns":[{"y":1,"Data":[3,18,18014398509481983]},{"y":1,"Data":[2,16,4294967295]}]},{"Text":"m","Patterns":[{"y":6,"Data":[19,13,31529045615181823,-1098572054522,54049794477490171,36024398972387384]},{"y":7,"Data":[12,8,107803820880396031,4278124801]},{"y":5,"Data":[17,12,3459327807354566655,504350373133157120,-8999501867843488,4094]}]},{"Text":"n","Patterns":[{"y":6,"Data":[12,13,27025445987811327,-8999502270644218,268337147]},{"y":7,"Data":[8,8,-72337965189759223]}]},{"Text":"o","Patterns":[{"y":6,"Data":[12,13,-4594230461768678404,-1117240732616697,33300473]},{"y":4,"Data":[9,9,7057263864975326460,31871]},{"y":5,"Data":[11,12,4324406131666445308,-558472749044071488,1]}]},{"Text":"p","Patterns":[{"y":6,"Data":[12,17,6926536226895822847,254172743642234928,-4602687477891856626,31]},{"y":5,"Data":[11,16,433330726646054910,506107431554845699,412383709182]},{"y":7,"Data":[8,11,2417326350311358463,229884]}]},{"Text":"q","Patterns":[{"y":6,"Data":[12,17,-2290013906707675140,110057555566379120,-32766194,4095]}]},{"Text":"r","Patterns":[{"y":6,"Data":[6,13,31533443661692927,6]},{"y":4,"Data":[5,9,69122916351]},{"y":4,"Data":[4,9,403439615]}]},{"Text":"s","Patterns":[{"y":6,"Data":[10,13,-3585302962172334978,-508933149943072313,1]},{"y":5,"Data":[10,12,4351539911567073304,16932358779069382]}]},{"Text":"t","Patterns":[{"y":4,"Data":[6,15,-3602422308280483841,58746624]},{"y":3,"Data":[5,14,918791497648693247,48]}]},{"Text":"u","Patterns":[{"y":6,"Data":[12,13,-4607744819031186433,-7317937027270655,268435455]},{"y":5,"Data":[10,12,864902294825596927,72057591889789024]}]},{"Text":"v","Patterns":[{"y":6,"Data":[13,13,-143554428622610429,2297954004820311553,268664956]}]},{"Text":"w","Patterns":[{"y":6,"Data":[19,13,-1148422234373103613,135177291909578241,-9205919497360375556,4414723063783]}]},{"Text":"x","Patterns":[{"y":6,"Data":[13,13,9207485709806497793,-4472182045208214544,1099981451295]}]},{"Text":"y","Patterns":[{"y":6,"Data":[13,17,2297963900303179779,-2296976410543129076,4035361614088894479,4096]},{"y":5,"Data":[12,16,-2018526881273413629,283761412197613536,281505045610748]}]},{"Text":"z","Patterns":[{"y":6,"Data":[10,13,-2431976792454562813,-9152422883697427993,3]}]},{"Text":"{","Patterns":[{"y":1,"Data":[7,22,1150669737005423616,1125779647750136,30]}]},{"Text":"|","Patterns":[{"y":1,"Data":[3,22,-1,3]}]},{"Text":"}","Patterns":[{"y":1,"Data":[7,22,-126105187583524863,1116901503563456511,114688]}]},{"Text":"~","Patterns":[{"y":11,"Data":[9,3,131856091]}]},{"Text":"♂","Patterns":[{"y":0,"Data":[27,23,-1123701151957248,284835151957982979,1143914579693173728,-576458621999386624,30786333442048,2111062576988190,142989305080447968,-4499238087823872,-8070451356881715709,133156700131]}]},{"Text":"♀","Patterns":[{"y":0,"Data":[29,23,1152851170214019580,-2303573626071285792,2216615573716999,1292533238815785952,-144106409162115072,-4611405093173002237,5048957996630143,8866462806575228,-9151350718244714528,144080072419065855,8128]}]}],"TrainingSettings":{"IsTrainingEnabled":false,"SkipName":false,"SkipTribe":false,"SkipOwner":false}},"LabelRectangles":{"default":["1294, 679, 195, 18","1294, 736, 195, 18","1294, 793, 195, 18","1294, 851, 195, 18","1294, 908, 195, 18","1375, 965, 114, 18","1375, 1023, 114, 18","1294, 1080, 195, 18","1294, 1137, 195, 18","1166, 265, 231, 20","1125, 218, 308, 23","1179, 311, 216, 18","1212, 357, 150, 18"]},"SelectedLabelSetName":"default"} \ No newline at end of file diff --git a/ARKBreedingStats/json/values/_manifest.json b/ARKBreedingStats/json/values/_manifest.json index 693318b24..21f4bd4b9 100644 --- a/ARKBreedingStats/json/values/_manifest.json +++ b/ARKBreedingStats/json/values/_manifest.json @@ -67,7 +67,7 @@ "mod": { "id": "1356703358", "tag": "Primal_Fear_Noxious_Creatures", "title": "Primal Fear Noxious Creatures" } }, "1373744537-AC2.json": { - "version": "358.17.1700355462", + "version": "358.17.1705110964", "mod": { "id": "1373744537", "tag": "AC2", "title": "Additional Creatures 2: Wild Ark" } }, "1379111008-RealismPlus.json": { @@ -242,7 +242,7 @@ "mod": { "id": "1934081600", "tag": "SoloFarmAnky", "title": "Solo Farm Mod" } }, "1979037318-IceWyverns.json": { - "version": "358.17.1696373342", + "version": "358.17.1705110815", "mod": { "id": "1979037318", "tag": "IceWyverns", "title": "Shads Critter Reworks" } }, "1984129536-MTSMod.json": { @@ -258,7 +258,7 @@ "mod": { "id": "2000326197", "tag": "ExtraResources", "title": "Event Assets" } }, "2003934830-Beasts.json": { - "version": "358.17.1699137788", + "version": "358.17.1705183647", "mod": { "id": "2003934830", "tag": "Beasts", "title": "Prehistoric Beasts" } }, "2019846325-ApexMod.json": { @@ -310,7 +310,7 @@ "mod": { "id": "2362246280", "tag": "GigaFullTame", "title": "Giga Full Tame" } }, "2447186973-ArkOmega.json": { - "version": "358.17.1701673974", + "version": "358.17.1705727328", "mod": { "id": "2447186973", "tag": "ArkOmega", "title": "Ark Omega" } }, "2453342929-MoreDragonsMod.json": { diff --git a/ARKBreedingStats/library/Creature.cs b/ARKBreedingStats/library/Creature.cs index 070070897..b06215bbe 100644 --- a/ARKBreedingStats/library/Creature.cs +++ b/ARKBreedingStats/library/Creature.cs @@ -42,15 +42,43 @@ public class Creature : IEquatable public double[] valuesBreeding; public double[] valuesDom; + /// - /// Indices of stats that are top for that species in the creatureCollection + /// Set a stat index to a top stat or not for that species in the creatureCollection. /// - public bool[] topBreedingStats; - public short topStatsCount; + public void SetTopStat(int statIndex, bool isTopStat) => + _topBreedingStatIndices = (isTopStat ? _topBreedingStatIndices | (1 << statIndex) : _topBreedingStatIndices & ~(1 << statIndex)); + /// - /// topStatCount with all stats (regardless of considerStatHighlight[]) and without torpor (for breedingPlanner) + /// Returns if a stat index is a top stat for that species in the creatureCollection. /// - public short topStatsCountBP; + public bool IsTopStat(int statIndex) => (_topBreedingStatIndices & (1 << statIndex)) != 0; + + public void ResetTopStats() => _topBreedingStatIndices = 0; + private int _topBreedingStatIndices; // bit flags if a stat index is a top stat + + /// + /// Number of top stats that are considered in the library. + /// + public byte topStatsConsideredCount; + + /// + /// Set a stat index to a top mutation stat or not for that species in the creatureCollection. + /// + public void SetTopMutationStat(int statIndex, bool isTopMutationStat) => + _topMutationStatIndices = (isTopMutationStat ? _topMutationStatIndices | (1 << statIndex) : _topMutationStatIndices & ~(1 << statIndex)); + + /// + /// Returns if a stat index is a top mutation stat for that species in the creatureCollection. + /// + public bool IsTopMutationStat(int statIndex) => (_topMutationStatIndices & (1 << statIndex)) != 0; + public void ResetTopMutationStats() => _topMutationStatIndices = 0; + private int _topMutationStatIndices; // bit flags if a stat index is a top mutation stat + + /// + /// topStatCount with all stats (regardless of considerStatHighlight[]) and without torpor (for breeding planner) + /// + public byte topStatsCountBP; /// /// True if it has some topBreedingStats and if it's male, no other male has more topBreedingStats. /// @@ -391,6 +419,7 @@ public Creature Mother motherGuid = mother?.guid ?? Guid.Empty; } } + public Creature Father { get => father; @@ -412,13 +441,11 @@ public void SetTopStatCount(bool[] considerStatHighlight, bool considerWastedSta || flags.HasFlag(CreatureFlags.Placeholder)) return; - if (topBreedingStats == null) topBreedingStats = new bool[Stats.StatsCount]; - - short c = 0, cBP = 0; + byte c = 0, cBP = 0; onlyTopConsideredStats = true; for (int s = 0; s < Stats.StatsCount; s++) { - if (topBreedingStats[s]) + if (IsTopStat(s)) { if (s != Stats.Torpidity) cBP++; @@ -430,7 +457,7 @@ public void SetTopStatCount(bool[] considerStatHighlight, bool considerWastedSta onlyTopConsideredStats = false; } } - topStatsCount = c; + topStatsConsideredCount = c; topStatsCountBP = cBP; } @@ -558,7 +585,6 @@ private void InitializeArrays() if (levelsDom == null) levelsDom = new int[Stats.StatsCount]; if (valuesBreeding == null) valuesBreeding = new double[Stats.StatsCount]; if (valuesDom == null) valuesDom = new double[Stats.StatsCount]; - if (topBreedingStats == null) topBreedingStats = new bool[Stats.StatsCount]; } /// diff --git a/ARKBreedingStats/library/CreatureCollection.cs b/ARKBreedingStats/library/CreatureCollection.cs index f7ef4908d..4ec8be9b5 100644 --- a/ARKBreedingStats/library/CreatureCollection.cs +++ b/ARKBreedingStats/library/CreatureCollection.cs @@ -620,6 +620,7 @@ public string Game switch (value) { case Ark.Asa: + Ark.SetUndefinedColorId(true); if (modIDs == null) modIDs = new List(); if (!modIDs.Contains(Ark.Asa)) { @@ -629,6 +630,7 @@ public string Game break; default: // non ASA + Ark.SetUndefinedColorId(false); if (modIDs == null) return; ModList.RemoveAll(m => m.id == Ark.Asa); if (modIDs.Remove(Ark.Asa)) diff --git a/ARKBreedingStats/library/CreatureInfoGraphic.cs b/ARKBreedingStats/library/CreatureInfoGraphic.cs index 8766a3b2b..25aa16e7e 100644 --- a/ARKBreedingStats/library/CreatureInfoGraphic.cs +++ b/ARKBreedingStats/library/CreatureInfoGraphic.cs @@ -126,7 +126,7 @@ public static Bitmap InfoGraphic(this Creature creature, CreatureCollection cc, // levels double meanLetterWidth = fontSize * 7d / 10; int xStatName = (int)meanLetterWidth; - var displayMutatedLevels = creature.levelsMutated != null; + var displayMutatedLevels = creature.levelsMutated != null && cc?.Game == Ark.Asa; // x position of level number. torpor is the largest level number. int xRightLevelValue = (int)(xStatName + ((displayWithDomLevels ? 6 : 5) + creature.levelsWild[Stats.Torpidity].ToString().Length) * meanLetterWidth); int xRightLevelMutValue = xRightLevelValue + (!displayMutatedLevels ? 0 : (int)((creature.levelsMutated.Max().ToString().Length + 3) * meanLetterWidth)); @@ -342,7 +342,7 @@ private static int MaxCharLength(double[] values) /// /// /// CreatureCollection for server settings. - public static void ExportInfoGraphicToClipboard(this Creature creature, CreatureCollection cc = null) + public static void ExportInfoGraphicToClipboard(this Creature creature, CreatureCollection cc) { if (creature == null) return; diff --git a/ARKBreedingStats/library/DummyCreatures.cs b/ARKBreedingStats/library/DummyCreatures.cs index 52d7323cd..ecae6f389 100644 --- a/ARKBreedingStats/library/DummyCreatures.cs +++ b/ARKBreedingStats/library/DummyCreatures.cs @@ -244,7 +244,7 @@ private static List BreedCreatures(Creature[] creatures, Species speci var allCreaturesArray = noGender ? allCreatures.ToArray() : null; var pairs = BreedingScore.CalculateBreedingScores(noGender ? allCreaturesArray : femalesMales[Sex.Female].ToArray(), noGender ? allCreaturesArray : femalesMales[Sex.Male].ToArray(), species, bestPossibleLevels, statWeights, bestLevels, - BreedingPlan.BreedingMode.TopStatsConservative, false, false, 0, ref filteredOutByMutationLimit); + BreedingScore.BreedingMode.TopStatsConservative, false, false, 0, ref filteredOutByMutationLimit); var pairsCount = Math.Min(usePairsPerGeneration, pairs.Count); for (int i = 0; i < pairsCount; i++) diff --git a/ARKBreedingStats/library/LevelStatusFlags.cs b/ARKBreedingStats/library/LevelStatusFlags.cs new file mode 100644 index 000000000..72b45e315 --- /dev/null +++ b/ARKBreedingStats/library/LevelStatusFlags.cs @@ -0,0 +1,161 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ARKBreedingStats.species; +using ARKBreedingStats.uiControls; + +namespace ARKBreedingStats.library +{ + /// + /// Level status flags of the current extracted or to be added creature. + /// E.g. if a level is a new top stat or has a new mutations. + /// + public static class LevelStatusFlags + { + /// + /// The level status of the currently to be added creature. + /// + public static readonly LevelStatus[] LevelStatusFlagsCurrentNewCreature = new LevelStatus[Stats.StatsCount]; + public static LevelStatus CombinedLevelStatusFlags; + + /// + /// Determines if the wild and mutated levels of a creature are equal or higher than the current top levels of that species. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Adds text for each stat + public static void DetermineLevelStatus(Species species, int[] highSpeciesLevels, int[] lowSpeciesLevels, int[] highSpeciesMutationLevels, + (double[], byte[]) statWeights, int[] levelsWild, int[] levelsMutated, double[] valuesBreeding, + out List topStatsText, out List newTopStatsText, StringBuilder sbStatInfoText = null) + { + // if there are no creatures of the species yet, assume 0 levels to be the current best and worst + if (highSpeciesLevels == null) highSpeciesLevels = new int[Stats.StatsCount]; + if (lowSpeciesLevels == null) lowSpeciesLevels = new int[Stats.StatsCount]; + if (highSpeciesMutationLevels == null) highSpeciesMutationLevels = new int[Stats.StatsCount]; + + newTopStatsText = new List(); + topStatsText = new List(); + + foreach (var s in Stats.DisplayOrder) + { + LevelStatusFlagsCurrentNewCreature[s] = LevelStatus.Neutral; + + if (s == Stats.Torpidity + || levelsWild[s] < 0 + || !species.UsesStat(s)) + continue; + + var statName = Utils.StatName(s, false, species.statNames); + var statNameAbb = Utils.StatName(s, true, species.statNames); + var weighting = statWeights.Item1 == null || statWeights.Item1[s] == 0 + ? StatWeighting.StatValuePreference.Indifferent + : statWeights.Item1[s] > 0 ? StatWeighting.StatValuePreference.High + : StatWeighting.StatValuePreference.Low; + + sbStatInfoText?.Append($"{statNameAbb}: {levelsWild[s]} | {levelsMutated[s]} ({valuesBreeding[s]})"); + + if (weighting == StatWeighting.StatValuePreference.High) + { + // higher stats are considered to be good. If no custom weightings are available, consider higher levels to be better. + + // check if higher level is only considered if even or odd + if ((statWeights.Item2?[s] ?? 0) == 0 // even/odd doesn't matter + || (statWeights.Item2[s] == 1 && levelsWild[s] % 2 == 1) + || (statWeights.Item2[s] == 2 && levelsWild[s] % 2 == 0) + ) + { + if (levelsWild[s] == highSpeciesLevels[s]) + { + LevelStatusFlagsCurrentNewCreature[s] = LevelStatus.TopLevel; + CombinedLevelStatusFlags |= LevelStatus.TopLevel; + topStatsText.Add(statName); + sbStatInfoText?.Append($" {Loc.S("topLevel")}"); + } + else if (highSpeciesLevels[s] != -1 && levelsWild[s] > highSpeciesLevels[s]) + { + LevelStatusFlagsCurrentNewCreature[s] = LevelStatus.NewTopLevel; + CombinedLevelStatusFlags |= LevelStatus.NewTopLevel; + newTopStatsText.Add(statName); + sbStatInfoText?.Append($" {Loc.S("newTopLevel")}"); + } + } + } + else if (weighting == StatWeighting.StatValuePreference.Low) + { + // lower stats are considered to be good + if (levelsWild[s] == lowSpeciesLevels[s]) + { + LevelStatusFlagsCurrentNewCreature[s] = LevelStatus.TopLevel; + CombinedLevelStatusFlags |= LevelStatus.TopLevel; + topStatsText.Add(statName); + sbStatInfoText?.Append($" {Loc.S("topLevel")}"); + } + else if (levelsWild[s] < lowSpeciesLevels[s]) + { + LevelStatusFlagsCurrentNewCreature[s] = LevelStatus.NewTopLevel; + CombinedLevelStatusFlags |= LevelStatus.NewTopLevel; + newTopStatsText.Add(statName); + sbStatInfoText?.Append($" {Loc.S("newTopLevel")}"); + } + } + + if (weighting == StatWeighting.StatValuePreference.High + && levelsMutated[s] > highSpeciesMutationLevels[s]) + { + LevelStatusFlagsCurrentNewCreature[s] |= LevelStatus.NewMutation; + CombinedLevelStatusFlags |= LevelStatus.NewMutation; + sbStatInfoText?.Append($" {Loc.S("new mutation")}"); + } + sbStatInfoText?.AppendLine(); + } + } + + public static void Clear() + { + for (var s = 0; s < Stats.StatsCount; s++) + LevelStatusFlagsCurrentNewCreature[s] = LevelStatus.Neutral; + CombinedLevelStatusFlags = LevelStatus.Neutral; + } + + /// + /// Status of wild levels, e.g. top level, max level. + /// + [Flags] + public enum LevelStatus + { + Neutral = 0, + /// + /// wild level is equal to the current top-level + /// + TopLevel = 1, + /// + /// wild level is higher than the current top-level + /// + NewTopLevel = 2, + /// + /// Max level to apply domesticated levels. + /// + MaxLevelForLevelUp = 4, + /// + /// Max level that can be saved. + /// + MaxLevel = 8, + /// + /// Level too high to be saved, rollover will happen. + /// + UltraMaxLevel = 16, + /// + /// Stat has new mutation. + /// + NewMutation = 32 + } + } +} diff --git a/ARKBreedingStats/local/strings.de.resx b/ARKBreedingStats/local/strings.de.resx index 9e65eabfc..86fb44e33 100644 --- a/ARKBreedingStats/local/strings.de.resx +++ b/ARKBreedingStats/local/strings.de.resx @@ -1331,4 +1331,10 @@ Es ist auch möglich Tiere mit einer Farbe in mehreren möglichen Regionen zu fi Klicken um in die Zwischenablage zu kopieren + + Aktualisiert + + + Dieser Ton wird abgespielt, wenn eine Kreatur aktualisiert wird, d.h. erneut importiert wird + \ No newline at end of file diff --git a/ARKBreedingStats/local/strings.resx b/ARKBreedingStats/local/strings.resx index e32916878..ea5a75c37 100644 --- a/ARKBreedingStats/local/strings.resx +++ b/ARKBreedingStats/local/strings.resx @@ -1343,4 +1343,10 @@ It's also possible to filter for creatures with a color in one of multiple possi Click to copy to clipboard + + Updated + + + This sound is played if a creature is updated, i.e. imported again + \ No newline at end of file diff --git a/ARKBreedingStats/ocr/OCRControl.cs b/ARKBreedingStats/ocr/OCRControl.cs index fcfff40f2..3136bc763 100644 --- a/ARKBreedingStats/ocr/OCRControl.cs +++ b/ARKBreedingStats/ocr/OCRControl.cs @@ -590,7 +590,7 @@ private void btUnloadOCR_Click(object sender, EventArgs e) private void BtNewOcrConfig_Click(object sender, EventArgs e) { var currentOcrConfig = ArkOcr.Ocr.ocrConfig; - ArkOcr.Ocr.ocrConfig = new OcrTemplate(); + ArkOcr.Ocr.ocrConfig = new OcrTemplate(true); if (SaveOcrFileAs()) return; // user doesn't want to create new config, reset to old one diff --git a/ARKBreedingStats/ocr/OCRTemplate.cs b/ARKBreedingStats/ocr/OCRTemplate.cs index 20b73bffc..3da6faf23 100644 --- a/ARKBreedingStats/ocr/OCRTemplate.cs +++ b/ARKBreedingStats/ocr/OCRTemplate.cs @@ -40,7 +40,7 @@ public class OcrTemplate /// /// Coordinates of the rectangles to read. Kept for backwards compatibility, now uses LabelRectangles. /// - [JsonProperty] + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public Rectangle[] labelRectangles; /// @@ -61,10 +61,11 @@ public class OcrTemplate public List> reducedIndices = new List>(); // indices of letters for reduced set (only [0-9\.,/%:]) - public OcrTemplate() + public OcrTemplate(bool initialize) { Version = new Version(CurrentVersion); - InitializeOcrTemplate(); + if (initialize) + InitializeOcrTemplate(); } public void InitializeOcrTemplate() diff --git a/ARKBreedingStats/settings/Settings.Designer.cs b/ARKBreedingStats/settings/Settings.Designer.cs index 6f48f8a70..497fdd264 100644 --- a/ARKBreedingStats/settings/Settings.Designer.cs +++ b/ARKBreedingStats/settings/Settings.Designer.cs @@ -124,6 +124,10 @@ private void InitializeComponent() this.checkBoxDisplayHiddenStats = new System.Windows.Forms.CheckBox(); this.tabControlSettings = new System.Windows.Forms.TabControl(); this.tabPageMultipliers = new System.Windows.Forms.TabPage(); + this.TbRemoteServerSettingsUri = new System.Windows.Forms.TextBox(); + this.BtSettingsToClipboard = new System.Windows.Forms.Button(); + this.btExportMultipliers = new System.Windows.Forms.Button(); + this.BtRemoteServerSettingsUri = new System.Windows.Forms.Button(); this.CbKeepMultipliersForNewLibrary = new System.Windows.Forms.CheckBox(); this.BtAutoImportLocalSettings = new System.Windows.Forms.Button(); this.panel3 = new System.Windows.Forms.Panel(); @@ -131,12 +135,10 @@ private void InitializeComponent() this.RbGameAse = new System.Windows.Forms.RadioButton(); this.BtImportSettingsSelectFile = new System.Windows.Forms.Button(); this.CbAtlasSettings = new System.Windows.Forms.CheckBox(); - this.BtSettingsToClipboard = new System.Windows.Forms.Button(); this.groupBox29 = new System.Windows.Forms.GroupBox(); this.CbAllowSpeedLeveling = new System.Windows.Forms.CheckBox(); this.CbAllowFlyerSpeedLeveling = new System.Windows.Forms.CheckBox(); this.label34 = new System.Windows.Forms.Label(); - this.btExportMultipliers = new System.Windows.Forms.Button(); this.groupBox18 = new System.Windows.Forms.GroupBox(); this.btApplyPreset = new System.Windows.Forms.Button(); this.cbbStatMultiplierPresets = new System.Windows.Forms.ComboBox(); @@ -162,6 +164,7 @@ private void InitializeComponent() this.GbImgCacheLocalAppData = new System.Windows.Forms.GroupBox(); this.CbImgCacheUseLocalAppData = new System.Windows.Forms.CheckBox(); this.groupBox16 = new System.Windows.Forms.GroupBox(); + this.CbStreamerMode = new System.Windows.Forms.CheckBox(); this.cbDevTools = new System.Windows.Forms.CheckBox(); this.GbSpecies = new System.Windows.Forms.GroupBox(); this.LbSpeciesSelectorCountLastUsed = new System.Windows.Forms.Label(); @@ -214,14 +217,14 @@ private void InitializeComponent() this.CbInfoGraphicDisplayMaxWildLevel = new System.Windows.Forms.CheckBox(); this.label50 = new System.Windows.Forms.Label(); this.tabPageImportSavegame = new System.Windows.Forms.TabPage(); - this.groupBox12 = new System.Windows.Forms.GroupBox(); this.label68 = new System.Windows.Forms.Label(); this.CbImportUnclaimedBabies = new System.Windows.Forms.CheckBox(); this.cbSaveImportCryo = new System.Windows.Forms.CheckBox(); + this.label24 = new System.Windows.Forms.Label(); this.cbIgnoreUnknownBPOnSaveImport = new System.Windows.Forms.CheckBox(); + this.groupBox14 = new System.Windows.Forms.GroupBox(); + this.fileSelectorExtractedSaveFolder = new ARKBreedingStats.uiControls.FileSelector(); this.textBoxImportTribeNameFilter = new System.Windows.Forms.TextBox(); - this.label_Filter = new System.Windows.Forms.Label(); - this.cbImportUpdateCreatureStatus = new System.Windows.Forms.CheckBox(); this.groupBox15 = new System.Windows.Forms.GroupBox(); this.dataGridView_FileLocations = new System.Windows.Forms.DataGridView(); this.convenientNameDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); @@ -233,9 +236,8 @@ private void InitializeComponent() this.aTImportFileLocationBindingSource = new System.Windows.Forms.BindingSource(this.components); this.btAddSavegameFileLocation = new System.Windows.Forms.Button(); this.labelSavegameFileLocationHint = new System.Windows.Forms.Label(); - this.groupBox14 = new System.Windows.Forms.GroupBox(); - this.fileSelectorExtractedSaveFolder = new ARKBreedingStats.uiControls.FileSelector(); - this.label24 = new System.Windows.Forms.Label(); + this.label_Filter = new System.Windows.Forms.Label(); + this.cbImportUpdateCreatureStatus = new System.Windows.Forms.CheckBox(); this.tabPageImportExported = new System.Windows.Forms.TabPage(); this.BtGetExportFolderAutomatically = new System.Windows.Forms.Button(); this.groupBox27 = new System.Windows.Forms.GroupBox(); @@ -254,6 +256,7 @@ private void InitializeComponent() this.CbExportFileRenameAfterImport = new System.Windows.Forms.CheckBox(); this.BtImportArchiveFolder = new System.Windows.Forms.Button(); this.panel2 = new System.Windows.Forms.Panel(); + this.BtBeepUpdated = new System.Windows.Forms.Button(); this.BtBeepNewTop = new System.Windows.Forms.Button(); this.BtBeepTop = new System.Windows.Forms.Button(); this.BtBeepSuccess = new System.Windows.Forms.Button(); @@ -351,8 +354,7 @@ private void InitializeComponent() this.label1 = new System.Windows.Forms.Label(); this.panel1 = new System.Windows.Forms.Panel(); this.colorDialog1 = new System.Windows.Forms.ColorDialog(); - this.BtRemoteServerSettingsUri = new System.Windows.Forms.Button(); - this.TbRemoteServerSettingsUri = new System.Windows.Forms.TextBox(); + this.CbLibraryDisplayZeroMutationLevels = new System.Windows.Forms.CheckBox(); this.groupBoxMultiplier.SuspendLayout(); this.groupBox2.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.nudTamedDinoCharacterFoodDrain)).BeginInit(); @@ -422,11 +424,10 @@ private void InitializeComponent() ((System.ComponentModel.ISupportInitialize)(this.nudInfoGraphicHeight)).BeginInit(); this.groupBox28.SuspendLayout(); this.tabPageImportSavegame.SuspendLayout(); - this.groupBox12.SuspendLayout(); + this.groupBox14.SuspendLayout(); this.groupBox15.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.dataGridView_FileLocations)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.aTImportFileLocationBindingSource)).BeginInit(); - this.groupBox14.SuspendLayout(); this.tabPageImportExported.SuspendLayout(); this.groupBox27.SuspendLayout(); this.groupBox23.SuspendLayout(); @@ -1900,6 +1901,43 @@ private void InitializeComponent() this.tabPageMultipliers.DragDrop += new System.Windows.Forms.DragEventHandler(this.tabPage2_DragDrop); this.tabPageMultipliers.DragEnter += new System.Windows.Forms.DragEventHandler(this.tabPage2_DragEnter); // + // TbRemoteServerSettingsUri + // + this.TbRemoteServerSettingsUri.Location = new System.Drawing.Point(407, 659); + this.TbRemoteServerSettingsUri.Name = "TbRemoteServerSettingsUri"; + this.TbRemoteServerSettingsUri.Size = new System.Drawing.Size(152, 20); + this.TbRemoteServerSettingsUri.TabIndex = 20; + // + // BtSettingsToClipboard + // + this.BtSettingsToClipboard.Location = new System.Drawing.Point(600, 713); + this.BtSettingsToClipboard.Name = "BtSettingsToClipboard"; + this.BtSettingsToClipboard.Size = new System.Drawing.Size(142, 23); + this.BtSettingsToClipboard.TabIndex = 13; + this.BtSettingsToClipboard.Text = "Copy settings to clipboard"; + this.BtSettingsToClipboard.UseVisualStyleBackColor = true; + this.BtSettingsToClipboard.Click += new System.EventHandler(this.BtSettingsToClipboard_Click); + // + // btExportMultipliers + // + this.btExportMultipliers.Location = new System.Drawing.Point(407, 713); + this.btExportMultipliers.Name = "btExportMultipliers"; + this.btExportMultipliers.Size = new System.Drawing.Size(187, 23); + this.btExportMultipliers.TabIndex = 11; + this.btExportMultipliers.Text = "Export multiplier settings to file…"; + this.btExportMultipliers.UseVisualStyleBackColor = true; + this.btExportMultipliers.Click += new System.EventHandler(this.btExportMultipliers_Click); + // + // BtRemoteServerSettingsUri + // + this.BtRemoteServerSettingsUri.Location = new System.Drawing.Point(565, 657); + this.BtRemoteServerSettingsUri.Name = "BtRemoteServerSettingsUri"; + this.BtRemoteServerSettingsUri.Size = new System.Drawing.Size(167, 23); + this.BtRemoteServerSettingsUri.TabIndex = 19; + this.BtRemoteServerSettingsUri.Text = "Import remote settings"; + this.BtRemoteServerSettingsUri.UseVisualStyleBackColor = true; + this.BtRemoteServerSettingsUri.Click += new System.EventHandler(this.BtRemoteServerSettingsUri_Click); + // // CbKeepMultipliersForNewLibrary // this.CbKeepMultipliersForNewLibrary.AutoSize = true; @@ -1940,6 +1978,7 @@ private void InitializeComponent() this.RbGameAsa.TabStop = true; this.RbGameAsa.Text = "ASA"; this.RbGameAsa.UseVisualStyleBackColor = true; + this.RbGameAsa.CheckedChanged += new System.EventHandler(this.RbGameAsa_CheckedChanged); // // RbGameAse // @@ -1973,16 +2012,6 @@ private void InitializeComponent() this.CbAtlasSettings.Text = "ATLAS settings"; this.CbAtlasSettings.UseVisualStyleBackColor = true; // - // BtSettingsToClipboard - // - this.BtSettingsToClipboard.Location = new System.Drawing.Point(600, 713); - this.BtSettingsToClipboard.Name = "BtSettingsToClipboard"; - this.BtSettingsToClipboard.Size = new System.Drawing.Size(142, 23); - this.BtSettingsToClipboard.TabIndex = 13; - this.BtSettingsToClipboard.Text = "Copy settings to clipboard"; - this.BtSettingsToClipboard.UseVisualStyleBackColor = true; - this.BtSettingsToClipboard.Click += new System.EventHandler(this.BtSettingsToClipboard_Click); - // // groupBox29 // this.groupBox29.Controls.Add(this.CbAllowSpeedLeveling); @@ -2023,16 +2052,6 @@ private void InitializeComponent() this.label34.TabIndex = 10; this.label34.Text = "You can export the settings on this page to a file or the clipboard to share it w" + "ith tribe members or for bug reports."; - // - // btExportMultipliers - // - this.btExportMultipliers.Location = new System.Drawing.Point(407, 713); - this.btExportMultipliers.Name = "btExportMultipliers"; - this.btExportMultipliers.Size = new System.Drawing.Size(187, 23); - this.btExportMultipliers.TabIndex = 11; - this.btExportMultipliers.Text = "Export multiplier settings to file…"; - this.btExportMultipliers.UseVisualStyleBackColor = true; - this.btExportMultipliers.Click += new System.EventHandler(this.btExportMultipliers_Click); // // groupBox18 // @@ -2192,7 +2211,7 @@ private void InitializeComponent() // CbAskSaveSettingsOnClose // this.CbAskSaveSettingsOnClose.AutoSize = true; - this.CbAskSaveSettingsOnClose.Location = new System.Drawing.Point(329, 699); + this.CbAskSaveSettingsOnClose.Location = new System.Drawing.Point(435, 721); this.CbAskSaveSettingsOnClose.Name = "CbAskSaveSettingsOnClose"; this.CbAskSaveSettingsOnClose.Size = new System.Drawing.Size(309, 17); this.CbAskSaveSettingsOnClose.TabIndex = 15; @@ -2204,7 +2223,7 @@ private void InitializeComponent() this.groupBox31.Controls.Add(this.CbColorIdOnColorRegionButton); this.groupBox31.Controls.Add(this.CbAlwaysShowAllColorRegions); this.groupBox31.Controls.Add(this.CbHideInvisibleColorRegions); - this.groupBox31.Location = new System.Drawing.Point(329, 283); + this.groupBox31.Location = new System.Drawing.Point(329, 319); this.groupBox31.Name = "groupBox31"; this.groupBox31.Size = new System.Drawing.Size(413, 66); this.groupBox31.TabIndex = 14; @@ -2247,9 +2266,9 @@ private void InitializeComponent() this.groupBox30.Controls.Add(this.BExportSpreadsheetMoveDown); this.groupBox30.Controls.Add(this.BExportSpreadsheetMoveUp); this.groupBox30.Controls.Add(this.ClbExportSpreadsheetFields); - this.groupBox30.Location = new System.Drawing.Point(329, 355); + this.groupBox30.Location = new System.Drawing.Point(329, 391); this.groupBox30.Name = "groupBox30"; - this.groupBox30.Size = new System.Drawing.Size(413, 281); + this.groupBox30.Size = new System.Drawing.Size(413, 268); this.groupBox30.TabIndex = 13; this.groupBox30.TabStop = false; this.groupBox30.Text = "Info to export for spreadsheet"; @@ -2288,9 +2307,9 @@ private void InitializeComponent() // ClbExportSpreadsheetFields // this.ClbExportSpreadsheetFields.FormattingEnabled = true; - this.ClbExportSpreadsheetFields.Location = new System.Drawing.Point(36, 41); + this.ClbExportSpreadsheetFields.Location = new System.Drawing.Point(36, 42); this.ClbExportSpreadsheetFields.Name = "ClbExportSpreadsheetFields"; - this.ClbExportSpreadsheetFields.Size = new System.Drawing.Size(371, 229); + this.ClbExportSpreadsheetFields.Size = new System.Drawing.Size(371, 214); this.ClbExportSpreadsheetFields.TabIndex = 12; // // GbImgCacheLocalAppData @@ -2315,18 +2334,27 @@ private void InitializeComponent() // // groupBox16 // + this.groupBox16.Controls.Add(this.CbStreamerMode); this.groupBox16.Controls.Add(this.cbDevTools); this.groupBox16.Location = new System.Drawing.Point(329, 234); this.groupBox16.Name = "groupBox16"; - this.groupBox16.Size = new System.Drawing.Size(413, 43); + this.groupBox16.Size = new System.Drawing.Size(413, 79); this.groupBox16.TabIndex = 10; this.groupBox16.TabStop = false; - this.groupBox16.Text = "Dev-Tools"; + this.groupBox16.Text = "Application"; + // + // CbStreamerMode + // + this.CbStreamerMode.Location = new System.Drawing.Point(6, 19); + this.CbStreamerMode.Name = "CbStreamerMode"; + this.CbStreamerMode.Size = new System.Drawing.Size(407, 24); + this.CbStreamerMode.TabIndex = 1; + this.CbStreamerMode.Text = "Streamer mode (hide confidential info, e.g. ASB server tag)"; + this.CbStreamerMode.UseVisualStyleBackColor = true; // // cbDevTools // - this.cbDevTools.Dock = System.Windows.Forms.DockStyle.Fill; - this.cbDevTools.Location = new System.Drawing.Point(3, 16); + this.cbDevTools.Location = new System.Drawing.Point(6, 44); this.cbDevTools.Name = "cbDevTools"; this.cbDevTools.Size = new System.Drawing.Size(407, 24); this.cbDevTools.TabIndex = 0; @@ -2486,7 +2514,7 @@ private void InitializeComponent() this.groupBox17.Controls.Add(this.LbLanguage2); this.groupBox17.Controls.Add(this.CbbLanguage2); this.groupBox17.Controls.Add(this.CbbLanguage); - this.groupBox17.Location = new System.Drawing.Point(329, 642); + this.groupBox17.Location = new System.Drawing.Point(329, 665); this.groupBox17.Name = "groupBox17"; this.groupBox17.Size = new System.Drawing.Size(413, 51); this.groupBox17.TabIndex = 5; @@ -2522,6 +2550,7 @@ private void InitializeComponent() // // groupBox9 // + this.groupBox9.Controls.Add(this.CbLibraryDisplayZeroMutationLevels); this.groupBox9.Controls.Add(this.CbDisplayLibraryCreatureIndex); this.groupBox9.Controls.Add(this.CbNaturalSortIgnoreSpaces); this.groupBox9.Controls.Add(this.CbNaturalSorting); @@ -2533,7 +2562,7 @@ private void InitializeComponent() this.groupBox9.Controls.Add(this.cbCreatureColorsLibrary); this.groupBox9.Location = new System.Drawing.Point(6, 509); this.groupBox9.Name = "groupBox9"; - this.groupBox9.Size = new System.Drawing.Size(317, 207); + this.groupBox9.Size = new System.Drawing.Size(317, 229); this.groupBox9.TabIndex = 4; this.groupBox9.TabStop = false; this.groupBox9.Text = "Library"; @@ -2893,7 +2922,16 @@ private void InitializeComponent() // tabPageImportSavegame // this.tabPageImportSavegame.AutoScroll = true; - this.tabPageImportSavegame.Controls.Add(this.groupBox12); + this.tabPageImportSavegame.Controls.Add(this.label68); + this.tabPageImportSavegame.Controls.Add(this.CbImportUnclaimedBabies); + this.tabPageImportSavegame.Controls.Add(this.cbSaveImportCryo); + this.tabPageImportSavegame.Controls.Add(this.label24); + this.tabPageImportSavegame.Controls.Add(this.cbIgnoreUnknownBPOnSaveImport); + this.tabPageImportSavegame.Controls.Add(this.groupBox14); + this.tabPageImportSavegame.Controls.Add(this.textBoxImportTribeNameFilter); + this.tabPageImportSavegame.Controls.Add(this.groupBox15); + this.tabPageImportSavegame.Controls.Add(this.label_Filter); + this.tabPageImportSavegame.Controls.Add(this.cbImportUpdateCreatureStatus); this.tabPageImportSavegame.Location = new System.Drawing.Point(4, 22); this.tabPageImportSavegame.Name = "tabPageImportSavegame"; this.tabPageImportSavegame.Padding = new System.Windows.Forms.Padding(3); @@ -2902,30 +2940,11 @@ private void InitializeComponent() this.tabPageImportSavegame.Text = "Import Savegame"; this.tabPageImportSavegame.UseVisualStyleBackColor = true; // - // groupBox12 - // - this.groupBox12.Controls.Add(this.label68); - this.groupBox12.Controls.Add(this.CbImportUnclaimedBabies); - this.groupBox12.Controls.Add(this.cbSaveImportCryo); - this.groupBox12.Controls.Add(this.cbIgnoreUnknownBPOnSaveImport); - this.groupBox12.Controls.Add(this.textBoxImportTribeNameFilter); - this.groupBox12.Controls.Add(this.label_Filter); - this.groupBox12.Controls.Add(this.cbImportUpdateCreatureStatus); - this.groupBox12.Controls.Add(this.groupBox15); - this.groupBox12.Controls.Add(this.groupBox14); - this.groupBox12.Controls.Add(this.label24); - this.groupBox12.Location = new System.Drawing.Point(3, 3); - this.groupBox12.Name = "groupBox12"; - this.groupBox12.Size = new System.Drawing.Size(739, 667); - this.groupBox12.TabIndex = 0; - this.groupBox12.TabStop = false; - this.groupBox12.Text = "Import Data from Save-File"; - // // label68 // this.label68.AutoSize = true; this.label68.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label68.Location = new System.Drawing.Point(6, 16); + this.label68.Location = new System.Drawing.Point(8, 3); this.label68.Name = "label68"; this.label68.Size = new System.Drawing.Size(506, 20); this.label68.TabIndex = 1; @@ -2934,7 +2953,7 @@ private void InitializeComponent() // CbImportUnclaimedBabies // this.CbImportUnclaimedBabies.AutoSize = true; - this.CbImportUnclaimedBabies.Location = new System.Drawing.Point(9, 176); + this.CbImportUnclaimedBabies.Location = new System.Drawing.Point(11, 163); this.CbImportUnclaimedBabies.Name = "CbImportUnclaimedBabies"; this.CbImportUnclaimedBabies.Size = new System.Drawing.Size(140, 17); this.CbImportUnclaimedBabies.TabIndex = 8; @@ -2944,57 +2963,66 @@ private void InitializeComponent() // cbSaveImportCryo // this.cbSaveImportCryo.AutoSize = true; - this.cbSaveImportCryo.Location = new System.Drawing.Point(9, 153); + this.cbSaveImportCryo.Location = new System.Drawing.Point(11, 140); this.cbSaveImportCryo.Name = "cbSaveImportCryo"; this.cbSaveImportCryo.Size = new System.Drawing.Size(216, 17); this.cbSaveImportCryo.TabIndex = 3; this.cbSaveImportCryo.Text = "Import creatures in cryopods or soultraps"; this.cbSaveImportCryo.UseVisualStyleBackColor = true; // + // label24 + // + this.label24.Location = new System.Drawing.Point(8, 39); + this.label24.Name = "label24"; + this.label24.Size = new System.Drawing.Size(730, 38); + this.label24.TabIndex = 0; + this.label24.Text = resources.GetString("label24.Text"); + // // cbIgnoreUnknownBPOnSaveImport // this.cbIgnoreUnknownBPOnSaveImport.AutoSize = true; - this.cbIgnoreUnknownBPOnSaveImport.Location = new System.Drawing.Point(9, 130); + this.cbIgnoreUnknownBPOnSaveImport.Location = new System.Drawing.Point(11, 117); this.cbIgnoreUnknownBPOnSaveImport.Name = "cbIgnoreUnknownBPOnSaveImport"; this.cbIgnoreUnknownBPOnSaveImport.Size = new System.Drawing.Size(334, 17); this.cbIgnoreUnknownBPOnSaveImport.TabIndex = 2; this.cbIgnoreUnknownBPOnSaveImport.Text = "Ignore unknown species on import and don\'t show a messagebox"; this.cbIgnoreUnknownBPOnSaveImport.UseVisualStyleBackColor = true; // - // textBoxImportTribeNameFilter + // groupBox14 // - this.textBoxImportTribeNameFilter.Location = new System.Drawing.Point(3, 215); - this.textBoxImportTribeNameFilter.Name = "textBoxImportTribeNameFilter"; - this.textBoxImportTribeNameFilter.Size = new System.Drawing.Size(730, 20); - this.textBoxImportTribeNameFilter.TabIndex = 5; + this.groupBox14.Controls.Add(this.fileSelectorExtractedSaveFolder); + this.groupBox14.Location = new System.Drawing.Point(8, 236); + this.groupBox14.Name = "groupBox14"; + this.groupBox14.Size = new System.Drawing.Size(730, 47); + this.groupBox14.TabIndex = 6; + this.groupBox14.TabStop = false; + this.groupBox14.Text = "Target folder for save-game working copy (user\'s temp dir if empty). It\'s recomme" + + "nded to leave this setting empty."; // - // label_Filter + // fileSelectorExtractedSaveFolder // - this.label_Filter.AutoSize = true; - this.label_Filter.Location = new System.Drawing.Point(3, 199); - this.label_Filter.Name = "label_Filter"; - this.label_Filter.Size = new System.Drawing.Size(487, 13); - this.label_Filter.TabIndex = 4; - this.label_Filter.Text = "Import only tribes with names containing at least one of these comma separated va" + - "lues, case sensitive"; + this.fileSelectorExtractedSaveFolder.Dock = System.Windows.Forms.DockStyle.Fill; + this.fileSelectorExtractedSaveFolder.Link = "filename"; + this.fileSelectorExtractedSaveFolder.Location = new System.Drawing.Point(3, 16); + this.fileSelectorExtractedSaveFolder.Name = "fileSelectorExtractedSaveFolder"; + this.fileSelectorExtractedSaveFolder.Size = new System.Drawing.Size(724, 28); + this.fileSelectorExtractedSaveFolder.TabIndex = 0; // - // cbImportUpdateCreatureStatus + // textBoxImportTribeNameFilter // - this.cbImportUpdateCreatureStatus.Location = new System.Drawing.Point(9, 87); - this.cbImportUpdateCreatureStatus.Name = "cbImportUpdateCreatureStatus"; - this.cbImportUpdateCreatureStatus.Size = new System.Drawing.Size(727, 37); - this.cbImportUpdateCreatureStatus.TabIndex = 1; - this.cbImportUpdateCreatureStatus.Text = "Update Available/Unavailable Status on Import for disappeared or reappeared creat" + - "ures (disable this if you will import savegames from multiple servers). This set" + - "ting is saved per library."; - this.cbImportUpdateCreatureStatus.UseVisualStyleBackColor = true; + this.textBoxImportTribeNameFilter.Location = new System.Drawing.Point(5, 202); + this.textBoxImportTribeNameFilter.Name = "textBoxImportTribeNameFilter"; + this.textBoxImportTribeNameFilter.Size = new System.Drawing.Size(730, 20); + this.textBoxImportTribeNameFilter.TabIndex = 5; // // groupBox15 // + this.groupBox15.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.groupBox15.Controls.Add(this.dataGridView_FileLocations); this.groupBox15.Controls.Add(this.btAddSavegameFileLocation); this.groupBox15.Controls.Add(this.labelSavegameFileLocationHint); - this.groupBox15.Location = new System.Drawing.Point(6, 302); + this.groupBox15.Location = new System.Drawing.Point(8, 289); this.groupBox15.Name = "groupBox15"; this.groupBox15.Size = new System.Drawing.Size(730, 386); this.groupBox15.TabIndex = 7; @@ -3108,33 +3136,26 @@ private void InitializeComponent() this.labelSavegameFileLocationHint.Text = "Location example for The Island: ...\\Steam\\steamapps\\common\\ARK\\ShooterGame\\Saved" + "\\SavedArksLocal\\TheIsland.ark"; // - // groupBox14 - // - this.groupBox14.Controls.Add(this.fileSelectorExtractedSaveFolder); - this.groupBox14.Location = new System.Drawing.Point(6, 249); - this.groupBox14.Name = "groupBox14"; - this.groupBox14.Size = new System.Drawing.Size(730, 47); - this.groupBox14.TabIndex = 6; - this.groupBox14.TabStop = false; - this.groupBox14.Text = "Target folder for save-game working copy (user\'s temp dir if empty). It\'s recomme" + - "nded to leave this setting empty."; - // - // fileSelectorExtractedSaveFolder + // label_Filter // - this.fileSelectorExtractedSaveFolder.Dock = System.Windows.Forms.DockStyle.Fill; - this.fileSelectorExtractedSaveFolder.Link = "filename"; - this.fileSelectorExtractedSaveFolder.Location = new System.Drawing.Point(3, 16); - this.fileSelectorExtractedSaveFolder.Name = "fileSelectorExtractedSaveFolder"; - this.fileSelectorExtractedSaveFolder.Size = new System.Drawing.Size(724, 28); - this.fileSelectorExtractedSaveFolder.TabIndex = 0; + this.label_Filter.AutoSize = true; + this.label_Filter.Location = new System.Drawing.Point(5, 186); + this.label_Filter.Name = "label_Filter"; + this.label_Filter.Size = new System.Drawing.Size(487, 13); + this.label_Filter.TabIndex = 4; + this.label_Filter.Text = "Import only tribes with names containing at least one of these comma separated va" + + "lues, case sensitive"; // - // label24 + // cbImportUpdateCreatureStatus // - this.label24.Location = new System.Drawing.Point(6, 52); - this.label24.Name = "label24"; - this.label24.Size = new System.Drawing.Size(730, 38); - this.label24.TabIndex = 0; - this.label24.Text = resources.GetString("label24.Text"); + this.cbImportUpdateCreatureStatus.Location = new System.Drawing.Point(11, 74); + this.cbImportUpdateCreatureStatus.Name = "cbImportUpdateCreatureStatus"; + this.cbImportUpdateCreatureStatus.Size = new System.Drawing.Size(727, 37); + this.cbImportUpdateCreatureStatus.TabIndex = 1; + this.cbImportUpdateCreatureStatus.Text = "Update Available/Unavailable Status on Import for disappeared or reappeared creat" + + "ures (disable this if you will import savegames from multiple servers). This set" + + "ting is saved per library."; + this.cbImportUpdateCreatureStatus.UseVisualStyleBackColor = true; // // tabPageImportExported // @@ -3333,6 +3354,7 @@ private void InitializeComponent() // // panel2 // + this.panel2.Controls.Add(this.BtBeepUpdated); this.panel2.Controls.Add(this.BtBeepNewTop); this.panel2.Controls.Add(this.BtBeepTop); this.panel2.Controls.Add(this.BtBeepSuccess); @@ -3340,12 +3362,22 @@ private void InitializeComponent() this.panel2.Controls.Add(this.BtBeepFailure); this.panel2.Location = new System.Drawing.Point(285, 11); this.panel2.Name = "panel2"; - this.panel2.Size = new System.Drawing.Size(121, 131); + this.panel2.Size = new System.Drawing.Size(121, 148); this.panel2.TabIndex = 7; // + // BtBeepUpdated + // + this.BtBeepUpdated.Location = new System.Drawing.Point(3, 122); + this.BtBeepUpdated.Name = "BtBeepUpdated"; + this.BtBeepUpdated.Size = new System.Drawing.Size(115, 23); + this.BtBeepUpdated.TabIndex = 5; + this.BtBeepUpdated.Text = "updated"; + this.BtBeepUpdated.UseVisualStyleBackColor = true; + this.BtBeepUpdated.Click += new System.EventHandler(this.BtBeepUpdated_Click); + // // BtBeepNewTop // - this.BtBeepNewTop.Location = new System.Drawing.Point(3, 105); + this.BtBeepNewTop.Location = new System.Drawing.Point(3, 96); this.BtBeepNewTop.Name = "BtBeepNewTop"; this.BtBeepNewTop.Size = new System.Drawing.Size(115, 23); this.BtBeepNewTop.TabIndex = 4; @@ -3355,7 +3387,7 @@ private void InitializeComponent() // // BtBeepTop // - this.BtBeepTop.Location = new System.Drawing.Point(3, 76); + this.BtBeepTop.Location = new System.Drawing.Point(3, 70); this.BtBeepTop.Name = "BtBeepTop"; this.BtBeepTop.Size = new System.Drawing.Size(115, 23); this.BtBeepTop.TabIndex = 3; @@ -3365,7 +3397,7 @@ private void InitializeComponent() // // BtBeepSuccess // - this.BtBeepSuccess.Location = new System.Drawing.Point(3, 47); + this.BtBeepSuccess.Location = new System.Drawing.Point(3, 44); this.BtBeepSuccess.Name = "BtBeepSuccess"; this.BtBeepSuccess.Size = new System.Drawing.Size(115, 23); this.BtBeepSuccess.TabIndex = 2; @@ -3549,6 +3581,8 @@ private void InitializeComponent() // // groupBox13 // + this.groupBox13.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.groupBox13.Controls.Add(this.dataGridViewExportFolders); this.groupBox13.Controls.Add(this.btAddExportFolder); this.groupBox13.Location = new System.Drawing.Point(6, 112); @@ -4486,22 +4520,15 @@ private void InitializeComponent() this.panel1.Size = new System.Drawing.Size(758, 30); this.panel1.TabIndex = 12; // - // BtRemoteServerSettingsUri - // - this.BtRemoteServerSettingsUri.Location = new System.Drawing.Point(565, 657); - this.BtRemoteServerSettingsUri.Name = "BtRemoteServerSettingsUri"; - this.BtRemoteServerSettingsUri.Size = new System.Drawing.Size(167, 23); - this.BtRemoteServerSettingsUri.TabIndex = 19; - this.BtRemoteServerSettingsUri.Text = "Import remote settings"; - this.BtRemoteServerSettingsUri.UseVisualStyleBackColor = true; - this.BtRemoteServerSettingsUri.Click += new System.EventHandler(this.BtRemoteServerSettingsUri_Click); - // - // TbRemoteServerSettingsUri + // CbLibraryDisplayZeroMutationLevels // - this.TbRemoteServerSettingsUri.Location = new System.Drawing.Point(407, 659); - this.TbRemoteServerSettingsUri.Name = "TbRemoteServerSettingsUri"; - this.TbRemoteServerSettingsUri.Size = new System.Drawing.Size(152, 20); - this.TbRemoteServerSettingsUri.TabIndex = 20; + this.CbLibraryDisplayZeroMutationLevels.AutoSize = true; + this.CbLibraryDisplayZeroMutationLevels.Location = new System.Drawing.Point(6, 203); + this.CbLibraryDisplayZeroMutationLevels.Name = "CbLibraryDisplayZeroMutationLevels"; + this.CbLibraryDisplayZeroMutationLevels.Size = new System.Drawing.Size(156, 17); + this.CbLibraryDisplayZeroMutationLevels.TabIndex = 9; + this.CbLibraryDisplayZeroMutationLevels.Text = "Display zero mutation levels"; + this.CbLibraryDisplayZeroMutationLevels.UseVisualStyleBackColor = true; // // Settings // @@ -4611,13 +4638,12 @@ private void InitializeComponent() this.groupBox28.ResumeLayout(false); this.groupBox28.PerformLayout(); this.tabPageImportSavegame.ResumeLayout(false); - this.groupBox12.ResumeLayout(false); - this.groupBox12.PerformLayout(); + this.tabPageImportSavegame.PerformLayout(); + this.groupBox14.ResumeLayout(false); this.groupBox15.ResumeLayout(false); this.groupBox15.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.dataGridView_FileLocations)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.aTImportFileLocationBindingSource)).EndInit(); - this.groupBox14.ResumeLayout(false); this.tabPageImportExported.ResumeLayout(false); this.tabPageImportExported.PerformLayout(); this.groupBox27.ResumeLayout(false); @@ -4745,7 +4771,6 @@ private void InitializeComponent() private System.Windows.Forms.GroupBox groupBox9; private System.Windows.Forms.CheckBox cbCreatureColorsLibrary; private System.Windows.Forms.TabPage tabPageImportSavegame; - private System.Windows.Forms.GroupBox groupBox12; private System.Windows.Forms.Label label24; private System.Windows.Forms.GroupBox groupBox15; private System.Windows.Forms.GroupBox groupBox14; @@ -4994,5 +5019,8 @@ private void InitializeComponent() private System.Windows.Forms.Label label69; private System.Windows.Forms.Button BtRemoteServerSettingsUri; private System.Windows.Forms.TextBox TbRemoteServerSettingsUri; + private System.Windows.Forms.Button BtBeepUpdated; + private System.Windows.Forms.CheckBox CbStreamerMode; + private System.Windows.Forms.CheckBox CbLibraryDisplayZeroMutationLevels; } } \ No newline at end of file diff --git a/ARKBreedingStats/settings/Settings.cs b/ARKBreedingStats/settings/Settings.cs index ecac9b50f..480349793 100644 --- a/ARKBreedingStats/settings/Settings.cs +++ b/ARKBreedingStats/settings/Settings.cs @@ -5,7 +5,6 @@ using System.Drawing; using System.IO; using System.Linq; -using System.Net.Http; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; @@ -215,8 +214,15 @@ private void LoadSettings(CreatureCollection cc) } cbSingleplayerSettings.Checked = cc.singlePlayerSettings; CbAtlasSettings.Checked = _cc.AtlasSettings; - if (_cc.Game == Ark.Asa) RbGameAsa.Checked = true; - else RbGameAse.Checked = true; + if (_cc.Game == Ark.Asa) + { + RbGameAsa.Checked = true; + } + else + { + RbGameAse.Checked = true; + CbAllowSpeedLeveling.Visible = false; + } nudMaxDomLevels.ValueSave = cc.maxDomLevel; numericUpDownMaxBreedingSug.ValueSave = cc.maxBreedingSuggestions; @@ -360,6 +366,7 @@ private void LoadSettings(CreatureCollection cc) CbNaturalSortIgnoreSpaces.Enabled = Properties.Settings.Default.UseNaturalSort; CbNaturalSortIgnoreSpaces.Checked = Properties.Settings.Default.NaturalSortIgnoreSpaces; CbDisplayLibraryCreatureIndex.Checked = Properties.Settings.Default.DisplayLibraryCreatureIndex; + CbLibraryDisplayZeroMutationLevels.Checked = Properties.Settings.Default.LibraryDisplayZeroMutationLevels; #endregion @@ -432,6 +439,7 @@ private void LoadSettings(CreatureCollection cc) NudSpeciesSelectorCountLastUsed.ValueSave = Properties.Settings.Default.SpeciesSelectorCountLastSpecies; + CbStreamerMode.Checked = Properties.Settings.Default.StreamerMode; cbDevTools.Checked = Properties.Settings.Default.DevTools; cbPrettifyJSON.Checked = Properties.Settings.Default.prettifyCollectionJson; @@ -614,6 +622,7 @@ private void SaveSettings() Properties.Settings.Default.UseNaturalSort = CbNaturalSorting.Checked; Properties.Settings.Default.NaturalSortIgnoreSpaces = CbNaturalSortIgnoreSpaces.Checked; Properties.Settings.Default.DisplayLibraryCreatureIndex = CbDisplayLibraryCreatureIndex.Checked; + Properties.Settings.Default.LibraryDisplayZeroMutationLevels = CbLibraryDisplayZeroMutationLevels.Checked; #endregion @@ -670,6 +679,7 @@ private void SaveSettings() Properties.Settings.Default.SpeciesSelectorCountLastSpecies = (int)NudSpeciesSelectorCountLastUsed.Value; + Properties.Settings.Default.StreamerMode = CbStreamerMode.Checked; Properties.Settings.Default.DevTools = cbDevTools.Checked; Properties.Settings.Default.prettifyCollectionJson = cbPrettifyJSON.Checked; @@ -1296,6 +1306,7 @@ private void Localization() Loc.ControlText(BtBeepSuccess, _tt); Loc.ControlText(BtBeepTop, _tt); Loc.ControlText(BtBeepNewTop, _tt); + Loc.ControlText(BtBeepUpdated, _tt); Loc.ControlText(BtGetExportFolderAutomatically); } @@ -1335,6 +1346,11 @@ private void BtBeepNewTop_Click(object sender, EventArgs e) SoundFeedback.BeepSignal(SoundFeedback.FeedbackSounds.Great); } + private void BtBeepUpdated_Click(object sender, EventArgs e) + { + SoundFeedback.BeepSignal(SoundFeedback.FeedbackSounds.Updated); + } + private void BtImportArchiveFolder_Click(object sender, EventArgs e) { // get folder of first export path @@ -1776,5 +1792,13 @@ private async void BtRemoteServerSettingsUri_Click(object sender, EventArgs e) BtRemoteServerSettingsUri.Text = "Load remote settings"; } } + + private void RbGameAsa_CheckedChanged(object sender, EventArgs e) + { + var isAsa = RbGameAsa.Checked; + CbAllowSpeedLeveling.Visible = isAsa; + if (!isAsa) + CbAllowSpeedLeveling.Checked = true; + } } } diff --git a/ARKBreedingStats/settings/Settings.resx b/ARKBreedingStats/settings/Settings.resx index 05c9ce312..ba4bd8b0e 100644 --- a/ARKBreedingStats/settings/Settings.resx +++ b/ARKBreedingStats/settings/Settings.resx @@ -120,6 +120,10 @@ If you have the files Game.ini or GameUserSettings.ini from your server, you can drag&&drop them on this window to insert their values. You can also select the text of the settings and drag&&drop the selection. + + + The creature data can be directly imported from the save-game, if you have access to that. This is also possible via an ftp-adress. +If you set the according files below, you can start the process automatically from the file-menu. True @@ -133,10 +137,6 @@ You can also select the text of the settings and drag&&drop the selectio 17, 17 - - The creature data can be directly imported from the save-game, if you have access to that. This is also possible via an ftp-adress. -If you set the according files below, you can start the process automatically from the file-menu. - True diff --git a/ARKBreedingStats/species/Species.cs b/ARKBreedingStats/species/Species.cs index 658ccaac9..47051e221 100644 --- a/ARKBreedingStats/species/Species.cs +++ b/ARKBreedingStats/species/Species.cs @@ -107,7 +107,7 @@ public class Species /// /// The used multipliers for each stat applied to the imprinting-bonus, affected by custom overrides and global leveling settings. - /// + /// public double[] StatImprintMultipliers; [JsonProperty] @@ -436,7 +436,7 @@ public void LoadOverrides(Species overrides) if (overrides.DisplayedStats != 0) DisplayedStats = overrides.DisplayedStats; if (overrides.skipWildLevelStats != 0) skipWildLevelStats = overrides.skipWildLevelStats; if (overrides.TamedBaseHealthMultiplier != null) TamedBaseHealthMultiplier = overrides.TamedBaseHealthMultiplier; - if (overrides.statImprintMult != null) statImprintMult = overrides.statImprintMult.ToArray(); + if (overrides.statImprintMult != null && overrides.statImprintMult != StatImprintMultipliersDefaultAse) statImprintMult = overrides.statImprintMult.ToArray(); if (overrides.mutationMult != null) mutationMult = overrides.mutationMult; if (overrides.colors != null) colors = overrides.colors; if (overrides.taming != null) taming = overrides.taming; diff --git a/ARKBreedingStats/uiControls/CreatureAnalysis.cs b/ARKBreedingStats/uiControls/CreatureAnalysis.cs index e6aeaa14f..969c3abc0 100644 --- a/ARKBreedingStats/uiControls/CreatureAnalysis.cs +++ b/ARKBreedingStats/uiControls/CreatureAnalysis.cs @@ -1,5 +1,6 @@ using System.Drawing; using System.Windows.Forms; +using ARKBreedingStats.library; namespace ARKBreedingStats.uiControls { @@ -10,10 +11,10 @@ public CreatureAnalysis() InitializeComponent(); } - private LevelStatus _statsStatus; - private LevelStatus _colorStatus; + private LevelStatusFlags.LevelStatus _statsStatus; + private LevelStatusFlags.LevelStatus _colorStatus; - public void SetStatsAnalysis(LevelStatus statsStatus, string statsAnalysis) + public void SetStatsAnalysis(LevelStatusFlags.LevelStatus statsStatus, string statsAnalysis) { _statsStatus = statsStatus; SetStatus(LbStatsStatus, statsStatus); @@ -21,7 +22,7 @@ public void SetStatsAnalysis(LevelStatus statsStatus, string statsAnalysis) LbStatAnalysis.Text = statsAnalysis; var generalStatus = statsStatus; - if (generalStatus != LevelStatus.NewTopLevel && _colorStatus != LevelStatus.Neutral) + if (!generalStatus.HasFlag(LevelStatusFlags.LevelStatus.NewTopLevel) && _colorStatus != LevelStatusFlags.LevelStatus.Neutral) { generalStatus = _colorStatus; } @@ -32,7 +33,7 @@ public void SetStatsAnalysis(LevelStatus statsStatus, string statsAnalysis) /// /// Set the color status and uses the earlier set statsStatus. /// - public void SetColorAnalysis(LevelStatus colorStatus, string colorAnalysis) + public void SetColorAnalysis(LevelStatusFlags.LevelStatus colorStatus, string colorAnalysis) { _colorStatus = colorStatus; SetStatus(LbColorStatus, colorStatus); @@ -40,7 +41,7 @@ public void SetColorAnalysis(LevelStatus colorStatus, string colorAnalysis) LbColorAnalysis.Text = colorAnalysis; var generalStatus = _statsStatus; - if (generalStatus != LevelStatus.NewTopLevel && colorStatus != LevelStatus.Neutral) + if (generalStatus != LevelStatusFlags.LevelStatus.NewTopLevel && colorStatus != LevelStatusFlags.LevelStatus.Neutral) { generalStatus = colorStatus; } @@ -48,36 +49,36 @@ public void SetColorAnalysis(LevelStatus colorStatus, string colorAnalysis) SetStatus(LbIcon, generalStatus, LbConclusion); } - private void SetStatus(Label labelIcon, LevelStatus status, Label labelText = null) + private void SetStatus(Label labelIcon, LevelStatusFlags.LevelStatus status, Label labelText = null) { - switch (status) + if (status.HasFlag(LevelStatusFlags.LevelStatus.NewTopLevel)) { - case LevelStatus.TopLevel: - labelIcon.BackColor = Color.LightGreen; - labelIcon.ForeColor = Color.DarkGreen; - labelIcon.Text = "✓"; - if (labelText != null) - labelText.Text = "Keep this creature!"; - break; - case LevelStatus.NewTopLevel: - labelIcon.BackColor = Color.LightYellow; - labelIcon.ForeColor = Color.Gold; - labelIcon.Text = "★"; - if (labelText != null) - labelText.Text = "Keep this creature, it adds new traits to your library!"; - break; - default: - labelIcon.BackColor = Color.LightGray; - labelIcon.ForeColor = Color.Gray; - labelIcon.Text = "-"; - if (labelText != null) - labelText.Text = "This creature adds nothing new to your library."; - break; + labelIcon.BackColor = Color.LightYellow; + labelIcon.ForeColor = Color.Gold; + labelIcon.Text = "★"; + if (labelText != null) + labelText.Text = "Keep this creature, it adds new traits to your library!"; + } + else if (status.HasFlag(LevelStatusFlags.LevelStatus.TopLevel)) + { + labelIcon.BackColor = Color.LightGreen; + labelIcon.ForeColor = Color.DarkGreen; + labelIcon.Text = "✓"; + if (labelText != null) + labelText.Text = "Keep this creature!"; + } + else + { + labelIcon.BackColor = Color.LightGray; + labelIcon.ForeColor = Color.Gray; + labelIcon.Text = "-"; + if (labelText != null) + labelText.Text = "This creature adds nothing new to your library."; } } /// - /// Colors are not cleared, they are set independently from the stats if the colors are changed. + /// Colors are not cleared, they are set independent of the stats if the colors are changed. /// public void Clear() { diff --git a/ARKBreedingStats/uiControls/MyColorPicker.cs b/ARKBreedingStats/uiControls/MyColorPicker.cs index fbd865823..2cc3edbce 100644 --- a/ARKBreedingStats/uiControls/MyColorPicker.cs +++ b/ARKBreedingStats/uiControls/MyColorPicker.cs @@ -29,10 +29,7 @@ public MyColorPicker() BtNoColor.Text = Loc.S("noColor"); LbAlternativeColor.Text = Loc.S("LbAlternativeColor"); _tt.SetToolTip(BtNoColor, "0: no color"); - - BtUndefinedColor.Tag = Ark.UndefinedColorId; // one possible id of undefined color, currently used by Ark - _tt.SetToolTip(BtUndefinedColor, $"{Ark.UndefinedColorId}: undefined color"); - + SetUndefinedColorId(); buttonCancel.Text = Loc.S("Cancel"); Disposed += MyColorPicker_Disposed; @@ -48,6 +45,12 @@ private void MyColorPicker_Disposed(object sender, EventArgs e) _tt.Dispose(); } + public void SetUndefinedColorId() + { + BtUndefinedColor.Tag = Ark.UndefinedColorId; // one possible id of undefined color, currently used by Ark + _tt.SetToolTip(BtUndefinedColor, $"{Ark.UndefinedColorId}: undefined color"); + } + /// /// Clears color buttons. Call if color definitions changed, e.g. when a mod with colors is loaded or unloaded. /// @@ -60,6 +63,7 @@ private void ResetColors() c.Dispose(); } flowLayoutPanel1.Controls.Clear(); + SetUndefinedColorId(); } public void PickColor(byte selectedColorId, string headerText, List naturalColors = null, byte selectedColorIdAlternative = 0) diff --git a/ARKBreedingStats/uiControls/PopupMessage.cs b/ARKBreedingStats/uiControls/PopupMessage.cs new file mode 100644 index 000000000..daad7823d --- /dev/null +++ b/ARKBreedingStats/uiControls/PopupMessage.cs @@ -0,0 +1,56 @@ +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace ARKBreedingStats.uiControls +{ + internal class PopupMessage : Form + { + private Label _label; + + public PopupMessage() + { + Width = 500; + Height = 400; + FormBorderStyle = FormBorderStyle.None; + ShowInTaskbar = false; + BackColor = Color.LightGray; + Padding = new Padding(2); + StartPosition = FormStartPosition.CenterParent; + + var lClose = new Label + { + Text = Loc.S("click to close"), + Dock = DockStyle.Bottom, + TextAlign = ContentAlignment.MiddleCenter, + BackColor = Color.LightSalmon + }; + Controls.Add(lClose); + lClose.Click += CloseClick; + + _label = new Label + { + Dock = DockStyle.Fill, + ForeColor = Color.Gainsboro, + BackColor = Color.Black, + TextAlign = ContentAlignment.MiddleCenter + }; + Controls.Add(_label); + _label.Click += CloseClick; + } + + public PopupMessage(string message, float fontSize = 8.25f) : this() + { + if (fontSize != 8.25f) + _label.Font = new Font(_label.Font.FontFamily, fontSize); + _label.Text = message; + } + + public static void Show(Form parent, string message, float fontSize = 8.25f) + { + new PopupMessage(message, fontSize).ShowDialog(parent); + } + + private void CloseClick(object sender, EventArgs e) => Close(); + } +} diff --git a/ARKBreedingStats/uiControls/StatIO.Designer.cs b/ARKBreedingStats/uiControls/StatIO.Designer.cs index 2de2bc5f3..3cd396701 100644 --- a/ARKBreedingStats/uiControls/StatIO.Designer.cs +++ b/ARKBreedingStats/uiControls/StatIO.Designer.cs @@ -1,4 +1,4 @@ -namespace ARKBreedingStats +namespace ARKBreedingStats.uiControls { partial class StatIO { diff --git a/ARKBreedingStats/uiControls/StatIO.cs b/ARKBreedingStats/uiControls/StatIO.cs index 728364f63..f0110925c 100644 --- a/ARKBreedingStats/uiControls/StatIO.cs +++ b/ARKBreedingStats/uiControls/StatIO.cs @@ -3,10 +3,11 @@ using System.Windows.Forms; using System.Windows.Input; using System.Windows.Threading; +using ARKBreedingStats.library; using ARKBreedingStats.utils; using Cursors = System.Windows.Forms.Cursors; -namespace ARKBreedingStats +namespace ARKBreedingStats.uiControls { public partial class StatIO : UserControl { @@ -188,43 +189,44 @@ public StatIOStatus Status } } - private LevelStatus _topLevel; - public LevelStatus TopLevel + private LevelStatusFlags.LevelStatus _topLevel; + public LevelStatusFlags.LevelStatus TopLevel { get => _topLevel; set { + if (_topLevel == value) return; _topLevel = value; - if (_topLevel == LevelStatus.Neutral) + if (_topLevel == LevelStatusFlags.LevelStatus.Neutral) { labelWildLevel.BackColor = Color.Transparent; _tt.SetToolTip(labelWildLevel, null); return; } - if (_topLevel.HasFlag(LevelStatus.TopLevel)) + if (_topLevel.HasFlag(LevelStatusFlags.LevelStatus.TopLevel)) { labelWildLevel.BackColor = Color.LightGreen; _tt.SetToolTip(labelWildLevel, Loc.S("topLevel")); } - else if (_topLevel.HasFlag(LevelStatus.NewTopLevel)) + else if (_topLevel.HasFlag(LevelStatusFlags.LevelStatus.NewTopLevel)) { labelWildLevel.BackColor = Color.Gold; _tt.SetToolTip(labelWildLevel, Loc.S("newTopLevel")); } - if (_topLevel.HasFlag(LevelStatus.MaxLevelForLevelUp)) + if (_topLevel.HasFlag(LevelStatusFlags.LevelStatus.MaxLevelForLevelUp)) { labelWildLevel.BackColor = Color.DeepSkyBlue; _tt.SetToolTip(labelWildLevel, Loc.S("maxLevelForLevelUp")); } - else if (_topLevel.HasFlag(LevelStatus.MaxLevel)) + else if (_topLevel.HasFlag(LevelStatusFlags.LevelStatus.MaxLevel)) { labelWildLevel.BackColor = Color.Orange; _tt.SetToolTip(labelWildLevel, Loc.S("maxLevelSaved")); } - else if (_topLevel.HasFlag(LevelStatus.UltraMaxLevel)) + else if (_topLevel.HasFlag(LevelStatusFlags.LevelStatus.UltraMaxLevel)) { labelWildLevel.BackColor = Color.LightCoral; _tt.SetToolTip(labelWildLevel, Loc.S("ultraMaxLevel")); @@ -267,7 +269,7 @@ public bool IsActive public void Clear() { Status = StatIOStatus.Neutral; - TopLevel = LevelStatus.Neutral; + TopLevel = LevelStatusFlags.LevelStatus.Neutral; numLvW.Value = 0; nudLvM.Value = 0; numLvD.Value = 0; @@ -280,18 +282,7 @@ public void Clear() private void numLvW_ValueChanged(object sender, EventArgs e) { - int lengthPercentage = 100 * (int)numLvW.Value / barMaxLevel; // in percentage of the max bar width - - if (lengthPercentage > 100) - { - lengthPercentage = 100; - } - if (lengthPercentage < 0) - { - lengthPercentage = 0; - } - panelBarWildLevels.Width = lengthPercentage * MaxBarLength / 100; - panelBarWildLevels.BackColor = Utils.GetColorFromPercent(lengthPercentage); + SetLevelBar(panelBarWildLevels, numLvW.Value); _tt.SetToolTip(panelBarWildLevels, Utils.LevelPercentile((int)numLvW.Value)); if (_linkWildMutated && _wildMutatedSum != -1) @@ -305,18 +296,7 @@ private void numLvW_ValueChanged(object sender, EventArgs e) private void nudLvM_ValueChanged(object sender, EventArgs e) { - int lengthPercentage = 100 * (int)nudLvM.Value / barMaxLevel; // in percentage of the max bar width - - if (lengthPercentage > 100) - { - lengthPercentage = 100; - } - if (lengthPercentage < 0) - { - lengthPercentage = 0; - } - panelBarMutLevels.Width = lengthPercentage * MaxBarLength / 100; - panelBarMutLevels.BackColor = Utils.GetColorFromPercent(lengthPercentage); + SetLevelBar(panelBarMutLevels, nudLvM.Value); if (_linkWildMutated && _wildMutatedSum != -1) { @@ -329,23 +309,23 @@ private void nudLvM_ValueChanged(object sender, EventArgs e) private void numLvD_ValueChanged(object sender, EventArgs e) { - int lengthPercentage = 100 * (int)numLvD.Value / barMaxLevel; // in percentage of the max bar width - - if (lengthPercentage > 100) - { - lengthPercentage = 100; - } - if (lengthPercentage < 0) - { - lengthPercentage = 0; - } - panelBarDomLevels.Width = lengthPercentage * MaxBarLength / 100; - panelBarDomLevels.BackColor = Utils.GetColorFromPercent(lengthPercentage); + SetLevelBar(panelBarDomLevels, numLvD.Value); if (_inputType != StatIOInputType.FinalValueInputType) LevelChangedDebouncer(); } + private void SetLevelBar(Panel panel, decimal level) + { + var lengthPercentage = 100 * (int)level / barMaxLevel; // in percentage of the max bar width + + if (lengthPercentage > 100) lengthPercentage = 100; + else if (lengthPercentage < 0) lengthPercentage = 0; + + panel.Width = lengthPercentage * MaxBarLength / 100; + panel.BackColor = Utils.GetColorFromPercent(lengthPercentage); + } + private readonly Debouncer _levelChangedDebouncer = new Debouncer(); private void LevelChangedDebouncer() => _levelChangedDebouncer.Debounce(200, FireLevelChanged, Dispatcher.CurrentDispatcher); @@ -453,35 +433,6 @@ public enum StatIOStatus Error } - /// - /// Status of wild levels, e.g. top level, max level. - /// - [Flags] - public enum LevelStatus - { - Neutral = 0, - /// - /// wild level is equal to the current top-level - /// - TopLevel = 1, - /// - /// wild level is higher than the current top-level - /// - NewTopLevel = 2, - /// - /// Max level to apply domesticated levels. - /// - MaxLevelForLevelUp = 4, - /// - /// Max level that can be saved. - /// - MaxLevel = 8, - /// - /// Level too high to be saved, rollover will happen. - /// - UltraMaxLevel = 16 - } - public enum StatIOInputType { FinalValueInputType, diff --git a/ARKBreedingStats/uiControls/StatWeighting.cs b/ARKBreedingStats/uiControls/StatWeighting.cs index 21a2f449c..089ac36ed 100644 --- a/ARKBreedingStats/uiControls/StatWeighting.cs +++ b/ARKBreedingStats/uiControls/StatWeighting.cs @@ -385,5 +385,25 @@ private void SetState(byte state) } } } + + /// + /// Describes if a stat level is desired to be high or low or if it doesn't matter. + /// + public enum StatValuePreference + { + Indifferent, + Low, + High + } + + /// + /// Describes if a stat level should be even or odd or if it doesn't matter. + /// + public enum StatValueEvenOdd + { + Indifferent, + Odd, + Even + } } } diff --git a/ARKBreedingStats/utils/CreatureListSorter.cs b/ARKBreedingStats/utils/CreatureListSorter.cs index 0a7e44b8d..4a6ddd004 100644 --- a/ARKBreedingStats/utils/CreatureListSorter.cs +++ b/ARKBreedingStats/utils/CreatureListSorter.cs @@ -136,7 +136,7 @@ private IEnumerable OrderList(IEnumerable list, IComparer c.sex, c => c.domesticatedAt, c => c.topness, - c => c.topStatsCount, + c => c.topStatsConsideredCount, c => c.generation, c => c.levelFound, c => c.Mutations, diff --git a/ARKBreedingStats/utils/SoundFeedback.cs b/ARKBreedingStats/utils/SoundFeedback.cs index a4d9217dd..4a66f6384 100644 --- a/ARKBreedingStats/utils/SoundFeedback.cs +++ b/ARKBreedingStats/utils/SoundFeedback.cs @@ -13,10 +13,12 @@ internal enum FeedbackSounds Success, Good, Great, - Indifferent + Indifferent, + Updated, + NewMutation } - private static readonly SoundPlayer _sp = new SoundPlayer(); + private static readonly SoundPlayer Sp = new SoundPlayer(); /// /// Beeps. @@ -25,25 +27,33 @@ public static void BeepSignal(FeedbackSounds kind) { switch (kind) { + case FeedbackSounds.Updated: + Sp.Stream = Properties.Resources.updated; + Sp.Play(); + return; case FeedbackSounds.Indifferent: - _sp.Stream = Properties.Resources.indifferent; - _sp.Play(); + Sp.Stream = Properties.Resources.indifferent; + Sp.Play(); return; case FeedbackSounds.Failure: - _sp.Stream = Properties.Resources.failure; - _sp.Play(); + Sp.Stream = Properties.Resources.failure; + Sp.Play(); return; case FeedbackSounds.Success: - _sp.Stream = Properties.Resources.success; - _sp.Play(); + Sp.Stream = Properties.Resources.success; + Sp.Play(); return; case FeedbackSounds.Good: - _sp.Stream = Properties.Resources.topstat; - _sp.Play(); + Sp.Stream = Properties.Resources.topstat; + Sp.Play(); return; case FeedbackSounds.Great: - _sp.Stream = Properties.Resources.newtopstat; - _sp.Play(); + Sp.Stream = Properties.Resources.newtopstat; + Sp.Play(); + return; + case FeedbackSounds.NewMutation: + Sp.Stream = Properties.Resources.newMutation; + Sp.Play(); return; } }