public static bool Prefix(CharacterInspectionScreen __instance, InputCommands.Id command)
        {
            switch (command)
            {
            // Handle 'E' for 'Export'
            case InputCommands.Id.RotateCCW:
                SaveCharacter();
                break;
            }

            return(true);

            void SaveCharacter()
            {
                var rulesetEntityService = ServiceRepository.GetService <IRulesetEntityService>();

                using (var logger = new MethodLogger("CharacterInspectionScreen_HandleInput"))
                {
                    var heroCharacter = __instance.InspectedCharacter.RulesetCharacterHero;

                    // record current name, etc..
                    var name    = heroCharacter.Name;
                    var builtin = heroCharacter.BuiltIn;
                    var guid    = heroCharacter.Guid;

                    // record current conditions, powers, spells and attunements
                    var conditions     = heroCharacter.ConditionsByCategory.ToList();
                    var powers         = heroCharacter.PowersUsedByMe.ToList();
                    var spells         = heroCharacter.SpellsCastByMe.ToList();
                    var inventoryItems = new List <RulesetItem>();
                    heroCharacter.CharacterInventory.EnumerateAllItems(inventoryItems);
                    var attunedItems = inventoryItems.Select(i => new { Item = i, Name = i.AttunedToCharacter }).ToList();

                    // record item guids
                    var heroItemGuids      = heroCharacter.Items.Select(i => new { Item = i, i.Guid }).ToList();
                    var inventoryItemGuids = inventoryItems.Select(i => new { Item = i, i.Guid }).ToList();

                    try
                    {
                        // TODO: update to use convention = name-nnn.sav
                        // TODO: then need UI to allow user to change name on export
                        // For now just add EX-
                        heroCharacter.Name    = "EX-" + name;
                        heroCharacter.BuiltIn = false;

                        // remove active conditions (or filter out during serialization)
                        heroCharacter.ConditionsByCategory.Clear();

                        // remove spells and effects (or filter out during serialization)
                        heroCharacter.PowersUsedByMe.Clear();
                        heroCharacter.SpellsCastByMe.Clear();

                        // remove attunement, attuned items don't work well in the character inspection screen out of game
                        foreach (var item in attunedItems)
                        {
                            item.Item.AttunedToCharacter = string.Empty;
                        }

                        // clear guids
                        AccessTools.Field(heroCharacter.GetType(), "guid").SetValue(heroCharacter, 0UL);

                        foreach (var item in heroItemGuids)
                        {
                            AccessTools.Field(item.Item.GetType(), "guid").SetValue(item.Item, 0UL);
                        }

                        foreach (var item in inventoryItemGuids)
                        {
                            AccessTools.Field(item.Item.GetType(), "guid").SetValue(item.Item, 0UL);
                        }

                        ServiceRepository
                        .GetService <ICharacterPoolService>()
                        .SaveCharacter(heroCharacter, true);
                    }
                    finally
                    {
                        // TODO: check these things are really restored

                        // restore original values
                        heroCharacter.Name    = name;
                        heroCharacter.BuiltIn = builtin;

                        // restore conditions
                        foreach (var kvp in conditions)
                        {
                            heroCharacter.ConditionsByCategory.Add(kvp.Key, kvp.Value);
                        }

                        // restore active spells and effects
                        heroCharacter.PowersUsedByMe.AddRange(powers);
                        heroCharacter.SpellsCastByMe.AddRange(spells);

                        // restore attunement
                        foreach (var item in attunedItems)
                        {
                            item.Item.AttunedToCharacter = item.Name;
                        }

                        // restore guids
                        AccessTools.Field(heroCharacter.GetType(), "guid").SetValue(heroCharacter, guid);

                        foreach (var item in heroItemGuids)
                        {
                            AccessTools.Field(item.Item.GetType(), "guid").SetValue(item.Item, item.Guid);
                        }

                        foreach (var item in inventoryItemGuids)
                        {
                            AccessTools.Field(item.Item.GetType(), "guid").SetValue(item.Item, item.Guid);
                        }
                    }
                }
            }
        }
        public static bool Prefix(CharacterInspectionScreen __instance, InputCommands.Id command)
        {
            switch (command)
            {
            // Handle 'E' for 'Export' - probably make it ctrl-E
            case InputCommands.Id.RotateCCW:
                ExportInspectedCharacter();
                break;
            }

            return(true);

            void ExportInspectedCharacter()
            {
                // TODO: UI to allow user to supply name on export, and receive feedback if name already used

                var hero      = __instance.InspectedCharacter.RulesetCharacterHero;
                var firstName = hero.Name;
                var surName   = hero.SurName;

                // get all names in use
                var usedNames = Directory
                                .EnumerateFiles(TacticalAdventuresApplication.GameCharactersDirectory, $"*.chr")
                                .Select(f => Path.GetFileNameWithoutExtension(f))
                                .ToHashSet(StringComparer.OrdinalIgnoreCase);

                // get the available predefined names by race and sex
                var racePresentation = hero.RaceDefinition.RacePresentation;
                var availablePredefinedFirstNames = Enumerable.Empty <string>();

                switch (hero.Sex)
                {
                case RuleDefinitions.CreatureSex.Male:
                    availablePredefinedFirstNames = racePresentation
                                                    .MaleNameOptions
                                                    .Select(mn => Localize(mn))
                                                    .ToHashSet(StringComparer.OrdinalIgnoreCase)
                                                    .Except(usedNames)
                                                    .ToList();
                    break;

                case RuleDefinitions.CreatureSex.Female:
                    availablePredefinedFirstNames = racePresentation
                                                    .FemaleNameOptions
                                                    .Select(fn => Localize(fn))
                                                    .ToHashSet(StringComparer.OrdinalIgnoreCase)
                                                    .Except(usedNames)
                                                    .ToList();
                    break;

                default:
                    break;
                }

                var    rnd = new Random(Environment.TickCount);
                string newFirstName;

                if (availablePredefinedFirstNames.Any())
                {
                    newFirstName = availablePredefinedFirstNames
                                   .Skip(rnd.Next(availablePredefinedFirstNames.Count()))
                                   .First();
                }
                else
                {
                    // Otherwise add "-n" to current name.
                    // Get the next save character index - let's not have over 1000 characters with the same name :)
                    var regex = new Regex($@"^{firstName}.*-(?<num>\d{{1,4}}).chr$", RegexOptions.Singleline | RegexOptions.Compiled);

                    var next = (Directory
                                .EnumerateFiles(TacticalAdventuresApplication.GameCharactersDirectory, $"{firstName}*.chr")
                                .Select(f => Path.GetFileName(f))
                                .Select(f => regex.Match(f))
                                .Where(m => m.Success)
                                .Select(m => (int?)int.Parse(m.Groups["num"].Value))
                                .Max() ?? 0) + 1;

                    newFirstName = $"{firstName}-{next}";
                }

                string newSurname;

                if (racePresentation.HasSurName && racePresentation.SurNameOptions.Any())
                {
                    var availableSurnames = racePresentation.SurNameOptions
                                            .Concat(Enumerable.Repeat(surName, 1))
                                            .Where(s => !string.IsNullOrWhiteSpace(s))
                                            .Select(sn => Localize(sn))
                                            .Distinct()
                                            .ToList();

                    newSurname = availableSurnames
                                 .Skip(rnd.Next(availableSurnames.Count))
                                 .First();
                }
                else
                {
                    newSurname = surName;
                }

                var msg = racePresentation.HasSurName ?
                          $"Export '{firstName} {surName}' as '{newFirstName} {newSurname}'." :
                          $"Export '{firstName}' as '{newFirstName}'.";

                // TODO: localize
                ServiceRepository.GetService <IGuiService>().ShowMessage(
                    MessageModal.Severity.Informative1, "Character export", msg, "OK", "Cancel",
                    () =>
                {
                    Main.Log("Ok pressed");
                    DoExportInspectedCharacter(newFirstName, newSurname);
                },
                    () =>
                {
                    Main.Log("Cancel pressed");
                });
            }

            void DoExportInspectedCharacter(string newFirstName, string newSurname)
            {
                var heroCharacter = __instance.InspectedCharacter.RulesetCharacterHero;

                // record current name, etc..
                var firstName = heroCharacter.Name;
                var surName   = heroCharacter.SurName;
                var builtin   = heroCharacter.BuiltIn;
                var guid      = heroCharacter.Guid;

                // record current conditions, powers, spells and attunements
                var conditions = heroCharacter.ConditionsByCategory.ToList();
                var powers     = heroCharacter.PowersUsedByMe.ToList();
                var spells     = heroCharacter.SpellsCastByMe.ToList();

                var inventoryItems = new List <RulesetItem>();

                heroCharacter.CharacterInventory.EnumerateAllItems(inventoryItems);
                var attunedItems = inventoryItems.Select(i => new { Item = i, Name = i.AttunedToCharacter }).ToList();

                // record item guids
                var heroItemGuids      = heroCharacter.Items.Select(i => new { Item = i, i.Guid }).ToList();
                var inventoryItemGuids = inventoryItems.Select(i => new { Item = i, i.Guid }).ToList();

                try
                {
                    heroCharacter.Name    = newFirstName;
                    heroCharacter.SurName = newSurname;
                    heroCharacter.BuiltIn = false;

                    // remove active conditions (or filter out during serialization)
                    heroCharacter.ConditionsByCategory.Clear();

                    // remove spells and effects (or filter out during serialization)
                    heroCharacter.PowersUsedByMe.Clear();
                    heroCharacter.SpellsCastByMe.Clear();

                    // TODO: -- need help
                    // TODO: remove weapon modifiers and effects
                    // TODO: fully rest and restore hit points

                    // remove attunement, attuned items don't work well in the character inspection screen out of game
                    foreach (var item in attunedItems)
                    {
                        item.Item.AttunedToCharacter = string.Empty;
                    }

                    // clear guids
                    heroCharacter.SetGuid(0);

                    foreach (var item in heroItemGuids)
                    {
                        item.Item.SetGuid(0);
                    }

                    foreach (var item in inventoryItemGuids)
                    {
                        item.Item.SetGuid(0);
                    }

                    // finally, save the character
                    ServiceRepository
                    .GetService <ICharacterPoolService>()
                    .SaveCharacter(heroCharacter, true);
                }
                finally
                {
                    // and finally, finally, restore everything.

                    // TODO: check these things are really restored

                    // restore original values
                    heroCharacter.Name    = firstName;
                    heroCharacter.SurName = surName;
                    heroCharacter.BuiltIn = builtin;

                    // restore conditions
                    foreach (var kvp in conditions)
                    {
                        heroCharacter.ConditionsByCategory.Add(kvp.Key, kvp.Value);
                    }

                    // restore active spells and effects
                    heroCharacter.PowersUsedByMe.AddRange(powers);
                    heroCharacter.SpellsCastByMe.AddRange(spells);

                    // restore attunements
                    foreach (var item in attunedItems)
                    {
                        item.Item.AttunedToCharacter = item.Name;
                    }

                    // restore guids
                    heroCharacter.SetGuid(guid);

                    foreach (var item in heroItemGuids)
                    {
                        item.Item.SetGuid(item.Guid);
                    }

                    foreach (var item in inventoryItemGuids)
                    {
                        item.Item.SetGuid(item.Guid);
                    }
                }
            }
        }