/// <summary> /// Resolves the naming-pattern functions /// </summary> /// <returns></returns> private static string ResolveFunction(Match m, NamePatternParameters parameters) { // function parameters can be non numeric if numbers are parsed try { if (!parameters.ProcessNumberField && m.Groups[2].Value.Contains("{n}")) { return(m.Groups[0].Value); } return(NamePatternFunctions.ResolveFunction(m, parameters)); } catch (Exception ex) { MessageBoxes.ExceptionMessageBox(ex, $"The syntax of the following pattern function\n{m.Groups[0].Value}\ncannot be processed and will be ignored.", "Naming pattern function error"); } return(string.Empty); }
/// <summary> /// Generate a creature name with the naming pattern. /// </summary> public static string GenerateCreatureName(Creature creature, Creature[] sameSpecies, int[] speciesTopLevels, int[] speciesLowestLevels, Dictionary <string, string> customReplacings, bool showDuplicateNameWarning, int namingPatternIndex, bool showTooLongWarning = true, string pattern = null, bool displayError = true, Dictionary <string, string> tokenDictionary = null) { var creatureNames = sameSpecies?.Where(c => c.guid != creature.guid).Select(x => x.name).ToArray() ?? new string[0]; if (pattern == null) { if (namingPatternIndex == -1) { pattern = string.Empty; } else { pattern = Properties.Settings.Default.NamingPatterns?[namingPatternIndex] ?? string.Empty; } } if (creature.topness == 0) { if (speciesTopLevels == null) { creature.topness = 1000; } else { int topLevelSum = 0; int creatureLevelSum = 0; for (int s = 0; s < Values.STATS_COUNT; s++) { if (s != (int)StatNames.Torpidity && creature.Species.UsesStat(s) && (Properties.Settings.Default.consideredStats & (1 << s)) != 0 ) { int creatureLevel = Math.Max(0, creature.levelsWild[s]); topLevelSum += Math.Max(creatureLevel, speciesTopLevels[s]); creatureLevelSum += creatureLevel; } } if (topLevelSum != 0) { creature.topness = (short)(creatureLevelSum * 1000f / topLevelSum); } else { creature.topness = 1000; } } if (tokenDictionary != null) { tokenDictionary["topPercent"] = (creature.topness / 10f).ToString(); } } if (tokenDictionary == null) { tokenDictionary = CreateTokenDictionary(creature, sameSpecies, speciesTopLevels, speciesLowestLevels); } // first resolve keys, then functions string name = ResolveFunctions( ResolveKeysToValues(tokenDictionary, pattern.Replace("\r", string.Empty).Replace("\n", string.Empty)), creature, customReplacings, displayError, false); if (name.Contains("{n}")) { // replace the unique number key with the lowest possible positive number >= 1 to get a unique name. string numberedUniqueName; string lastNumberedUniqueName = null; int n = 1; do { numberedUniqueName = ResolveFunctions( ResolveKeysToValues(tokenDictionary, name, n++), creature, customReplacings, displayError, true); // check if numberedUniqueName actually is different, else break the potentially infinite loop. E.g. it is not different if {n} is an unreached if branch or was altered with other functions if (numberedUniqueName == lastNumberedUniqueName) { break; } lastNumberedUniqueName = numberedUniqueName; } while (creatureNames.Contains(numberedUniqueName, StringComparer.OrdinalIgnoreCase)); name = numberedUniqueName; } // evaluate escaped characters name = NamePatternFunctions.UnEscapeSpecialCharacters(name.Replace(PipeEscapeSequence, "|")); if (showDuplicateNameWarning && creatureNames.Contains(name, StringComparer.OrdinalIgnoreCase)) { MessageBox.Show($"The generated name for the creature\n{name}\nalready exists in the library.\n\nConsider adding {{n}} or {{sn}} in the pattern to generate unique names.", "Name already exists", MessageBoxButtons.OK, MessageBoxIcon.Warning); } else if (showTooLongWarning && name.Length > 24) { MessageBox.Show("The generated name is longer than 24 characters, the name will look like this in game:\n" + name.Substring(0, 24), "Name too long for game", MessageBoxButtons.OK, MessageBoxIcon.Warning); } return(name); }