diff --git a/ARKBreedingStats/CreatureInfoInput.cs b/ARKBreedingStats/CreatureInfoInput.cs index c8e8fb85..8b247356 100644 --- a/ARKBreedingStats/CreatureInfoInput.cs +++ b/ARKBreedingStats/CreatureInfoInput.cs @@ -639,7 +639,7 @@ public void SetCreatureData(Creature cr) cr.growingUntil = GrowingUntil; cr.domesticatedAt = DomesticatedAt; cr.ArkId = ArkId; - cr.InitializeArkInGame(); + cr.InitializeArkIdInGame(); } private void textBoxOwner_Leave(object sender, EventArgs e) diff --git a/ARKBreedingStats/Form1.Designer.cs b/ARKBreedingStats/Form1.Designer.cs index b809cd12..92f59f4b 100644 --- a/ARKBreedingStats/Form1.Designer.cs +++ b/ARKBreedingStats/Form1.Designer.cs @@ -1855,6 +1855,7 @@ private void InitializeComponent() // // creatureInfoInputTester // + this.creatureInfoInputTester.AlreadyExistingCreature = null; this.creatureInfoInputTester.ColorIdsAlsoPossible = null; this.creatureInfoInputTester.CooldownUntil = null; this.creatureInfoInputTester.CreatureFlags = ARKBreedingStats.Library.CreatureFlags.None; @@ -2116,6 +2117,7 @@ private void InitializeComponent() // // labelErrorHelp // + this.labelErrorHelp.AutoEllipsis = true; this.labelErrorHelp.Location = new System.Drawing.Point(642, 43); this.labelErrorHelp.Name = "labelErrorHelp"; this.labelErrorHelp.Size = new System.Drawing.Size(239, 569); @@ -2162,6 +2164,7 @@ private void InitializeComponent() // // creatureInfoInputExtractor // + this.creatureInfoInputExtractor.AlreadyExistingCreature = null; this.creatureInfoInputExtractor.ColorIdsAlsoPossible = null; this.creatureInfoInputExtractor.CooldownUntil = null; this.creatureInfoInputExtractor.CreatureFlags = ARKBreedingStats.Library.CreatureFlags.None; diff --git a/ARKBreedingStats/Form1.cs b/ARKBreedingStats/Form1.cs index 5f8cdfba..61b2e39b 100644 --- a/ARKBreedingStats/Form1.cs +++ b/ARKBreedingStats/Form1.cs @@ -788,6 +788,9 @@ private void numericUpDown_Enter(object sender, EventArgs e) /// private void ApplySettingsToValues() { + if (_creatureCollection.serverMultipliers == null) + return; // nothing to apply from, settings are loaded soon, then applied + // apply multipliers Values.V.ApplyMultipliers(_creatureCollection, cbEventMultipliers.Checked); tamingControl1.SetServerMultipliers(Values.V.currentServerMultipliers); @@ -1131,9 +1134,13 @@ private async void CheckForUpdates(bool silentCheck = false, bool selectDefaultI if (valuesUpdated) { - var statsLoaded = LoadStatAndKibbleValues(forceReload: true); + var statsLoaded = LoadStatAndKibbleValues(false, true); if (statsLoaded.statValuesLoaded) { + _creatureCollection.modListHash = 0; + ReloadModValuesOfCollectionIfNeeded(true, false, false, false); + ApplySettingsToValues(); + MessageBox.Show(Loc.S("downloadingValuesSuccess"), Loc.S("updateSuccessTitle"), MessageBoxButtons.OK, MessageBoxIcon.Information); ApplySpeciesObjectsToCollection(_creatureCollection); diff --git a/ARKBreedingStats/Form1.extractor.cs b/ARKBreedingStats/Form1.extractor.cs index 89ea89f5..db3ca08a 100644 --- a/ARKBreedingStats/Form1.extractor.cs +++ b/ARKBreedingStats/Form1.extractor.cs @@ -132,7 +132,9 @@ private void ShowSumOfChosenLevels(int levelsImpossibleToDistribute) if (levelsImpossibleToDistribute != 0 && _statIOs.All(s => s.Status != StatIOStatus.NonUnique)) { - ExtractionFailed(IssueNotes.Issue.SpeedLevelingSetting); + ExtractionFailed(IssueNotes.Issue.SpeedLevelingSetting + | IssueNotes.Issue.TamingEffectivenessRange + | IssueNotes.Issue.ImpossibleTe); } bool allValid = valid && inbound && torporLevelValid && _extractor.ValidResults; @@ -1201,7 +1203,7 @@ private Creature GetCreatureFromInput(bool fromExtractor, Species species, int? }; creature.ArkIdImported = Utils.IsArkIdImported(creature.ArkId, creature.guid); - creature.InitializeArkInGame(); + creature.InitializeArkIdInGame(); creature.InitializeFlags(); diff --git a/ARKBreedingStats/Form1.tester.cs b/ARKBreedingStats/Form1.tester.cs index 570fa0e7..5c8881da 100644 --- a/ARKBreedingStats/Form1.tester.cs +++ b/ARKBreedingStats/Form1.tester.cs @@ -263,6 +263,7 @@ private void SetTesterInfoInputCreature(Creature c = null, bool virtualCreature creatureInfoInputTester.AddedToLibraryAt = c.addedToLibrary; creatureInfoInputTester.CreatureFlags = c.flags; creatureInfoInputTester.RegionColors = c.colors; + creatureInfoInputTester.ColorIdsAlsoPossible = c.ColorIdsAlsoPossible; creatureInfoInputTester.CreatureGuid = c.guid; creatureInfoInputTester.SetArkId(c.ArkId, c.ArkIdImported); UpdateParentListInput(creatureInfoInputTester); @@ -286,6 +287,7 @@ private void SetTesterInfoInputCreature(Creature c = null, bool virtualCreature creatureInfoInputTester.AddedToLibraryAt = null; creatureInfoInputTester.CreatureFlags = CreatureFlags.None; creatureInfoInputTester.RegionColors = new byte[Ark.ColorRegionCount]; + creatureInfoInputTester.ColorIdsAlsoPossible = null; creatureInfoInputTester.CreatureGuid = Guid.Empty; creatureInfoInputTester.SetArkId(0, false); creatureInfoInputTester.MutationCounterMother = 0; @@ -340,12 +342,15 @@ private void SetRandomWildLevels(object sender, EventArgs e) if (species == null) return; var difficulty = (CreatureCollection.CurrentCreatureCollection?.maxWildLevel ?? 150) / 30; - var creature = DummyCreatures.CreateCreature(species, difficulty, false); + var creature = DummyCreatures.CreateCreature(species, difficulty, !rbWildTester.Checked); for (int si = 0; si < Stats.StatsCount; si++) { _testingIOs[si].LevelWild = creature.levelsWild[si]; } + + if (rbTamedTester.Checked) + NumericUpDownTestingTE.ValueSaveDouble = creature.tamingEff * 100; } private void pictureBoxColorRegionsTester_Click(object sender, EventArgs e) diff --git a/ARKBreedingStats/NamePatterns/NamePattern.cs b/ARKBreedingStats/NamePatterns/NamePattern.cs index 3bc64761..3a4803cf 100644 --- a/ARKBreedingStats/NamePatterns/NamePattern.cs +++ b/ARKBreedingStats/NamePatterns/NamePattern.cs @@ -338,7 +338,8 @@ public static Dictionary CreateTokenDictionary(Creature creature { "dom", dom}, { "arkid", arkid }, { "alreadyexists", speciesCreatures.Contains(creature) ? "1" : string.Empty }, - { "isflyer", creature.Species.isFlyer ? "1" : string.Empty } + { "isflyer", creature.Species.isFlyer ? "1" : string.Empty }, + { "status", creature.Status.ToString() } }; // stat index and according level diff --git a/ARKBreedingStats/NamePatterns/PatternEditor.cs b/ARKBreedingStats/NamePatterns/PatternEditor.cs index 74cbdbd6..f9662a90 100644 --- a/ARKBreedingStats/NamePatterns/PatternEditor.cs +++ b/ARKBreedingStats/NamePatterns/PatternEditor.cs @@ -490,6 +490,7 @@ private void InsertText(string text) { "arkid", "the Ark-Id (as entered or seen in-game)"}, { "alreadyExists", "returns 1 if the creature is already in the library, can be used with {{#if: }}"}, { "isFlyer", "returns 1 if the creature's species is a flyer"}, + { "status", "returns the status of the creature, e.g. Available, Obelisk, Dead"}, { "highest1l", "the highest stat-level of this creature (excluding torpidity)" }, { "highest2l", "the second highest stat-level of this creature (excluding torpidity)" }, { "highest3l", "the third highest stat-level of this creature (excluding torpidity)" }, diff --git a/ARKBreedingStats/Properties/AssemblyInfo.cs b/ARKBreedingStats/Properties/AssemblyInfo.cs index 946ad4c8..b0a195a6 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.60.3.0")] +[assembly: AssemblyFileVersion("0.60.4.0")] [assembly: NeutralResourcesLanguage("en")] diff --git a/ARKBreedingStats/_manifest.json b/ARKBreedingStats/_manifest.json index 052c57b6..0be00ed2 100644 --- a/ARKBreedingStats/_manifest.json +++ b/ARKBreedingStats/_manifest.json @@ -4,19 +4,19 @@ "ARK Smart Breeding": { "Id": "ARK Smart Breeding", "Category": "main", - "version": "0.60.3.0" + "version": "0.60.4.0" }, "SpeciesColorImages": { "Id": "SpeciesColorImages", "Category": "Species Images", "Name": "Species Images", - "Author": "cadaei and Myrmecoleon", - "Description": "Download this package to have a visualization for the colors of creatures (~20 MB), uncheck if you don't want to download these files.", + "Author": "cadaei, Myrmecoleon, coldino", + "Description": "Download this package to have a visualization for the colors of creatures (~21 MB), uncheck if you don't want to download these files.", "Url": "https://github.com/cadon/ARKStatsExtractor/raw/master/speciesImages/speciesImages.zip", "LocalPath": "images/speciesImages", "IsFolder": true, "Selectable": true, - "version": "2022.11.13" + "version": "2024.03.11" }, "NamePatternTemplates": { "Id": "NamePatternTemplates", diff --git a/ARKBreedingStats/_manifest.tt b/ARKBreedingStats/_manifest.tt index 94ff0a7f..a685701b 100644 --- a/ARKBreedingStats/_manifest.tt +++ b/ARKBreedingStats/_manifest.tt @@ -21,13 +21,13 @@ string appVersion = Regex.Match(File.ReadAllText(Host.ResolvePath("Properties/As "Id": "SpeciesColorImages", "Category": "Species Images", "Name": "Species Images", - "Author": "cadaei and Myrmecoleon", - "Description": "Download this package to have a visualization for the colors of creatures (~20 MB), uncheck if you don't want to download these files.", + "Author": "cadaei, Myrmecoleon, coldino", + "Description": "Download this package to have a visualization for the colors of creatures (~21 MB), uncheck if you don't want to download these files.", "Url": "https://github.com/cadon/ARKStatsExtractor/raw/master/speciesImages/speciesImages.zip", "LocalPath": "images/speciesImages", "IsFolder": true, "Selectable": true, - "version": "2022.11.13" + "version": "2024.03.11" }, "NamePatternTemplates": { "Id": "NamePatternTemplates", diff --git a/ARKBreedingStats/importExportGun/ExportGunServerFile.cs b/ARKBreedingStats/importExportGun/ExportGunServerFile.cs index 0ebc519c..73945777 100644 --- a/ARKBreedingStats/importExportGun/ExportGunServerFile.cs +++ b/ARKBreedingStats/importExportGun/ExportGunServerFile.cs @@ -14,7 +14,7 @@ internal class ExportGunServerFile public double[] TameAdd { get; set; } public double[] TameAff { get; set; } public double WildLevelStepSize { get; set; } - public int MaxWildLevel { get; set; } + public double MaxWildLevel { get; set; } public int DestroyTamesOverLevelClamp { get; set; } public double TamingSpeedMultiplier { get; set; } = 1; public double WildDinoTorporDrainMultiplier { get; set; } = 1; diff --git a/ARKBreedingStats/importExportGun/ImportExportGun.cs b/ARKBreedingStats/importExportGun/ImportExportGun.cs index 9bfa4e2c..009aa53e 100644 --- a/ARKBreedingStats/importExportGun/ImportExportGun.cs +++ b/ARKBreedingStats/importExportGun/ImportExportGun.cs @@ -333,7 +333,7 @@ internal static bool SetServerMultipliers(CreatureCollection cc, ExportGunServer cc.serverMultipliers.statMultipliers[s][Stats.IndexLevelWild] = Math.Round(esm.WildLevel[s], roundToDigits); cc.serverMultipliers.statMultipliers[s][Stats.IndexLevelDom] = Math.Round(esm.TameLevel[s], roundToDigits); } - cc.maxWildLevel = esm.MaxWildLevel; + cc.maxWildLevel = (int)Math.Ceiling(esm.MaxWildLevel); cc.maxServerLevel = esm.DestroyTamesOverLevelClamp; cc.serverMultipliers.TamingSpeedMultiplier = Math.Round(esm.TamingSpeedMultiplier, roundToDigits); cc.serverMultipliers.DinoCharacterFoodDrainMultiplier = Math.Round(esm.DinoCharacterFoodDrainMultiplier, roundToDigits); diff --git a/ARKBreedingStats/json/values/ASA-values.json b/ARKBreedingStats/json/values/ASA-values.json index 295a249b..6ba35e99 100644 --- a/ARKBreedingStats/json/values/ASA-values.json +++ b/ARKBreedingStats/json/values/ASA-values.json @@ -1,5 +1,5 @@ { - "version": "32.11.468631", + "version": "32.11.468632", "format": "1.15-asa", "mod": { "id": "ASA", @@ -1594,13 +1594,13 @@ "incubationTime": 5999.52004, "eggTempMin": 26, "eggTempMax": 32, - "maturationTime": 416666.667, + "maturationTime": 166666.667, "matingCooldownMin": 64800, "matingCooldownMax": 172800 }, "taming": { - "nonViolent": false, - "violent": true, + "nonViolent": true, + "violent": false, "tamingIneffectiveness": 0.06, "affinityNeeded0": 6800, "affinityIncreasePL": 160, diff --git a/ARKBreedingStats/json/values/_manifest.json b/ARKBreedingStats/json/values/_manifest.json index 74c9cab9..e79a5b82 100644 --- a/ARKBreedingStats/json/values/_manifest.json +++ b/ARKBreedingStats/json/values/_manifest.json @@ -398,7 +398,7 @@ "mod": { "id": "919470289", "tag": "SSFlyer", "title": "SSFlyer" } }, "ASA-values.json": { - "version": "32.11.468631", + "version": "32.11.468632", "format": "1.15-asa", "mod": { "id": "ASA", "tag": "", "title": "Ark: Survival Ascended", "shortTitle": "ASA" } }, @@ -407,7 +407,7 @@ "mod": { "id": "CrystalIsles", "tag": "CrystalIsles", "title": "CrystalIsles", "official": true, "expansion": true } }, "values.json": { - "version": "358.6.11410860" + "version": "358.17.12291776" } } } \ No newline at end of file diff --git a/ARKBreedingStats/json/values/values.json b/ARKBreedingStats/json/values/values.json index 4491774a..3ac99156 100644 --- a/ARKBreedingStats/json/values/values.json +++ b/ARKBreedingStats/json/values/values.json @@ -1,5 +1,5 @@ { - "version": "358.6.11410860", + "version": "358.17.12291776", "format": "1.14-flyerspeed", "species": [ { @@ -105510,11 +105510,13 @@ } ], "taming": { - "nonViolent": false, + "nonViolent": true, "violent": false, "tamingIneffectiveness": 0.9375, "affinityNeeded0": 6850, "affinityIncreasePL": 300, + "wakeAffinityMult": 1.6, + "wakeFoodDeplMult": 2, "foodConsumptionBase": 0.001543, "foodConsumptionMult": 216.0294, "babyFoodConsumptionMult": 510 diff --git a/ARKBreedingStats/library/AddDummyCreaturesSettings.cs b/ARKBreedingStats/library/AddDummyCreaturesSettings.cs index 56e06cc0..85a45a30 100644 --- a/ARKBreedingStats/library/AddDummyCreaturesSettings.cs +++ b/ARKBreedingStats/library/AddDummyCreaturesSettings.cs @@ -38,6 +38,13 @@ private void BtOk_Click(object sender, EventArgs e) { if (NudAmount.Value > 0) { + if (NudAmount.Value > 1000 + && NudBreedForGenerations.Value > 0 + && MessageBox.Show("Adding many creatures and simulate breeding may take a long time. Continue?", + "Continue possible lengthy action?", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) + != DialogResult.Yes) + return; + DialogResult = DialogResult.OK; Settings = new DummyCreatureCreationSettings { diff --git a/ARKBreedingStats/library/Creature.cs b/ARKBreedingStats/library/Creature.cs index b06215bb..a397ecc9 100644 --- a/ARKBreedingStats/library/Creature.cs +++ b/ARKBreedingStats/library/Creature.cs @@ -570,7 +570,7 @@ public double Maturation [OnDeserialized] private void Initialize(StreamingContext ct) { - InitializeArkInGame(); + InitializeArkIdInGame(); if (flags.HasFlag(CreatureFlags.Placeholder)) return; InitializeArrays(); } @@ -578,7 +578,7 @@ private void Initialize(StreamingContext ct) /// /// Set the string of ArkIdInGame depending on the real ArkId or the user input number. /// - internal void InitializeArkInGame() => ArkIdInGame = ArkIdImported ? Utils.ConvertImportedArkIdToIngameVisualization(ArkId) : ArkId.ToString(); + internal void InitializeArkIdInGame() => ArkIdInGame = ArkIdImported ? Utils.ConvertImportedArkIdToIngameVisualization(ArkId) : ArkId.ToString(); private void InitializeArrays() { diff --git a/ARKBreedingStats/library/CreatureCollection.cs b/ARKBreedingStats/library/CreatureCollection.cs index 0f9dfc94..bba69d7c 100644 --- a/ARKBreedingStats/library/CreatureCollection.cs +++ b/ARKBreedingStats/library/CreatureCollection.cs @@ -59,8 +59,12 @@ public class CreatureCollection [JsonProperty] public ServerMultipliers serverMultipliers; + + /// + /// Only the taming and breeding multipliers of this are used. + /// [JsonProperty] - public ServerMultipliers serverMultipliersEvents; // only the taming and breeding multipliers of this are used + public ServerMultipliers serverMultipliersEvents; /// /// Deprecated setting, remove on 2025-01-01 diff --git a/ARKBreedingStats/oldLibraryFormat/FormatConverter.cs b/ARKBreedingStats/oldLibraryFormat/FormatConverter.cs index 2b2846b2..e2b141b4 100644 --- a/ARKBreedingStats/oldLibraryFormat/FormatConverter.cs +++ b/ARKBreedingStats/oldLibraryFormat/FormatConverter.cs @@ -114,7 +114,7 @@ public static void UpgradeFormatTo12Stats(CreatureCollectionOld ccOld, CreatureC tamingEff = c.tamingEff, tribe = c.tribe }; - newC.InitializeArkInGame(); + newC.InitializeArkIdInGame(); ccNew.creatures.Add(newC); if (c.IsPlaceholder) newC.flags |= CreatureFlags.Placeholder; diff --git a/ARKBreedingStats/settings/Settings.cs b/ARKBreedingStats/settings/Settings.cs index 33a9558e..a604fd10 100644 --- a/ARKBreedingStats/settings/Settings.cs +++ b/ARKBreedingStats/settings/Settings.cs @@ -844,10 +844,10 @@ private void ExtractSettingsFromText(string text, bool doMergeSettings = false) for (int s = 0; s < Stats.StatsCount; s++) { - ParseAndSetStatMultiplier(0, @"PerLevelStatsMultiplier_DinoTamed_Add\[" + s + @"\] ?= ?(\d*\.?\d+)"); - ParseAndSetStatMultiplier(1, @"PerLevelStatsMultiplier_DinoTamed_Affinity\[" + s + @"\] ?= ?(\d*\.?\d+)"); - ParseAndSetStatMultiplier(2, @"PerLevelStatsMultiplier_DinoTamed\[" + s + @"\] ?= ?(\d*\.?\d+)"); - ParseAndSetStatMultiplier(3, @"PerLevelStatsMultiplier_DinoWild\[" + s + @"\] ?= ?(\d*\.?\d+)"); + ParseAndSetStatMultiplier(Stats.IndexTamingAdd, @"PerLevelStatsMultiplier_DinoTamed_Add\[" + s + @"\] ?= ?(\d*\.?\d+)"); + ParseAndSetStatMultiplier(Stats.IndexTamingMult, @"PerLevelStatsMultiplier_DinoTamed_Affinity\[" + s + @"\] ?= ?(\d*\.?\d+)"); + ParseAndSetStatMultiplier(Stats.IndexLevelDom, @"PerLevelStatsMultiplier_DinoTamed\[" + s + @"\] ?= ?(\d*\.?\d+)"); + ParseAndSetStatMultiplier(Stats.IndexLevelWild, @"PerLevelStatsMultiplier_DinoWild\[" + s + @"\] ?= ?(\d*\.?\d+)"); void ParseAndSetStatMultiplier(int multiplierIndex, string regexPattern) { @@ -859,6 +859,9 @@ void ParseAndSetStatMultiplier(int multiplierIndex, string regexPattern) } } } + // some server files have a different value for wild level torpor increase, but ARK ignores that value. + // reset that value, so no error message pops up, so user is not confused. Error message only on manual input + _multSetter[Stats.Torpidity].SetMultiplier(Stats.IndexLevelWild, 1); // breeding ParseAndSetValue(nudMatingInterval, @"MatingIntervalMultiplier ?= ?(\d*\.?\d+)"); @@ -971,13 +974,17 @@ private void LoadServerMultipliersFromSavFile(string filePath) const int roundToDigits = 6; for (int s = 0; s < Stats.StatsCount; s++) { - _multSetter[s].SetMultiplier(0, Math.Round(esm.TameAdd[s], roundToDigits)); - _multSetter[s].SetMultiplier(1, Math.Round(esm.TameAff[s], roundToDigits)); - _multSetter[s].SetMultiplier(2, Math.Round(esm.TameLevel[s], roundToDigits)); - _multSetter[s].SetMultiplier(3, Math.Round(esm.WildLevel[s], roundToDigits)); + _multSetter[s].SetMultiplier(Stats.IndexTamingAdd, Math.Round(esm.TameAdd[s], roundToDigits)); + _multSetter[s].SetMultiplier(Stats.IndexTamingMult, Math.Round(esm.TameAff[s], roundToDigits)); + _multSetter[s].SetMultiplier(Stats.IndexLevelDom, Math.Round(esm.TameLevel[s], roundToDigits)); + _multSetter[s].SetMultiplier(Stats.IndexLevelWild, Math.Round(esm.WildLevel[s], roundToDigits)); } + // some server files have a different value for wild level torpor increase, but ARK ignores that value. + // reset that value, so no error message pops up, so user is not confused. Error message only on manual input + _multSetter[Stats.Torpidity].SetMultiplier(Stats.IndexLevelWild, 1); - nudMaxWildLevels.ValueSave = esm.MaxWildLevel; + nudMaxWildLevels.ValueSaveDouble = Math.Ceiling(esm.MaxWildLevel); + nudWildLevelStep.ValueSaveDouble = Math.Round(esm.WildLevelStepSize, roundToDigits); nudMaxServerLevel.ValueSave = esm.DestroyTamesOverLevelClamp; nudTamingSpeed.ValueSaveDouble = Math.Round(esm.TamingSpeedMultiplier, roundToDigits); nudDinoCharacterFoodDrain.ValueSaveDouble = Math.Round(esm.DinoCharacterFoodDrainMultiplier, roundToDigits); diff --git a/ARKBreedingStats/uiControls/ColorPickerControl.cs b/ARKBreedingStats/uiControls/ColorPickerControl.cs index e3d61f86..d93a2376 100644 --- a/ARKBreedingStats/uiControls/ColorPickerControl.cs +++ b/ARKBreedingStats/uiControls/ColorPickerControl.cs @@ -216,6 +216,10 @@ private void ColorChosen(object sender, EventArgs e) } SelectedColorId = (byte)((Button)sender).Tag; + // if selected color was alternative selected color, remove alternative color + if (SelectedColorId == SelectedColorIdAlternative) + SelectedColorIdAlternative = 0; + if (sender is NoPaddingButton bts) { _buttonSelectedColor = bts; diff --git a/ARKBreedingStats/uiControls/LibraryInfo.cs b/ARKBreedingStats/uiControls/LibraryInfo.cs index c4fcfba3..8ea22dc3 100644 --- a/ARKBreedingStats/uiControls/LibraryInfo.cs +++ b/ARKBreedingStats/uiControls/LibraryInfo.cs @@ -15,7 +15,12 @@ internal static class LibraryInfo private static Species _infoForSpecies; private static bool _libraryFilterConsidered; private static string _speciesInfo; + /// + /// All color ids existing for this species per region. + /// public static readonly HashSet[] ColorsExistPerRegion = new HashSet[Ark.ColorRegionCount]; + public static readonly HashSet ColorsExistInAllRegions = new HashSet(); + public static readonly HashSet ColorsExistInAllUsedRegions = new HashSet(); /// /// Clear the cached information. @@ -60,6 +65,13 @@ internal static bool SetColorInfo(Species species, IList creatures, bo properties[flag] = 0; var creatureCount = 0; + var regionsUsed = _infoForSpecies.colors?.Select(r => !string.IsNullOrEmpty(r?.name)).ToArray() + ?? Enumerable.Repeat(true, Ark.ColorRegionCount).ToArray(); + var speciesUsesAllRegions = regionsUsed.All(u => u); + + var creaturesEqualColors = new List<(Creature, byte)>(); + var creaturesUsedEqualColors = new List<(Creature, byte)>(); + foreach (var cr in creatures) { if (cr.speciesBlueprint != species.blueprintPath @@ -68,21 +80,44 @@ internal static bool SetColorInfo(Species species, IList creatures, bo || cr.colors == null) continue; + var allColorsEqual = -1; + var allUsedRegionColorsEqual = -1; + creatureCount++; - for (var ci = 0; ci < Ark.ColorRegionCount; ci++) + for (var ri = 0; ri < Ark.ColorRegionCount; ri++) { - var co = cr.colors[ci]; - if (ColorsExistPerRegion[ci].Contains(co)) continue; - ColorsExistPerRegion[ci].Add(co); - colorsDontExistPerRegion[ci].Remove(co); + var co = cr.colors[ri]; + + if (allColorsEqual == -1) + allColorsEqual = co; + else if (allColorsEqual != co) + allColorsEqual = -2; + + if (!speciesUsesAllRegions && regionsUsed[ri]) + { + if (allUsedRegionColorsEqual == -1) + allUsedRegionColorsEqual = co; + else if (allUsedRegionColorsEqual != co) + allUsedRegionColorsEqual = -2; + } + + if (ColorsExistPerRegion[ri].Contains(co)) continue; + ColorsExistPerRegion[ri].Add(co); + colorsDontExistPerRegion[ri].Remove(co); } + if (allColorsEqual >= 0) + creaturesEqualColors.Add((cr, (byte)allColorsEqual)); + if (allUsedRegionColorsEqual >= 0) + creaturesUsedEqualColors.Add((cr, (byte)allUsedRegionColorsEqual)); + foreach (var flag in flags) { if (cr.flags.HasFlag(flag)) properties[flag]++; } } + SetColorsAvailableInAllRegions(allAvailableColorIds, regionsUsed); var sb = new StringBuilder(); var tableRow = 1; @@ -114,7 +149,7 @@ void AddParagraph(string text, string suffixForPlainText = null, bool bold = fal AddParagraph( $"{creatureCount} creatures. {string.Join(", ", properties.Where(p => p.Value > 0).Select(p => $"{Loc.S(p.Key.ToString())}: {p.Value}"))}", "\n"); - AddParagraph($"Color information", null, true, 1.3f); + AddParagraph("Color information", null, true, 1.3f); var rangeSb = new StringBuilder(); for (int i = 0; i < Ark.ColorRegionCount; i++) @@ -129,6 +164,44 @@ void AddParagraph(string text, string suffixForPlainText = null, bool bold = fal AddParagraph(CreateNumberRanges(colorsDontExistPerRegion[i]), "\n"); } + var regionsUsedList = string.Join(", ", regionsUsed.Select((used, ri) => (used, ri)).Where(r => r.used) + .Select(r => r.ri)); + if (string.IsNullOrEmpty(regionsUsedList)) + regionsUsedList = "species uses no region"; + if (!speciesUsesAllRegions && ColorsExistInAllUsedRegions.Any()) + { + AddParagraph($"These colors exist in all regions the {_infoForSpecies.name} uses ({regionsUsedList})", bold: true, relativeFontSize: 1.1f); + AddParagraph("(not necessarily in one creature combined)"); + AddParagraph(CreateNumberRanges(ColorsExistInAllUsedRegions)); + } + + if (ColorsExistInAllRegions.Any()) + { + AddParagraph("These colors exist in all regions", bold: true, relativeFontSize: 1.1f); + AddParagraph("(not necessarily in one creature combined)"); + AddParagraph(CreateNumberRanges(ColorsExistInAllRegions)); + } + + if (!speciesUsesAllRegions && creaturesUsedEqualColors.Any()) + { + AddParagraph($"These colors exist in all regions the {_infoForSpecies.name} uses ({regionsUsedList}) in a single creature", bold: true, relativeFontSize: 1.1f); + AddParagraph("For each of these colors there's a creature that only has that color in the used regions: " + + CreateNumberRanges(creaturesUsedEqualColors.Select(cc => cc.Item2).ToHashSet())); + AddParagraph(string.Join(Environment.NewLine, + creaturesUsedEqualColors.GroupBy(cc => cc.Item2).OrderBy(g => g.Key) + .Select(g => $"{g.Key}: {string.Join(", ", g.Select(c => c.Item1.name))}"))); + } + + if (creaturesEqualColors.Any()) + { + AddParagraph("These colors exist in all regions in a single creature", bold: true, relativeFontSize: 1.1f); + AddParagraph("For each of these colors there's a creature that only has that color in all regions: " + + CreateNumberRanges(creaturesEqualColors.Select(cc => cc.Item2).ToHashSet())); + AddParagraph(string.Join(Environment.NewLine, + creaturesEqualColors.GroupBy(cc => cc.Item2).OrderBy(g => g.Key) + .Select(g => $"{g.Key}: {string.Join(", ", g.Select(c => c.Item1.name))}"))); + } + string CreateNumberRanges(HashSet numbers) { var count = numbers.Count; @@ -177,5 +250,42 @@ string CreateNumberRanges(HashSet numbers) tlp?.ResumeLayout(); return true; } + + /// + /// Stores color ids that are available in all (used) regions in creatures of the species. + /// + /// + /// + private static void SetColorsAvailableInAllRegions(byte[] allAvailableColorIds, bool[] regionsUsed) + { + ColorsExistInAllRegions.Clear(); + ColorsExistInAllUsedRegions.Clear(); + + if (!ColorsExistPerRegion.Any(r => r.Any())) return; + + foreach (var colorId in allAvailableColorIds) + { + var inAllRegions = true; + var inAllUsedRegions = true; + var speciesUsesAnyRegion = false; + for (int r = 0; r < Ark.ColorRegionCount; r++) + { + var inThisRegion = ColorsExistPerRegion[r].Contains(colorId); + inAllRegions = inAllRegions && inThisRegion; + if (regionsUsed[r]) + { + speciesUsesAnyRegion = true; + if (inThisRegion) continue; + inAllUsedRegions = false; + break; + } + } + + if (inAllRegions) + ColorsExistInAllRegions.Add(colorId); + if (inAllUsedRegions && speciesUsesAnyRegion) + ColorsExistInAllUsedRegions.Add(colorId); + } + } } } diff --git a/ARKBreedingStats/uiControls/LibraryInfoControl.cs b/ARKBreedingStats/uiControls/LibraryInfoControl.cs index ff955f24..7cef2e3e 100644 --- a/ARKBreedingStats/uiControls/LibraryInfoControl.cs +++ b/ARKBreedingStats/uiControls/LibraryInfoControl.cs @@ -1,5 +1,6 @@ using System; using System.Drawing; +using System.Linq; using System.Windows.Forms; using ARKBreedingStats.Library; using ARKBreedingStats.species; @@ -46,6 +47,8 @@ private void InitializeControls() _tlbMain.Controls.Add(TlpColorInfoText, 0, 0); _tlbMain.SetRowSpan(TlpColorInfoText, 2); + const int buttonsTotalWidth = 444; + const int buttonMargins = 6; // color region buttons var flpButtons = new FlowLayoutPanel { Dock = DockStyle.Fill, Height = 180 }; _colorRegionButtons = new Button[Ark.ColorRegionCount]; @@ -56,7 +59,7 @@ private void InitializeControls() Text = i.ToString(), TextAlign = ContentAlignment.MiddleCenter, Tag = i, - Width = 142, + Width = buttonsTotalWidth / 3 - buttonMargins, Height = 70 }; _colorRegionButtons[i] = bt; @@ -68,7 +71,7 @@ private void InitializeControls() { Text = Loc.S("Clear"), TextAlign = ContentAlignment.MiddleCenter, - Width = 142, + Width = buttonsTotalWidth / 4 - buttonMargins, Height = 25 }; colorsButton.Click += ButtonClearColorsClick; @@ -78,17 +81,28 @@ private void InitializeControls() { Text = Loc.S("Random natural"), TextAlign = ContentAlignment.MiddleCenter, - Width = 142, + Width = buttonsTotalWidth / 4 - buttonMargins, Height = 25 }; colorsButton.Click += ButtonRandomNaturalColorsClick; flpButtons.Controls.Add(colorsButton); + colorsButton = new Button + { + Text = Loc.S("Random library"), + TextAlign = ContentAlignment.MiddleCenter, + Width = buttonsTotalWidth / 4 - buttonMargins, + Height = 25 + }; + _tt.SetToolTip(colorsButton, "Random colors available in the library"); + colorsButton.Click += ButtonRandomLibraryColorsClick; + flpButtons.Controls.Add(colorsButton); + colorsButton = new Button { Text = Loc.S("Random"), TextAlign = ContentAlignment.MiddleCenter, - Width = 142, + Width = buttonsTotalWidth / 4 - buttonMargins, Height = 25 }; colorsButton.Click += ButtonRandomColorsClick; @@ -103,6 +117,9 @@ private void InitializeControls() _tlbMain.Controls.Add(_speciesPictureBox, 2, 0); _tlbMain.SetRowSpan(_speciesPictureBox, 2); + + _speciesPictureBox.Click += _speciesPictureBoxClick; + _tt.SetToolTip(_speciesPictureBox, "Click to copy image to the clipboard"); } private void ButtonClearColorsClick(object sender, EventArgs e) @@ -115,6 +132,23 @@ private void ButtonRandomNaturalColorsClick(object sender, EventArgs e) SetColors(_species?.RandomSpeciesColors()); } + /// + /// Set to random colors available in the library + /// + private void ButtonRandomLibraryColorsClick(object sender, EventArgs e) + { + var colorIds = new byte[Ark.ColorRegionCount]; + var rand = new Random(); + for (int ri = 0; ri < Ark.ColorRegionCount; ri++) + { + var colorsInRegion = LibraryInfo.ColorsExistPerRegion?[ri]?.ToArray(); + var colorsCountInRegion = colorsInRegion?.Length ?? 0; + if (colorsCountInRegion == 0) continue; + colorIds[ri] = colorsInRegion[rand.Next(colorsCountInRegion)]; + } + SetColors(colorIds); + } + private void ButtonRandomColorsClick(object sender, EventArgs e) { SetColors(Values.V.Colors.GetRandomColors()); @@ -175,5 +209,11 @@ public void UpdateCreatureImage() // todo button for gender _speciesPictureBox.SetImageAndDisposeOld(CreatureColored.GetColoredCreature(_selectedColors, _species, _species.EnabledColorRegions, ColoredCreatureSize, onlyImage: true, creatureSex: Sex.Male)); } + + private void _speciesPictureBoxClick(object sender, EventArgs e) + { + if (_speciesPictureBox.Image == null) return; + Clipboard.SetImage(_speciesPictureBox.Image); + } } } diff --git a/ARKBreedingStats/values/Values.cs b/ARKBreedingStats/values/Values.cs index 3735e56f..181ac810 100644 --- a/ARKBreedingStats/values/Values.cs +++ b/ARKBreedingStats/values/Values.cs @@ -498,8 +498,10 @@ public void ApplyMultipliers(CreatureCollection cc, bool eventMultipliers = fals currentServerMultipliers.FixZeroValues(); double[] defaultMultipliers = new double[] { 1, 1, 1, 1 }; // used if serverMultipliers don't specify non-default values - var allowSpeedLeveling = cc.serverMultipliers.AllowSpeedLeveling || cc.Game != Ark.Asa; - var allowFlyerSpeedLeveling = cc.serverMultipliers.AllowFlyerSpeedLeveling; + // server multipliers for all multipliers except taming and breeding + var serverMultipliersNonBreedingTaming = cc.serverMultipliers ?? V.serverMultipliersPresets.GetPreset(ServerMultipliersPresets.Official); + var allowSpeedLeveling = serverMultipliersNonBreedingTaming.AllowSpeedLeveling || cc.Game != Ark.Asa; + var allowFlyerSpeedLeveling = serverMultipliersNonBreedingTaming.AllowFlyerSpeedLeveling; foreach (Species sp in species) { diff --git a/speciesImages/speciesImages.zip b/speciesImages/speciesImages.zip index 6c6eb920..3e2208b2 100644 Binary files a/speciesImages/speciesImages.zip and b/speciesImages/speciesImages.zip differ