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)); }