private static void ApplyMutations(CharacterTemplate buildTemplate, List <MLNode> mutationNodes)
        {
            if (!buildTemplate.genotypeEntry.IsMutant)
            {
                return;
            }
            Mutations part = buildTemplate.PlayerBody.GetPart <Mutations>();

            foreach (MLNode node in mutationNodes)
            {
                if (node.Entry != null && node.Selected > 0)
                {
                    if (node.Entry.Mutation != null)
                    {
                        BaseMutation baseMutation = node.Entry.CreateInstance();
                        baseMutation.SetVariant(node.Variant);
                        part.AddMutation(baseMutation, node.Selected);
                    }
                    else if (node.Entry.DisplayName == "Chimera")
                    {
                        buildTemplate.MutationLevel = "Chimera";
                    }
                    else if (node.Entry.DisplayName == "Esper")
                    {
                        buildTemplate.MutationLevel = "Esper";
                    }
                }
            }
        }
Пример #2
0
            /// <summary>
            /// Creates an ability description for a mutation. The description is constructed from the
            /// mutation description and the GetLevelText() for the mutation at its current level.
            /// Cooldown information is also appended to the description.
            /// </summary>
            /// TODO: Determine if the Level logic has changed with the new chimera rapid advancements.
            ///       For example, will level return 6 if that's my actual level, or will it return
            ///       5 if my mutation level is restricted based on my character level?
            public List <string> MakeMutationAbilityDescription(string category, ActivatedAbilityEntry ability)
            {
                if (!this.Categories.ContainsKey(category))
                {
                    LogUnique($"(FYI) Activated ability description for '{SimplifiedAbilityName(ability?.DisplayName)}'"
                              + $" won't be updated because QudUX didn't recognize it's activated ability category, '{category}'");
                    return(SpecialFormatDescription(ability?.Description, SourceAbility: ability));
                }
                List <AbilityXmlInfo> abilityData = this.Categories[category];

                foreach (AbilityXmlInfo abilityDataEntry in abilityData)
                {
                    if (abilityDataEntry.Name == SimplifiedAbilityName(ability.DisplayName))
                    {
                        //match AbilityDataEntry to the Ability name
                        BaseMutation abilitySourceMutation = null;
                        BaseMutation secondaryMatch        = null;
                        foreach (BaseMutation playerMutation in this.PlayerMutations)
                        {
                            MutationEntry mutationEntry = playerMutation.GetMutationEntry();
                            if (mutationEntry != null && mutationEntry.DisplayName == abilityDataEntry.MutationName)
                            {
                                abilitySourceMutation = playerMutation;
                                break;
                            }
                            if (playerMutation.DisplayName == abilityDataEntry.MutationName)
                            {
                                secondaryMatch = playerMutation; //less desirable match method, but necessary for some NPC mutations that don't have a MutationEntry
                            }
                        }
                        if (abilitySourceMutation == null && secondaryMatch != null)
                        {
                            abilitySourceMutation = secondaryMatch;
                        }
                        if (abilitySourceMutation == null)
                        {
                            LogUnique($"(FYI) Mutation activated ability '{SimplifiedAbilityName(ability?.DisplayName)}'"
                                      + $" in category '{category}' has no description available in game and no backup description"
                                      + " provided by QudUX, so a description won't be shown on the Manage Abilities screen.");
                            break;
                        }

                        string abilityDescription = abilitySourceMutation.GetDescription() + "\n\n" + abilitySourceMutation.GetLevelText(abilitySourceMutation.Level);
                        abilityDescription = abilityDescription.TrimEnd('\r', '\n', ' ');
                        //updated Cooldown based on wisdom:
                        if (abilityDescription.Contains("Cooldown:") || !string.IsNullOrEmpty(abilityDataEntry.BaseCooldown))
                        {
                            if (string.IsNullOrEmpty(abilityDataEntry.NoCooldownReduction) || abilityDataEntry.NoCooldownReduction != "true")
                            {
                                string   updatedDescription      = string.Empty;
                                string   extractedCooldownString = GetAdjustedBaseCooldown(abilityDataEntry);
                                string[] descriptionParts        = abilityDescription.Split('\n');
                                foreach (string descriptionPart in descriptionParts)
                                {
                                    if (descriptionPart.Contains("Cooldown:"))
                                    {
                                        string[] words = descriptionPart.Split(' ');
                                        foreach (string word in words)
                                        {
                                            int o;
                                            if (int.TryParse(word, out o))
                                            {
                                                extractedCooldownString = this.GetCooldownString(word);
                                                break;
                                            }
                                        }
                                        if (string.IsNullOrEmpty(extractedCooldownString))
                                        {
                                            updatedDescription += (updatedDescription != string.Empty ? "\n" : string.Empty) + descriptionPart; //restore line in case we didn't find the number (should never happen)
                                        }
                                    }
                                    else
                                    {
                                        updatedDescription += (updatedDescription != string.Empty ? "\n" : string.Empty) + descriptionPart;
                                    }
                                }
                                abilityDescription = updatedDescription + (!string.IsNullOrEmpty(extractedCooldownString) ? "\n\n" + extractedCooldownString : string.Empty);
                            }
                        }
                        return(SpecialFormatDescription(abilityDescription, abilityDataEntry.DeleteLines, abilityDataEntry.DeletePhrases, ability));
                    }
                }
                return(SpecialFormatDescription(ability?.Description, SourceAbility: ability));
            }
Пример #3
0
        public override bool FireEvent(Event E)
        {
            if (E.ID == "ApplyTonic")
            {
                GameObject target = E.GetGameObjectParameter("Target");
                target.PermuteRandomMutationBuys();
                var       Messages  = new List <string>();
                var       gainLimb  = false;
                Mutations mutations = null;
                if (target.IsPlayer())
                {
                    Popup.Show("As the tonic floods your veins, you feel the latent genetic pressure of eons.");
                }
                if (ParentObject.HasPart("Temporary") && !target.HasPart("Temporary"))
                {
                    Messages.Add((target.IsPlayer() ? "Your" :
                                  Grammar.MakePossessive(target.The + target.ShortDisplayName)) +
                                 " genes ache longingly.");
                }
                else
                {
                    var Random    = Utility.Random(this, target);
                    var goodColor = ColorCoding.ConsequentialColor(ColorAsGoodFor: target);
                    var badColor  = ColorCoding.ConsequentialColor(ColorAsBadFor: target);
                    if (target.IsTrueKin())
                    {
                        var which = new[] { "Strength", "Agility", "Toughness" }.GetRandomElement(Random);
                        if (target.HasStat(which))
                        {
                            ++target.Statistics[which].BaseValue;
                            Messages.Add(goodColor +
                                         (target.IsPlayer() ? "You" : target.The + target.ShortDisplayName) +
                                         target.GetVerb("gain") + " 1 point of " + which + "!");
                        }
                    }
                    else   /*if mutant*/
                    {
                        mutations = target.GetPart <Mutations>();
                        if (target.IsEsper())
                        {
                            // can't chimerify; reduce glimmer instead
                            int glimmerReduction = Random.Next(1, 5);
                            int currentGlimmer   = target.GetPsychicGlimmer();
                            if (glimmerReduction > currentGlimmer)
                            {
                                glimmerReduction = currentGlimmer;
                            }
                            _ = target.ModIntProperty("GlimmerModifier", -glimmerReduction);
                            target.SyncMutationLevelAndGlimmer();
                            Messages.Add("Nerves weave and ossify, unable to escape " +
                                         (target.IsPlayer() ? "your" : Grammar.MakePossessive(target.the + target.ShortDisplayName)) +
                                         " psychic cage.");
                        }
                        else if (!target.IsChimera())
                        {
                            var mentals       = target.GetMentalMutations();
                            var mentalDefects = target.GetMutationsOfCategory("MentalDefects");
                            var mpToTransfer  = 0;
                            if (mentals.Count > 0 || mentalDefects.Count > 0)
                            {
                                Messages.Add((target.IsPlayer() ? "Your" :
                                              Grammar.MakePossessive(target.The + target.ShortDisplayName)) +
                                             " genome sloughs off superfluous layers of alien thoughtstuff.");
                                Messages.Add("");
                            }
                            if (mentals.Count > 0)
                            {
                                // choose 1d4 MP of investment in mental mutations to remove...
                                mpToTransfer = Random.Next(1, 5);
                                var totalLevels = mentals.Map(m => m.BaseLevel).Sum();
                                var toReduce    = new List <Tuple <BaseMutation, int> >(mpToTransfer);
                                if (totalLevels <= mpToTransfer)
                                {
                                    // remove everything, will be eligible for Chimera
                                    mpToTransfer = totalLevels;
                                    foreach (var mental in mentals)
                                    {
                                        toReduce.Add(Tuple.Create(mental, mental.BaseLevel));
                                    }
                                }
                                else
                                {
                                    // magically pick mpToTransfer mutations weighted by level
                                    var remainingLevels    = totalLevels;
                                    var remainingReduction = mpToTransfer;
                                    foreach (var mental in mentals)
                                    {
                                        var thisMentalReduction = 0;
                                        while (0 < remainingReduction && Random.Next(0, remainingLevels) < mental.BaseLevel - thisMentalReduction + remainingReduction - 1)
                                        {
                                            ++thisMentalReduction;
                                            --remainingLevels;
                                            --remainingReduction;
                                        }
                                        if (0 < thisMentalReduction)
                                        {
                                            toReduce.Add(Tuple.Create(mental, thisMentalReduction));
                                        }
                                        remainingLevels -= mental.BaseLevel - thisMentalReduction;
                                        if (0 >= remainingReduction)
                                        {
                                            break;
                                        }
                                    }
                                }
                                // ... remove them...
                                var lostMentals = new List <MutationEntry>();
                                foreach (var mental in toReduce)
                                {
                                    var mutation  = mental.Item1;
                                    var reduction = mental.Item2;
                                    if (mutation.BaseLevel <= reduction)
                                    {
                                        // remove the mutation altogether
                                        lostMentals.Add(mutation.GetMutationEntry());
                                        mutations.RemoveMutation(mutation);
                                    }
                                    else
                                    {
                                        // reduce the mutation level
                                        mutations.LevelMutation(mutation, mutation.BaseLevel - reduction);
                                    }
                                }
                                // ... and replace any lost mental mutations with physical mutations
                                foreach (var mental in lostMentals)
                                {
                                    // expensive to regenerate this each time, but won't be very many times and
                                    // want to make sure exclusions from e.g. Stinger are handled correctly
                                    Messages.Add(badColor +
                                                 (target.IsPlayer() ? "You" : target.The + target.ShortDisplayName) +
                                                 target.GetVerb("lose") + " " + mental.DisplayName + "!");
                                    var eligiblePhysicals = mutations.GetMutatePool(m => m.Category.Name.EndsWith("Physical")).Shuffle(Random);
                                    var similarPhysicals  = eligiblePhysicals.Where(p => p.Cost == mental.Cost);
                                    var otherPhysicals    = eligiblePhysicals.Where(p => p.Cost != mental.Cost);
                                    foreach (var physical in similarPhysicals.Concat(otherPhysicals))
                                    {
                                        _ = mutations.AddMutation(physical, 1);
                                        Messages.Add(goodColor +
                                                     (target.IsPlayer() ? "You" : target.The + target.ShortDisplayName) +
                                                     target.GetVerb("gain") + " " + physical.DisplayName + "!");
                                        --mpToTransfer;
                                        break;
                                    } // else if there are no valid physical mutations, don't add anything new
                                }
                            }
                            while (0 < mpToTransfer)
                            {
                                var          physicals        = target.GetPhysicalMutations();
                                BaseMutation which            = null;
                                var          canLevelNormally = physicals.Where(m => m.CanIncreaseLevel());
                                if (canLevelNormally.Any())
                                {
                                    which = canLevelNormally.GetRandomElement(Random);
                                }
                                else
                                {
                                    var underMaxLevel = physicals.Where(m => m.BaseLevel < m.MaxLevel);
                                    if (underMaxLevel.Any())
                                    {
                                        which = underMaxLevel.GetRandomElement(Random);
                                    }
                                }
                                if (which != null)
                                {
                                    mutations.LevelMutation(which, which.BaseLevel + 1);
                                    --mpToTransfer;
                                }
                                else
                                {
                                    // no physical mutations to put the levels in, spend the rest on a new one
                                    foreach (var physical in mutations.GetMutatePool(m => m.Category.Name.EndsWith("Physical")).Shuffle(Random))
                                    {
                                        _ = mutations.AddMutation(physical, 1);
                                        Messages.Add(goodColor +
                                                     (target.IsPlayer() ? "You" : target.The + target.ShortDisplayName) +
                                                     target.GetVerb("gain") + " " + physical.DisplayName + "!");
                                        break;
                                    }
                                    mpToTransfer = 0;
                                }
                            }
                            if (target.GetMentalMutations().Count == 0)
                            {
                                foreach (var mutation in mentalDefects)
                                {
                                    mutations.RemoveMutation(mutation);

                                    var mental = mutation.GetMutationEntry();
                                    Messages.Add(goodColor +
                                                 (target.IsPlayer() ? "You" : target.The + target.ShortDisplayName) +
                                                 target.GetVerb("lose") + " " + mental.DisplayName + "!");

                                    var eligibleDefects = MutationFactory.GetMutationsOfCategory("PhysicalDefects").Shuffle(Random);
                                    var similarDefects  = eligibleDefects.Where(p => p.Cost == mental.Cost);
                                    var otherDefects    = eligibleDefects.Where(p => p.Cost != mental.Cost);
                                    foreach (var physical in similarDefects.Concat(otherDefects))
                                    {
                                        _ = mutations.AddMutation(physical, 1);
                                        Messages.Add(badColor +
                                                     (target.IsPlayer() ? "You" : target.The + target.ShortDisplayName) +
                                                     target.GetVerb("gain") + " " + physical.DisplayName + "!");
                                        break;
                                    } // else if there are no valid physical defects, don't add anything new
                                }

                                target.Property["MutationLevel"] =
                                    target.Property.GetValueOrDefault("MutationLevel", "") + "Chimera";
                                Messages.Add("");
                                Messages.Add(goodColor +
                                             (target.IsPlayer() ? "You" : target.The + target.ShortDisplayName) +
                                             target.GetVerb("become") + " a Chimera!");
                            }
                        }
                        else   /*target.IsChimera*/
                        {
                            // 50% chance of new limb, 50% chance of mutation level gain
                            if (Random.Next(2) == 0)
                            {
                                // new limb! defer until the other messages are shown to actually gain it
                                gainLimb = true;
                            }
                            else
                            {
                                var physicals = target.GetPhysicalMutations().Where(m => m.CanLevel());
                                if (physicals.Any())
                                {
                                    // +1 to level of a physical mutation, uncapped
                                    var          which  = physicals.GetRandomElement(Random);
                                    const string source = "{{r-r-r-R-R-W distribution|limbic fluid}} injections";
                                    var          found  = false;
                                    foreach (var mod in mutations.MutationMods)
                                    {
                                        if (mod.sourceName == source && mod.mutationName == which.Name)
                                        {
                                            ++mod.bonus;
                                            found = true;
                                        }
                                    }
                                    if (!found)
                                    {
                                        _ = mutations.AddMutationMod(which.Name, 1, Mutations.MutationModifierTracker.SourceType.StatMod, source);
                                    }
                                    Messages.Add(goodColor +
                                                 (target.IsPlayer() ? "You" : target.The + target.ShortDisplayName) +
                                                 target.GetVerb("gain") + " one rank of " + which.DisplayName + "!");
                                }
                                else
                                {
                                    // +1 MP if we can't level anything
                                    target.GainMP(1);
                                    Messages.Add(goodColor +
                                                 (target.IsPlayer() ? "You" : target.The + target.ShortDisplayName) +
                                                 target.GetVerb("gain") + " one MP!");
                                }
                            }
                        }
                    }
                }
                if (target.IsPlayer() && Messages.Count > 0)
                {
                    var output = string.Join("\n", Messages);
                    output = _extraLines.Replace(output, "\n\n");
                    Popup.Show(output);
                }
                else
                {
                    foreach (var Message in Messages)
                    {
                        AddPlayerMessage(Message);
                    }
                }
                if (gainLimb)
                {
                    _ = mutations.AddChimericBodyPart();
                }
            }
            return(base.FireEvent(E));
        }
Пример #4
0
 public static void RemoveMutation(Mutations mutations, BaseMutation mutation)
 {
     mutations.RemoveMutation(mutation);
     Show($"Om nom nom! {mutation.DisplayName} is gone! {{{{w|*belch*}}}}");
 }
Пример #5
0
        public void UpdateMutationAbilityDescription(string category, ActivatedAbilityEntry ability)
        {
            if (!this.Categories.ContainsKey(category))
            {
                Debug.Log("QudUX Mod: Couldn't find any data for activated ability category '" + category + "'. Activated ability description for " + this.SimplifiedAbilityName(ability.DisplayName) + " won't be updated.");
                return;
            }
            List <Egcb_AbilityDataEntry> abilityData = this.Categories[category];

            foreach (Egcb_AbilityDataEntry abilityDataEntry in abilityData)
            {
                if (abilityDataEntry.Name == this.SimplifiedAbilityName(ability.DisplayName))
                {
                    //match AbilityDataEntry to the Ability name
                    BaseMutation abilitySourceMutation = null;
                    BaseMutation secondaryMatch        = null;
                    foreach (BaseMutation playerMutation in this.PlayerMutations)
                    {
                        MutationEntry mutationEntry = playerMutation.GetMutationEntry();
                        if (mutationEntry != null && mutationEntry.DisplayName == abilityDataEntry.MutationName)
                        {
                            abilitySourceMutation = playerMutation;
                            break;
                        }
                        if (playerMutation.DisplayName == abilityDataEntry.MutationName)
                        {
                            secondaryMatch = playerMutation; //less desirable match method, but necessary for some NPC mutations that don't have a MutationEntry
                        }
                    }
                    if (abilitySourceMutation == null && secondaryMatch != null)
                    {
                        abilitySourceMutation = secondaryMatch;
                    }
                    if (abilitySourceMutation == null)
                    {
                        Debug.Log("QudUX Mod: Unexpectedly failed to load mutation description data for '" + this.SimplifiedAbilityName(ability.DisplayName) + "' activated ability.");
                        continue;
                    }
                    if (!this.VanillaDescriptionText.ContainsKey(ability.ID))
                    {
                        this.VanillaDescriptionText.Add(ability.ID, ability.Description);
                    }
                    ability.Description = abilitySourceMutation.GetDescription() + "\n\n" + abilitySourceMutation.GetLevelText(abilitySourceMutation.Level);
                    ability.Description = ability.Description.TrimEnd('\r', '\n', ' ');
                    //updated Cooldown based on wisdom:
                    if (ability.Description.Contains("Cooldown:") || !string.IsNullOrEmpty(abilityDataEntry.BaseCooldown))
                    {
                        string   updatedDescription      = string.Empty;
                        string   extractedCooldownString = !string.IsNullOrEmpty(abilityDataEntry.BaseCooldown) ? this.GetCooldownString(abilityDataEntry.BaseCooldown) : string.Empty;
                        string[] descriptionParts        = ability.Description.Split('\n');
                        foreach (string descriptionPart in descriptionParts)
                        {
                            if (descriptionPart.Contains("Cooldown:"))
                            {
                                string[] words = descriptionPart.Split(' ');
                                foreach (string word in words)
                                {
                                    int o;
                                    if (int.TryParse(word, out o))
                                    {
                                        extractedCooldownString = this.GetCooldownString(word);
                                        break;
                                    }
                                }
                                if (string.IsNullOrEmpty(extractedCooldownString))
                                {
                                    updatedDescription += (updatedDescription != string.Empty ? "\n" : string.Empty) + descriptionPart; //restore line in case we didn't find the number (should never happen)
                                }
                            }
                            else
                            {
                                updatedDescription += (updatedDescription != string.Empty ? "\n" : string.Empty) + descriptionPart;
                            }
                        }
                        ability.Description = updatedDescription + (!string.IsNullOrEmpty(extractedCooldownString) ? "\n\n" + extractedCooldownString : string.Empty);
                    }
                    ability.Description = Egcb_AbilityData.SpecialFormatDescription(ability.Description, abilityDataEntry.DeleteLines, abilityDataEntry.DeletePhrases);
                    break;
                }
            }
        }