protected override string UpdatedHornsText(Creature target, HornData oldData) { if (oldData.hornCount == 0) { return(GlobalStrings.NewParagraph() + "You hear the sound of cracking branches erupting from the tip of your skull. Small bulges on either side of your head advance outwards in a straight line, eventually spreading out in multiple directions like a miniature tree. Investigating the exotic additions sprouting from your head, the situation becomes clear. <b>You've grown antlers!</b>"); } else { return(GlobalStrings.NewParagraph() + "You hear the sound of cracking branches erupting from the tip of your skull. The horns on your head begin to twist and turn fanatically, their texture and size morphing considerably until they resemble something more like trees than anything else. Branching out rebelliously, you've come to the conclusion that <b>you've somehow gained antlers!</b>"); } }
protected virtual string RestoredHornsText(Creature target, HornData oldData) { return(target.horns.RestoredText(oldData)); }
protected internal override string DoTransformation(Creature target, out bool isBadEnd) { isBadEnd = false; int changeCount = GenerateChangeCount(target, new int[] { 2, 2 }); int remainingChanges = changeCount; StringBuilder sb = new StringBuilder(); //the initial text for starting the transformation. feel free to add additional variables to this if needed. sb.Append(InitialTransformationText(target)); //Add any free changes here - these can occur even if the change count is 0. these include things such as change in stats (intelligence, etc) //change in height, hips, and/or butt, or other similar stats. //this will handle the edge case where the change count starts out as 0. if (remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } //Any transformation related changes go here. these typically cost 1 change. these can be anything from body parts to gender (which technically also changes body parts, //but w/e). You are required to make sure you return as soon as you've applied changeCount changes, but a single line of code can be applied at the end of a change to do //this for you. //paste this line after any tf is applied, and it will: automatically decrement the remaining changes count. if it becomes 0 or less, apply the total number of changes //underwent to the target's change count (if applicable) and then return the StringBuilder content. //if (--remainingChanges <= 0) return ApplyChangesAndReturn(target, sb, changeCount - remainingChanges); //----------------------- // MAJOR TRANSFORMATIONS //----------------------- //1st priority: Change lower body to bipedal. if (Utils.Rand(4) == 0) { LowerBodyData oldData = target.lowerBody.AsReadOnlyData(); target.RestoreLowerBody(); sb.Append(RestoredLowerBodyText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Remove Oviposition Perk if (target.womb.canRemoveOviposition && Utils.Rand(5) == 0) { target.womb.ClearOviposition(); sb.Append(ClearOvipositionText(target)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Remove Incorporeality Perk, if not permanent if (target.HasPerk <Incorporeal>() && Utils.Rand(4) == 0) { target.RemovePerk <Incorporeal>(); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Restore neck if (target.neck.type != NeckType.HUMANOID && Utils.Rand(5) == 0) { NeckData oldData = target.neck.AsReadOnlyData(); target.RestoreNeck(); sb.Append(RestoredNeckText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Rear body restore if (!target.back.isDefault && Utils.Rand(5) == 0) { BackData oldData = target.back.AsReadOnlyData(); target.RestoreBack(); sb.Append(RestoredBackText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //-Skin color change – light, fair, olive, dark, ebony, mahogany, russet if (!Species.HUMAN.availableTones.Contains(target.body.primarySkin.tone) && Utils.Rand(5) == 0) { target.body.ChangeAllSkin(Utils.RandomChoice(Species.HUMAN.availableTones)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Change skin to normal if (target.body.type != BodyType.HUMANOID && (target.ears.type == EarType.HUMAN || target.ears.type == EarType.ELFIN) && Utils.Rand(4) == 0) { BodyData oldData = target.body.AsReadOnlyData(); target.RestoreBody(); sb.Append(RestoredBodyText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Restore arms to become human arms again if (Utils.Rand(4) == 0) { ArmData oldData = target.arms.AsReadOnlyData(); target.RestoreArms(); sb.Append(RestoredArmsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //----------------------- // MINOR TRANSFORMATIONS //----------------------- //-Human face if (target.face.type != FaceType.HUMAN && Utils.Rand(4) == 0) { FaceData oldData = target.face.AsReadOnlyData(); target.RestoreFace(); sb.Append(RestoreFaceText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //-Human tongue if (target.tongue.type != TongueType.HUMAN && Utils.Rand(4) == 0) { TongueData oldData = target.tongue.AsReadOnlyData(); target.RestoreTongue(); sb.Append(RestoreTongueText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Remove odd eyes if (Utils.Rand(5) == 0 && target.eyes.type != EyeType.HUMAN) { EyeData oldData = target.eyes.AsReadOnlyData(); target.RestoreEyes(); sb.Append(RestoredEyesText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //-Gain human ears (If you have human face) if (target.ears.type != EarType.HUMAN && target.face.type == FaceType.HUMAN && Utils.Rand(4) == 0) { EarData oldData = target.ears.AsReadOnlyData(); target.RestoreEar(); sb.Append(RestoreEarsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Removes gills if (Utils.Rand(4) == 0 && !target.gills.isDefault) { GillData oldData = target.gills.AsReadOnlyData(); target.RestoreGills(); sb.Append(RestoredGillsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Nipples Turn Back: if (target.genitals.hasBlackNipples && Utils.Rand(3) == 0) { target.genitals.SetBlackNipples(false); } //Remove extra nipples if (target.genitals.hasQuadNipples && Utils.Rand(3) == 0) { target.genitals.SetQuadNipples(false); } //Hair turns normal //Restart hair growth, if hair's normal but growth isn't on. Or just over turning hair normal. The power of rng. if ((target.hair.type != HairType.NORMAL || target.hair.growthArtificallyDisabled) && Utils.Rand(3) == 0) { target.UpdateHair(HairType.NORMAL); if (target.hair.growthArtificallyDisabled) { target.hair.SetHairGrowthStatus(true); } if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //----------------------- // EXTRA PARTS REMOVAL //----------------------- //Removes antennae if (target.antennae.type != AntennaeType.NONE && Utils.Rand(3) == 0) { AntennaeData oldData = target.antennae.AsReadOnlyData(); target.RestoreAntennae(); sb.Append(RestoredAntennaeText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Removes horns if ((target.horns.type != HornType.NONE) && Utils.Rand(5) == 0) { HornData oldData = target.horns.AsReadOnlyData(); target.RestoreHorns(); sb.Append(RestoredHornsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Removes wings if (target.wings.type != WingType.NONE && Utils.Rand(5) == 0) { WingData oldData = target.wings.AsReadOnlyData(); target.RestoreWings(); sb.Append(RestoredWingsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Removes tail if (target.tail.type != TailType.NONE && Utils.Rand(5) == 0) { TailData oldData = target.tail.AsReadOnlyData(); target.RestoreTail(); sb.Append(RestoredTailText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Increase height up to 4ft 10in. if (Utils.Rand(2) == 0 && target.build.heightInInches < 58) { int temp = Utils.Rand(5) + 3; //Flavor texts. Flavored like 1950's cigarettes. Yum. target.build.IncreaseHeight((byte)temp); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Decrease height down to a maximum of 6ft 2in. if (Utils.Rand(2) == 0 && target.build.heightInInches > 74) { target.build.DecreaseHeight((byte)(3 + Utils.Rand(5))); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //----------------------- // SEXUAL TRANSFORMATIONS //----------------------- //Remove additional cocks if (target.cocks.Count > 1 && Utils.Rand(3) == 0) { target.RemoveCock(); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Remove additional balls/remove uniball if (target.balls.hasBalls && (target.balls.count != 2 || target.balls.uniBall) && Utils.Rand(3) == 0) { if (target.balls.size > 2) { if (target.balls.size > 5) { target.balls.ShrinkBalls((byte)(1 + Utils.Rand(3))); } target.balls.ShrinkBalls(1); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } else if (target.balls.count > 2) { target.balls.RemoveExtraBalls(); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } else //if (target.balls.count == 1 || target.balls.uniBall) { target.balls.MakeStandard(); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //remove second v****a. if (target.vaginas.Count > 1 && Utils.Rand(3) == 0) { target.genitals.RemoveExtraVaginas(); } //Change c**k back to normal if (target.hasCock && !target.genitals.OnlyHasCocksOfType(CockType.HUMAN) && Utils.Rand(3) == 0) { //Select first non-human c**k C**k firstNonHuman = target.cocks.First(x => x.type != CockType.HUMAN); target.genitals.UpdateCock(firstNonHuman, CockType.HUMAN); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } C**k longest = target.genitals.LongestCock(); double targetSize = Math.Max(7, target.genitals.minimumCockLength); //Shrink oversized cocks if (target.hasCock && longest.length > targetSize && Utils.Rand(3) == 0) { longest.DecreaseLength((Utils.Rand(10) + 2) / 10.0); if (longest.girth > 1) { longest.DecreaseThickness((Utils.Rand(4) + 1) / 10.0); } if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Remove additional breasts if (target.breasts.Count > 1 && Utils.Rand(3) == 0) { target.RemoveExtraBreastRows(); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } Breasts biggestCup = target.genitals.LargestBreast(); CupSize targetCup = EnumHelper.Max(CupSize.D, target.genitals.smallestPossibleFemaleCupSize); //Shrink t**s! if (Utils.Rand(3) == 0 && biggestCup.cupSize > targetCup) { foreach (Breasts t**s in target.breasts) { t**s.ShrinkBreasts(); } if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Change v****a back to normal if (Utils.Rand(3) == 0 && target.hasVagina && !target.genitals.OnlyHasVaginasOfType(VaginaType.defaultValue)) { foreach (V****a vag in target.vaginas) { target.genitals.RestoreVagina(vag); } if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } VaginalWetness targetWetness = EnumHelper.Max(VaginalWetness.WET, target.genitals.minVaginalWetness); //Reduce wetness down to a minimum of 2 if (Utils.Rand(3) == 0 && target.hasVagina && target.genitals.LargestVaginalWetness() > targetWetness) { foreach (V****a vag in target.vaginas) { if (vag.wetness > targetWetness) { vag.DecreaseWetness(); } } if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Fertility Decrease: if (target.hasVagina && target.fertility.baseFertility > 10 && Utils.Rand(3) == 0) { //High fertility: //Average fertility: target.fertility.DecreaseFertility((byte)(1 + Utils.Rand(3))); if (target.fertility.baseFertility < 10) { target.fertility.SetFertility(10); } if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Cum Multiplier Decrease: if (target.hasCock && target.genitals.cumMultiplier > 5 && Utils.Rand(3) == 0) { target.genitals.DecreaseCumMultiplier(1 + (Utils.Rand(20) / 10.0)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Anal wetness decrease if (target.ass.wetness > 0 && Utils.Rand(3) == 0) { target.ass.DecreaseWetness(); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //this is the fallthrough that occurs when a tf item goes through all the changes, but does not proc enough of them to exit early. it will apply however many changes //occurred, then return the contents of the stringbuilder. return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); }
protected internal override string DoTransformation(Creature target, out bool isBadEnd) { isBadEnd = false; //by default, this is 2 rolls at 50%, so a 25% chance of 0 additional tfs, 50% chance of 1 additional tf, 25% chance of 2 additional tfs. //also takes into consideration any perks that increase or decrease tf effectiveness. if you need to roll out your own, feel free to do so. int changeCount = GenerateChangeCount(target, new int[] { 2, 2 }); int remainingChanges = changeCount; StringBuilder sb = new StringBuilder(); //For all of these, any text regarding the transformation should be instead abstracted out as an abstract string function. append the result of this abstract function //to the string builder declared above (aka sb.Append(FunctionCall(variables));) string builder is just a fancy way of telling the compiler that you'll be creating a //long string, piece by piece, so don't do any crazy optimizations first. //the initial text for starting the transformation. feel free to add additional variables to this if needed. sb.Append(InitialTransformationText(target)); //Add any free changes here - these can occur even if the change count is 0. these include things such as change in stats (intelligence, etc) //change in height, hips, and/or butt, or other similar stats. //this will handle the edge case where the change count starts out as 0. if (remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } //Any transformation related changes go here. these typically cost 1 change. these can be anything from body parts to gender (which technically also changes body parts, //but w/e). You are required to make sure you return as soon as you've applied changeCount changes, but a single line of code can be applied at the end of a change to do //this for you. //paste this line after any tf is applied, and it will: automatically decrement the remaining changes count. if it becomes 0 or less, apply the total number of changes //underwent to the target's change count (if applicable) and then return the StringBuilder content. //if (--remainingChanges <= 0) return ApplyChangesAndReturn(target, sb, changeCount - remainingChanges); //Corruption reduction if (isPure) { //Special honey will also reduce corruption, but uses different text and is handled separately target.ChangeCorruption(-(1 + (target.corruptionTrue / 20))); //Libido Reduction if (target.corruption > 0 && Utils.Rand(3) < 2 && target.relativeLibido > 40) { target.DeltaCreatureStats(lib: -3, lus: -20); } } //Intelligence Boost if (Utils.Rand(2) == 0 && target.relativeIntelligence < 80) { target.IncreaseIntelligence(0.1 * (80 - target.relativeIntelligence)); } //bee item corollary: if (target.hair.type == HairType.ANEMONE && Utils.Rand(2) == 0) { HairData oldData = target.hair.AsReadOnlyData(); target.RestoreHair(); sb.Append(RestoredHairText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Sexual Stuff //No idears //Appearance Stuff //Hair Color if (target.hair.hairColor != HairFurColors.BLACK && target.hair.length > 10 && Utils.Rand(5) == 0) { if (Utils.Rand(9) == 0) { target.hair.SetBothHairColors(HairFurColors.BLACK, HairFurColors.YELLOW); } else { target.hair.SetHairColor(HairFurColors.BLACK); } if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Hair Length if (target.hair.length < 25 && target.hair.type.canLengthen && Utils.Rand(3) == 0) { target.hair.GrowHair(Utils.Rand(4) + 1); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //-Remove extra breast rows if (target.breasts.Count > 2 && Utils.Rand(3) == 0 && !hyperHappy) { target.genitals.RemoveBreastRows(); } //Antennae if (target.antennae.type == AntennaeType.NONE && target.horns.numHorns == 0 && Utils.Rand(3) == 0) { AntennaeData oldData = target.antennae.AsReadOnlyData(); target.UpdateAntennae(AntennaeType.BEE); sb.Append(UpdateAntennaeText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Horns if (!target.horns.isDefault && Utils.Rand(3) == 0) { HornData oldData = target.horns.AsReadOnlyData(); target.RestoreHorns(); sb.Append(RestoredHornsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Bee Legs if (target.lowerBody.type != LowerBodyType.BEE && Utils.Rand(4) == 0) { LowerBodyData oldData = target.lowerBody.AsReadOnlyData(); target.UpdateLowerBody(LowerBodyType.BEE); sb.Append(UpdateLowerBodyText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //(Arms to carapace-covered arms) if (target.arms.type != ArmType.BEE && Utils.Rand(4) == 0) { ArmData oldData = target.arms.AsReadOnlyData(); target.UpdateArms(ArmType.BEE); sb.Append(UpdateArmsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //-Nipples reduction to 1 per tit. if (target.genitals.hasQuadNipples && Utils.Rand(4) == 0) { target.genitals.SetQuadNipples(false); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Neck restore if (!target.neck.isDefault && Utils.Rand(4) == 0) { NeckData oldData = target.neck.AsReadOnlyData(); target.RestoreNeck(); sb.Append(RestoredNeckText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Rear body restore if (!target.back.isDefault && Utils.Rand(5) == 0) { BackData oldData = target.back.AsReadOnlyData(); target.RestoreBack(); sb.Append(RestoredBackText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Lose reptile oviposition! if (target.womb.canRemoveOviposition && Utils.Rand(5) == 0) { target.womb.ClearOviposition(); sb.Append(ClearOvipositionText(target)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Gain bee ovipositor! if (target.tail.type == TailType.BEE_STINGER && !target.tail.hasOvipositor && Utils.Rand(2) == 0) { target.tail.GrantOvipositor(); } //Bee butt - 66% lower chance if already has a tail if (target.tail.type != TailType.BEE_STINGER && (target.tail.type == TailType.NONE || Utils.Rand(3) < 2) && Utils.Rand(4) == 0) { target.UpdateTail(TailType.BEE_STINGER); target.tail.UpdateResources((short)(10 - target.tail.resources), (short)(2 - target.tail.regenRate)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Venom Increase if (target.tail.type == TailType.BEE_STINGER && target.tail.regenRate < 15 && Utils.Rand(2) == 0) { short additionalRegen = 1; if (target.tail.regenRate < 5) { additionalRegen = 3; } else if (target.tail.regenRate < 10) { additionalRegen = 2; } target.tail.UpdateResources(50, additionalRegen); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Wings //Grow bigger bee wings! if (target.wings.type == WingType.BEE_LIKE && !target.wings.isLarge && Utils.Rand(4) == 0) { target.wings.GrowLarge(); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Grow new bee wings if target has none. if (target.wings.type == WingType.NONE && Utils.Rand(4) == 0) { if (target.back.type == BackType.SHARK_FIN) { target.RestoreBack(); } WingData oldData = target.wings.AsReadOnlyData(); target.UpdateWings(WingType.BEE_LIKE); sb.Append(UpdateWingsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Melt demon wings! if (target.wings.type == WingType.BAT_LIKE) { WingData oldData = target.wings.AsReadOnlyData(); target.RestoreWings(); sb.Append(RestoredWingsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Remove gills! if (Utils.Rand(4) == 0 && !target.gills.isDefault) { GillData oldData = target.gills.AsReadOnlyData(); target.RestoreGills(); sb.Append(RestoredGillsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //All the speical honey effects occur after any normal bee transformations (if the target wasn't a full bee morph) if (isSpecial) { //if no c**k: grow one. if (!target.hasCock) { target.genitals.AddCock(CockType.defaultValue, Utils.Rand(3) + 8, 2); target.HaveGenericCockOrgasm(0, false, true); target.ChangeSensitivity(10); } //if multiple cocks, remove the largest c**k by area. combine its length/girth into the first c**k. else if (target.cocks.Count > 1) { //find the biggest c**k that isn't the first one. C**k biggest = target.cocks.Skip(1).MaxItem(x => x.area); double delta = (double)(5 * Math.Sqrt(0.2 * biggest.area)); target.cocks[0].DeltaLengthAndGirth(delta, delta); target.HaveGenericCockOrgasm(0, false, true); } //one c**k. grow it to 100 area total or larger else if (target.cocks[0].area < 100) { target.cocks[0].DeltaLengthAndGirth(Utils.Rand(3) + 4, 0.1 * Utils.Rand(5) + 0.5); } // else { double baseLengthChange; double baseGirthChange; if (target.cocks[0].type != CockType.BEE && Species.CurrentSpecies(target) == Species.BEE) { target.genitals.UpdateCock(0, CockType.BEE); target.ChangeSensitivity(15); baseLengthChange = 5; baseGirthChange = 1; } else { baseLengthChange = 0.1 * Utils.Rand(10) + 1; baseGirthChange = 0.1 * Utils.Rand(2) + 1; } double mult; C**k c**k = target.cocks[0]; if (c**k.area >= 400) { mult = 0; //C**k stops growing at that point. } else if (c**k.area >= 300) { mult = 0.1; } if (c**k.area > 100) { int offset = (((int)c**k.area) - 100) / 40; mult = 1 - 0.2 * offset; } else { mult = 1; } double deltaLength = (double)(mult * baseLengthChange); double deltaGirth = (double)(mult * baseGirthChange); target.cocks[0].DeltaLengthAndGirth(deltaLength, deltaGirth); } if (target.corruption >= 5) { double corrLoss = Math.Min(0.1 * target.corruptionTrue + 5, target.corruptionTrue); target.DeltaCreatureStats(corr: -corrLoss, lib: corrLoss); //Lose corruption and gains that much libido } else { target.ChangeLibido(5); } if (target.femininity >= 60 || target.femininity <= 40) { if (target.femininity >= 60) { target.femininity.IncreaseMasculinity(3); } else { target.femininity.IncreaseFemininity(3); } } target.ChangeLust(0.2 * target.libidoTrue + 5); } //this is the fallthrough that occurs when a tf item goes through all the changes, but does not proc enough of them to exit early. it will apply however many changes //occurred, then return the contents of the stringbuilder. return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); }
protected abstract string MadeHornsBigger(Creature target, HornData oldHorns);
private static string NoHornsLongDesc(HornData horns, bool alternateFormat, bool pluralIfApplicable, out bool isPlural) { throw new InDevelopmentExceptionThatBreaksOnRelease(); }
protected virtual string ChangeOrGrowHornsText(Creature target, HornData oldHorns) { return(target.horns.TransformFromText(oldHorns)); }
protected internal override string DoTransformation(Creature target, out bool isBadEnd) { isBadEnd = false; //huh. no rng rolls, just starts at 3. cool int changeCount = GenerateChangeCount(target, null, 3); int remainingChanges = changeCount; StringBuilder sb = new StringBuilder(); //For all of these, any text regarding the transformation should be instead abstracted out as an abstract string function. append the result of this abstract function //to the string builder declared above (aka sb.Append(FunctionCall(variables));) string builder is just a fancy way of telling the compiler that you'll be creating a //long string, piece by piece, so don't do any crazy optimizations first. //the initial text for starting the transformation. feel free to add additional variables to this if needed. sb.Append(InitialTransformationText(target)); //Add any free changes here - these can occur even if the change count is 0. these include things such as change in stats (intelligence, etc) //change in height, hips, and/or butt, or other similar stats. //this will handle the edge case where the change count starts out as 0. if (remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } //Any transformation related changes go here. these typically cost 1 change. these can be anything from body parts to gender (which technically also changes body parts, //but w/e). You are required to make sure you return as soon as you've applied changeCount changes, but a single line of code can be applied at the end of a change to do //this for you. //paste this line after any tf is applied, and it will: automatically decrement the remaining changes count. if it becomes 0 or less, apply the total number of changes //underwent to the target's change count (if applicable) and then return the StringBuilder content. //if (--remainingChanges <= 0) return ApplyChangesAndReturn(target, sb, changeCount - remainingChanges); //Stats and genital changes if (Utils.Rand(2) == 0) { target.ChangeLust(25); if (target.relativeLibido < 100) { if (target.relativeLibido < 50) { target.ChangeLibido(1); } target.ChangeLibido(1); } } C**k smallest = target.genitals.ShortestCock(); if (target.hasCock && smallest.length < 12 && Utils.Rand(3) == 0) { smallest.IncreaseLength(); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } C**k thinnest = target.genitals.ThinnestCock(); if (target.hasCock && thinnest.girth < 4 && Utils.Rand(3) == 0) { thinnest.IncreaseThickness(0.5); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (target.balls.count > 0 && target.genitals.cumMultiplier < 50 && Utils.Rand(3) == 0) { target.ChangeLust(20); if (target.genitals.cumMultiplier < 10) { target.genitals.IncreaseCumMultiplier(1); } if (target.genitals.cumMultiplier < 50) { target.genitals.IncreaseCumMultiplier(0.5); } if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (Utils.Rand(3) == 0 && target.hasVagina && target.genitals.standardBonusVaginalCapacity > 0) { target.genitals.DecreaseBonusVaginalCapacity((ushort)(Utils.Rand(5) + 5)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (Utils.Rand(3) == 0 && target.hasVagina && !target.hasCock) { target.RemoveAllVaginas(); target.AddCock(CockType.HUMAN, 6, 1); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (Utils.Rand(3) == 0 && target.hasCock && !target.balls.hasBalls) { target.balls.GrowBalls(); target.HaveGenericCockOrgasm(0, true, true); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Transformations //Neck restore if (target.neck.type != NeckType.HUMANOID && Utils.Rand(4) == 0) { target.RestoreNeck(); } //Rear body restore if (!target.back.isDefault && Utils.Rand(5) == 0) { target.RestoreBack(); } //Ovi perk loss if (target.womb.canRemoveOviposition && Utils.Rand(5) == 0) { if (target.womb.ClearOviposition()) { sb.Append(RemovedOvipositionText(target)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //remove anything with a scaly or partially scaly body. now affects cockatrice too! if (Utils.Rand(3) == 0 && target.body.HasAny(EpidermisType.SCALES)) { BodyData oldData = target.body.AsReadOnlyData(); target.RestoreBody(); sb.Append(RestoredBodyText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (Utils.Rand(3) == 0 && target.arms.type != ArmType.HUMAN) { ArmData oldData = target.arms.AsReadOnlyData(); target.RestoreArms(); sb.Append(RestoredArmsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (Utils.Rand(4) == 0 && target.lowerBody.type != LowerBodyType.CLOVEN_HOOVED) { LowerBodyData oldData = target.lowerBody.AsReadOnlyData(); target.UpdateLowerBody(LowerBodyType.CLOVEN_HOOVED); sb.Append(UpdateLowerBodyText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (Utils.Rand(3) == 0 && target.lowerBody.type == LowerBodyType.CLOVEN_HOOVED && target.horns.type == HornType.GOAT && target.face.type != FaceType.HUMAN) { FaceData oldData = target.face.AsReadOnlyData(); target.UpdateFace(FaceType.HUMAN); sb.Append(UpdateFaceText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //MOD: anything with scales will prevent this, including partial scales (a la cockatrice). since body is reworked a lot of these checks are hard to port, //but this i think is the closest i can get. if (Utils.Rand(4) == 0 && !target.body.HasAny(EpidermisType.SCALES) && target.ears.type != EarType.ELFIN) { EarData oldData = target.ears.AsReadOnlyData(); target.UpdateEars(EarType.ELFIN); sb.Append(UpdateEarsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (Utils.Rand(3) == 0 && target.horns.type == HornType.NONE) { HornData oldData = target.horns.AsReadOnlyData(); target.UpdateHorns(HornType.GOAT); sb.Append(UpdateHornsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Mod Note: Horns: if (Utils.Rand(3) == 0 && target.horns.type != HornType.GOAT) { HornData oldData = target.horns.AsReadOnlyData(); target.UpdateHorns(HornType.GOAT); sb.Append(UpdateHornsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (Utils.Rand(3) == 0 && target.horns.type == HornType.GOAT && target.horns.CanStrengthen) { target.horns.StrengthenTransform(); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (Utils.Rand(4) == 0 && target.antennae.type != AntennaeType.NONE) { AntennaeData oldData = target.antennae.AsReadOnlyData(); target.RestoreAntennae(); sb.Append(RestoredAntennaeText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (Utils.Rand(3) == 0 && target.cocks.Count == 1 && target.cocks[0].type != CockType.HUMAN) { target.genitals.UpdateCock(0, CockType.HUMAN); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (Utils.Rand(3) == 0 && target.cocks.Count > 1 && !target.genitals.OnlyHasCocksOfType(CockType.HUMAN)) { target.genitals.UpdateCock(target.cocks.First(x => x.type != CockType.HUMAN), CockType.HUMAN); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (Utils.Rand(3) == 0 && target.tail.type != TailType.SATYR) { TailData oldData = target.tail.AsReadOnlyData(); target.UpdateTail(TailType.SATYR); sb.Append(UpdateTailText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //this is the fallthrough that occurs when a tf item goes through all the changes, but does not proc enough of them to exit early. it will apply however many changes //occurred, then return the contents of the stringbuilder. return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); }
protected override string RestoredHornsText(Creature target, HornData oldData) { return(GlobalStrings.NewParagraph() + "You feel your horns crumble, falling apart in large chunks until they flake away into nothing."); }
protected internal override string DoTransformation(Creature target, out bool isBadEnd) { isBadEnd = false; //by default, this is 2 rolls at 50%, so a 25% chance of 0 additional tfs, 50% chance of 1 additional tf, 25% chance of 2 additional tfs. //also takes into consideration any perks that increase or decrease tf effectiveness. if you need to roll out your own, feel free to do so. int changeCount = GenerateChangeCount(target, new int[] { 2, 2 }); int remainingChanges = changeCount; StringBuilder sb = new StringBuilder(); //For all of these, any text regarding the transformation should be instead abstracted out as an abstract string function. append the result of this abstract function //to the string builder declared above (aka sb.Append(FunctionCall(variables));) string builder is just a fancy way of telling the compiler that you'll be creating a //long string, piece by piece, so don't do any crazy optimizations first. //the initial text for starting the transformation. feel free to add additional variables to this if needed. //Add any free changes here - these can occur even if the change count is 0. these include things such as change in stats (intelligence, etc) //change in height, hips, and/or butt, or other similar stats. double crit = 0; if (Utils.Rand(100) < 15) { crit = Utils.Rand(20) / 10.0 + 2; } bool hasCrit() => crit > 1; sb.Append(InitialTransformationText(target, crit)); //STAT CHANGES - TOU SPE INT RANDOM CHANCE, LIB LUST COR ALWAYS UPPED target.DeltaCreatureStats(lib: 1 + Utils.Rand(2), lus: 5 + Utils.Rand(10), corr: 1 + Utils.Rand(5)); if (target.relativeToughness < 70 && Utils.Rand(3) == 0) { double delta = target.ChangeToughness(crit); sb.Append(IncreasedToughnessText(crit, delta)); } if (target.relativeSpeed > 30 && Utils.Rand(7) == 0) { double loss = target.DecreaseSpeed(crit); sb.Append(DecreasedSpeedText(crit, loss)); } if (target.relativeIntelligence < 60 && Utils.Rand(7) == 0) { double delta = target.ChangeIntelligence(crit); sb.Append(IncreasedIntelligenceText(crit, delta)); } //handle edge case where we start at 0. if (remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } //Non-free changes. //if (--remainingChanges <= 0) return ApplyChangesAndReturn(target, sb, changeCount - remainingChanges); //MUTATIONZZZZZ //PRE-CHANGES: become biped, remove horns, remove wings, give human tongue, remove claws, remove antennea //no claws if (Utils.Rand(4) == 0 && target.arms.hands.isClaws) { ArmData oldData = target.arms.AsReadOnlyData(); if (target.RestoreArms()) { sb.Append(RestoredArmsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //remove antennae if (target.antennae.type != AntennaeType.NONE && Utils.Rand(3) == 0) { AntennaeData oldData = target.antennae.AsReadOnlyData(); target.RestoreAntennae(); sb.Append(RestoredAntennaeText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //remove horns if (target.horns.type != HornType.NONE && Utils.Rand(3) == 0) { HornData oldData = target.horns.AsReadOnlyData(); target.RestoreHorns(); sb.Append(RestoredHornsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //remove wings if ((target.wings.type != WingType.NONE || target.back.type == BackType.SHARK_FIN) && Utils.Rand(3) == 0) { BackData oldBack = target.back.AsReadOnlyData(); if (target.back.type == BackType.SHARK_FIN) { target.RestoreBack(); } WingData oldWings = target.wings.AsReadOnlyData(); target.RestoreWings(); sb.Append(RestoredBackAndWings(target, oldWings, oldBack)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //give human tongue if (target.tongue.type != TongueType.HUMAN && Utils.Rand(3) == 0) { //MOD NOTE: this was incorrect - this actually was === (equal with strict typechecking) instead of = (assign). so this was an implicit bool. //this is part of the reason why the rework forces all value updates as function calls. the more you know. TongueData oldData = target.tongue.AsReadOnlyData(); target.RestoreTongue(); sb.Append(RestoredTongueText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //remove non-wolf eyes if (Utils.Rand(3) == 0 && target.eyes.type != EyeType.HUMAN && target.eyes.type != EyeType.WOLF) { EyeData oldData = target.eyes.AsReadOnlyData(); target.RestoreEyes(); sb.Append(RestoredEyesText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //normal legs if (target.lowerBody.type != LowerBodyType.WOLF && Utils.Rand(4) == 0) { LowerBodyData oldData = target.lowerBody.AsReadOnlyData(); target.RestoreLowerBody(); sb.Append(RestoredLowerBodyText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //normal arms if (Utils.Rand(4) == 0) { ArmData oldData = target.arms.AsReadOnlyData(); target.RestoreArms(); sb.Append(RestoredArmsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } HairData oldHair = target.hair.AsReadOnlyData(); //remove feather hair if (Utils.Rand(4) == 0 && RemoveFeatheryHair(target)) { sb.Append(RemovedFeatheryHairText(target, oldHair)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //remove basilisk hair if (Utils.Rand(4) == 0 && target.hair.IsBasiliskHair()) { HairData oldData = target.hair.AsReadOnlyData(); target.RestoreHair(); target.hair.SetHairLength(0); target.hair.ResumeNaturalGrowth(); sb.Append(RemovedBasiliskHair(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //MUTATIONZ AT ANY TIME: wolf dick, add/decrease breasts, decrease breast size if above D //get a wolf dick //if ya genderless we give ya a dick cuz we nice like that //MOD: Now respects hyper happy. if (target.gender == Gender.GENDERLESS && !hyperHappy) { target.genitals.AddCock(CockType.WOLF, Utils.Rand(4) + 4, Utils.Rand(8) / 4.0 + 0.25, 1.5); sb.Append(BecameMaleByGrowingCock(target)); target.DeltaCreatureStats(lib: 3, sens: 2, lus: 25); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //if ya got a dick that's ok too we'll change it to wolf //MOD NOTE: but only if you don't only have wolf cocks, of course (because if they are all wolf cocks, we can't make anything wolf cocks, duh). if (target.hasCock && !target.genitals.OnlyHasCocksOfType(CockType.WOLF) && Utils.RandBool()) { //MOD NOTE: no longer shamelessly copy/pasted from dog c**k, because we have better ways of looping in C#. C**k firstNonWolf = target.cocks.First(x => x.type != CockType.WOLF); CockData oldData = firstNonWolf.AsReadOnlyData(); //Select first non-wolf c**k //MOD: now using type description because we can, so the fact this used generic is irrelevant now :) if (firstNonWolf.type == CockType.HORSE) { //horses get changes if (firstNonWolf.length > 6) { firstNonWolf.DecreaseLength(2); } else { firstNonWolf.DecreaseLength(.5); } firstNonWolf.IncreaseThickness(.5); } target.DeltaCreatureStats(sens: 3, lus: 5 * crit); target.genitals.UpdateCockWithKnot(firstNonWolf, CockType.WOLF, 1.5); firstNonWolf.IncreaseThickness(2); sb.Append(ChangedCockToWolf(target, oldData, oldData.cockIndex)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //titties for those who got titties //wolfs have 8 nips so, 4 rows max. fen has no power here I'm making a wolf not a dog. //MOD: still stolen shamelessly from dog and updated, but now with the modern format. woo! //MOD: if breasts can be updated (not flat) and we flip a coin. if (target.genitals.BiggestCupSize() > CupSize.FLAT && Utils.RandBool()) { if (target.breasts.Count < 4) { byte breastCount = (byte)target.breasts.Count; BreastCollectionData oldBreastData = target.genitals.allBreasts.AsReadOnlyData(); //in vanilla code, we had some strange checks here that required the first row (and only the first row) be a certain size. //now, we check all the rows, but no longer require any of them to be a certain size. instead, if it's not the right size, we make it that size, //then add the row. so, for two rows, your first row must be at least a B-Cup. for 3: first must be a C cup, second an A cup. //if we supported 4 rows, it'd be D, B, A. for (int x = 0; x < target.breasts.Count; x++) { CupSize requiredSize = (CupSize)(byte)(target.breasts.Count - x); if (x == 0) { requiredSize++; } if (target.breasts[x].cupSize < requiredSize) { target.breasts[x].SetCupSize(requiredSize); } } target.genitals.AddBreastRow(target.breasts[breastCount - 1].cupSize.ByteEnumSubtract(1)); bool doCrit = false, uberCrit = false; if (target.breasts.Count == 2) { target.IncreaseCreatureStats(lus: 5, sens: 6); } else if (hasCrit()) { doCrit = true; if (crit > 2) { target.IncreaseCreatureStats(sens: 6, lus: 15); uberCrit = true; } else { target.IncreaseCreatureStats(sens: 3, lus: 10); } } sb.Append(UpdateAndGrowAdditionalRowText(target, oldBreastData, doCrit, uberCrit)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } else { BreastCollectionData oldBreastData = target.genitals.allBreasts.AsReadOnlyData(); //only call the normalize text if we actually did anything. related, anthro breasts now returns a bool. thanks, fox tfs. if (target.genitals.AnthropomorphizeBreasts()) { sb.Append(NormalizedBreastSizeText(target, oldBreastData)); } } } //Remove a breast row if over 4. afaik this should never happen. if (target.breasts.Count > 4 && Utils.Rand(3) == 0) { var oldData = target.breasts[target.breasts.Count - 1].AsReadOnlyData(); target.genitals.RemoveBreastRows(1); sb.Append(RemovedExcessRow(target, oldData)); } //Grow breasts if has v****a and has no breasts/nips //Shrink breasts if over D-cup CupSize targetSize = EnumHelper.Max(target.genitals.smallestPossibleCupSize, CupSize.D); if (!hyperHappy && target.genitals.BiggestCupSize() > targetSize && Utils.Rand(3) == 0) { BreastCollectionData oldCollection = target.genitals.allBreasts.AsReadOnlyData(); bool changedAnything = false; foreach (Breasts row in target.breasts) { //If this row is over threshhold if (row.cupSize > targetSize) { //Big change if (row.cupSize > CupSize.EE_BIG) { changedAnything |= row.ShrinkBreasts((byte)(2 + Utils.Rand(3))) > 0; } //Small change else { changedAnything |= row.ShrinkBreasts() > 0; } //Increment changed rows } } //Count shrinking if (changedAnything) { sb.Append(ShrunkRowsText(target, oldCollection)); remainingChanges--; if (remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //MUTATIONZ LEVEL 1: fur, stop hair growth, ears, tail //Gain fur if (Utils.Rand(5) == 0 && !target.body.IsFurBodyType()) { BodyData oldData = target.body.AsReadOnlyData(); Species.WOLF.GetRandomFurColors(out FurColor primary, out FurColor underbody); if (FurColor.IsNullOrEmpty(underbody)) { target.UpdateBody(BodyType.UNDERBODY_FUR, primary); } else { target.UpdateBody(BodyType.UNDERBODY_FUR, primary, underbody); } sb.Append(UpdateBodyText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Ears time if (Utils.Rand(3) == 0 && target.ears.type != EarType.WOLF) { EarData oldData = target.ears.AsReadOnlyData(); target.UpdateEars(EarType.WOLF); sb.Append(UpdateEarsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Wolf tail if (Utils.Rand(3) == 0 && target.tail.type != TailType.WOLF) { TailData oldData = target.tail.AsReadOnlyData(); target.UpdateTail(TailType.WOLF); sb.Append(UpdateTailText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Sets hair normal if (target.hair.type != HairType.NORMAL && Utils.Rand(3) == 0) { HairData oldData = target.hair.AsReadOnlyData(); target.RestoreHair(); sb.Append(RestoreHairText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //MUTATIONZ LEVEL 2: fur->arms fur+tail+ears->face stophair->nohair fur+tail->legs //gain wolf face if (target.face.type != FaceType.WOLF && target.ears.type == EarType.WOLF && target.tail.type == TailType.WOLF && target.body.IsFurBodyType() && Utils.Rand(5) == 0) { FaceData oldData = target.face.AsReadOnlyData(); target.UpdateFace(FaceType.WOLF); sb.Append(UpdateFaceText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //legz if (target.lowerBody.legCount == 2 && target.lowerBody.type != LowerBodyType.WOLF && target.tail.type == TailType.WOLF && target.body.IsFurBodyType() && Utils.Rand(4) == 0) { //Hooman feets //Hooves -> Paws LowerBodyData oldData = target.lowerBody.AsReadOnlyData(); target.UpdateLowerBody(LowerBodyType.WOLF); sb.Append(UpdateLowerBodyText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //MUTATIONZ LEVEL 3: face->eyes if (target.eyes.type != EyeType.WOLF && target.face.type == FaceType.WOLF && Utils.Rand(4) == 0) { EyeData oldData = target.eyes.AsReadOnlyData(); target.UpdateEyes(EyeType.WOLF); sb.Append(UpdateEyesText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //MISC CRAP //Neck restore if (target.neck.type != NeckType.HUMANOID && Utils.Rand(4) == 0) { NeckData oldData = target.neck.AsReadOnlyData(); target.RestoreNeck(); sb.Append(RestoredNeckText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Rear body restore if (!target.back.isDefault && Utils.Rand(5) == 0) { BackData oldData = target.back.AsReadOnlyData(); target.RestoreBack(); sb.Append(RestoredBackText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Ovi perk loss if (target.womb.canRemoveOviposition && Utils.Rand(5) == 0) { target.womb.ClearOviposition(); sb.Append(ClearOvipositionText(target)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (Utils.Rand(3) == 0) { var res = target.build.ChangeMuscleToneToward(100, 4); sb.Append(AdjustToneText(target, 4, res)); } if (Utils.Rand(3) == 0) { var adjustedAmount = target.build.ChangeThicknessToward(75, 3); sb.Append(AdjustThicknessText(target, adjustedAmount)); } //this is the fallthrough that occurs when a tf item goes through all the changes, but does not proc enough of them to exit early. it will apply however many changes //occurred, then return the contents of the stringbuilder. return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); }
protected internal override string DoTransformation(Creature target, out bool isBadEnd) { isBadEnd = false; //by default, this is 2 rolls at 50%, so a 25% chance of 0 additional tfs, 50% chance of 1 additional tf, 25% chance of 2 additional tfs. //also takes into consideration any perks that increase or decrease tf effectiveness. if you need to roll out your own, feel free to do so. int changeCount = GenerateChangeCount(target, new int[] { 2, 3, 3 }, 1, 2); int remainingChanges = changeCount; StringBuilder sb = new StringBuilder(); //For all of these, any text regarding the transformation should be instead abstracted out as an abstract string function. append the result of this abstract function //to the string builder declared above (aka sb.Append(FunctionCall(variables));) string builder is just a fancy way of telling the compiler that you'll be creating a //long string, piece by piece, so don't do any crazy optimizations first. //the initial text for starting the transformation. feel free to add additional variables to this if needed. sb.Append(InitialTransformationText(target)); //Add any free changes here - these can occur even if the change count is 0. these include things such as change in stats (intelligence, etc) //change in height, hips, and/or butt, or other similar stats. //this will handle the edge case where the change count starts out as 0. if (remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } //Any transformation related changes go here. these typically cost 1 change. these can be anything from body parts to gender (which technically also changes body parts, //but w/e). You are required to make sure you return as soon as you've applied changeCount changes, but a single line of code can be applied at the end of a change to do //this for you. //paste this line after any tf is applied, and it will: automatically decrement the remaining changes count. if it becomes 0 or less, apply the total number of changes //underwent to the target's change count (if applicable) and then return the StringBuilder content. //if (--remainingChanges <= 0) return ApplyChangesAndReturn(target, sb, changeCount - remainingChanges); //STATS //Strength h if (Utils.Rand(3) == 0) { //weaker characters gain more if (target.relativeStrength <= 50) { //very weak targets gain more if (target.relativeStrength <= 20) { target.ChangeStrength(3); } else { target.ChangeStrength(2); } } //stronger characters gain less else { //small growth if over 75 if (target.relativeStrength >= 75) { target.ChangeStrength(.5); } //faster from 50-75 else { target.ChangeStrength(1); } } //Chance of speed drop if (Utils.Rand(2) == 0 && target.relativeStrength > 50) { target.ChangeSpeed(-1); } } //Toughness (chance of - sensitivity) if (Utils.Rand(3) == 0) { //weaker characters gain more if (target.relativeToughness <= 50) { //very weak targets gain more if (target.relativeToughness <= 20) { target.ChangeToughness(3); } else { target.ChangeToughness(2); } } //stronger characters gain less else { //small growth if over 75 if (target.relativeToughness >= 75) { target.ChangeToughness(.5); } //faster from 50-75 else { target.ChangeToughness(1); } } //chance of less sensitivity if (Utils.Rand(2) == 0 && target.relativeSensitivity > 10) { if (target.relativeToughness > 75) { target.ChangeSensitivity(-3); } if (target.relativeToughness <= 75 && target.relativeToughness > 50) { target.ChangeSensitivity(-2); } if (target.relativeToughness <= 50) { target.ChangeSensitivity(-3); } } } //SEXUAL //Boosts ball size MORE than equinum :D:D:D:D:D:D: if (Utils.Rand(2) == 0 && target.balls.size <= 5 && target.genitals.HasAnyCocksOfType(CockType.HORSE)) { //Chance of ball growth if not 3" yet if (target.balls.count == 0) { target.balls.GrowBalls(); target.DeltaCreatureStats(lib: 2, lus: 5); } else { target.balls.EnlargeBalls(1); target.DeltaCreatureStats(lib: 1, lus: 3); } if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Neck restore if (target.neck.type != NeckType.HUMANOID && Utils.Rand(4) == 0) { target.RestoreNeck(); } //Rear body restore if (!target.back.isDefault && Utils.Rand(5) == 0) { target.RestoreBack(); } //Ovi perk loss if (target.womb.canRemoveOviposition && Utils.Rand(5) == 0) { target.womb.ClearOviposition(); //if (--remainingChanges <= 0) return ApplyChangesAndReturn(target, sb, changeCount - remainingChanges); } //Restore arms to become human arms again if (Utils.Rand(4) == 0) { target.RestoreArms(); } //+hooves if (target.lowerBody.type != LowerBodyType.HOOVED) { if (Utils.Rand(3) == 0) { //Catch-all target.UpdateLowerBody(LowerBodyType.HOOVED); target.ChangeSpeed(1); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } if (!hyperHappy) { //Kills v****a size (and eventually the whole v****a) if (target.vaginas.Count > 0) { //behavior not defined for multi vag. i' VaginalLooseness minLooseness = target.genitals.minVaginalLooseness; // if (target.genitals.LargestVaginalLooseness() > minLooseness) { //tighten that bitch up! foreach (V****a vag in target.vaginas) { if (vag.looseness > minLooseness) { vag.DecreaseLooseness(); } } } else if (target.vaginas.Count > 1) { target.RemoveExtraVaginas(); } else { if (target.cocks.Count == 0) { target.genitals.AddCock(CockType.HORSE, target.vaginas[0].c**t.length + 2, 1); } //Goodbye womanhood! target.genitals.RemoveAllVaginas(); } if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //-Remove extra breast rows if (target.breasts.Count > 1 && Utils.Rand(3) == 0) { target.RemoveExtraBreastRows(); } //Shrink boobages till they are normal else if (Utils.Rand(2) == 0 && target.breasts.Count > 0) { //Single row CupSize smallestCup = EnumHelper.Max(target.genitals.smallestPossibleCupSize, CupSize.B); bool changedAny = false; foreach (Breasts row in target.breasts.Where(x => x.cupSize > smallestCup)) { changedAny |= row.ShrinkBreasts() > 0; if (row.cupSize > CupSize.E_BIG) { changedAny |= row.ShrinkBreasts() > 0; } } if (changedAny && --remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //Boosts c**k size up to 36"x5". //MOD: Used linq: find the first c**k that matches the requirement, or if no cocks exist, return null. C**k firstCockToGrow = target.cocks.FirstOrDefault(x => x.type == CockType.HORSE && x.length < 36 || x.girth < 5); //MOD: thus, we can simply place the null check here to see if we actually grow it. if (!(firstCockToGrow is null) && Utils.Rand(2) == 0) { if (firstCockToGrow.girth < 5 && firstCockToGrow.length < 36) { firstCockToGrow.IncreaseThickness(1); firstCockToGrow.IncreaseLength(2 + Utils.Rand(8)); } else if (firstCockToGrow.length < 36) { firstCockToGrow.IncreaseLength(2 + Utils.Rand(8)); } else { firstCockToGrow.IncreaseThickness(1); } if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Morph dick to horsediiiiick C**k firstNonHorse = target.cocks.FirstOrDefault(x => x.type != CockType.HORSE); if (!(firstNonHorse is null) && Utils.Rand(2) == 0) { //Text for humandicks or others //Text for dogdicks target.genitals.UpdateCockWithLength(firstNonHorse, CockType.HORSE, firstNonHorse.length + 4); target.DeltaCreatureStats(lib: 5, sens: 4, lus: 35); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Males go into rut if (Utils.Rand(4) == 0) { if (target.GoIntoRut()) { remainingChanges--; if (remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //Anti-masturbation status if (Utils.Rand(4) == 0 && !target.HasTimedEffect <Dysfunction>() && target.gender != Gender.GENDERLESS) { target.AddTimedEffect <Dysfunction>(); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Appearance shit: //Tail, Ears, Hooves, Horns, Height (no prereq), Face //+height up to 9 foot //Mod note: rand(1.7) seriously? rand only works with ints, guys. that's straight from vanilla. though to be fair, it's not caught there b/c actionscript is shit. if (Utils.Rand(17) < 10 && target.build.heightInInches < 108) { byte temp = (byte)(Utils.Rand(5) + 3); //Slow rate of growth near ceiling if (target.build.heightInInches > 90) { temp /= 2; } //Never 0 if (temp == 0) { temp = 1; } //Flavor texts. Flavored like 1950's cigarettes. Yum. target.build.IncreaseHeight(temp); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Face change, requires Ears + Height + Hooves if (target.ears.type == EarType.COW && target.lowerBody.type == LowerBodyType.HOOVED && target.build.heightInInches >= 90 && target.face.type != FaceType.COW_MINOTAUR && Utils.Rand(3) == 0) { FaceData oldData = target.face.AsReadOnlyData(); target.UpdateFace(FaceType.COW_MINOTAUR); sb.Append(UpdateFaceText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //+mino horns require ears/tail if (Utils.Rand(3) == 0 && target.ears.type == EarType.COW && target.tail.type == TailType.COW) { //New horns or expanding mino horns if (target.horns.type == HornType.BOVINE || target.horns.type == HornType.NONE) { //Get bigger if target has horns if (target.horns.type == HornType.BOVINE) { //Fems horns don't get bigger. if (target.vaginas.Count > 0) { if (target.horns.significantHornSize > 4) { target.genitals.AddPentUpTime(200); target.ChangeLust(20); } else { target.horns.StrengthenTransform(2); } if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Males horns get 'uge. else { target.horns.StrengthenTransform(2); //boys get a cum refill sometimes if (Utils.Rand(2) == 0) { target.genitals.AddPentUpTime(200); target.ChangeLust(20); } if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //If no horns yet.. else { HornData oldData = target.horns.AsReadOnlyData(); target.UpdateHorns(HornType.BOVINE); sb.Append(UpdateHornsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //Not mino horns, change to cow-horns else { HornData oldData = target.horns.AsReadOnlyData(); target.UpdateHorns(HornType.BOVINE); sb.Append(UpdateHornsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //+cow ears - requires tail if (target.ears.type != EarType.COW && target.tail.type == TailType.COW && Utils.Rand(2) == 0) { EarData oldData = target.ears.AsReadOnlyData(); target.UpdateEars(EarType.COW); sb.Append(UpdateEarsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //+cow tail if (Utils.Rand(2) == 0 && target.tail.type != TailType.COW) { TailData oldData = target.tail.AsReadOnlyData(); target.UpdateTail(TailType.COW); sb.Append(UpdateTailText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } // Remove gills if (Utils.Rand(4) == 0 && !target.gills.isDefault) { GillData oldData = target.gills.AsReadOnlyData(); target.RestoreGills(); sb.Append(RestoredGillsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (Utils.Rand(4) == 0 && target.ass.wetness > target.ass.minWetness) { target.ass.DecreaseWetness(); AnalLooseness targetLooseness = EnumHelper.Max(AnalLooseness.LOOSE, target.ass.minLooseness); if (target.ass.looseness > targetLooseness) { target.ass.DecreaseLooseness(); } if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Give you that mino build! //Default if (remainingChanges == changeCount) { if (target.balls.count > 0) { target.genitals.AddPentUpTime(200); } (target as CombatCreature)?.AddHP(50); target.ChangeLust(50); } //this is the fallthrough that occurs when a tf item goes through all the changes, but does not proc enough of them to exit early. it will apply however many changes //occurred, then return the contents of the stringbuilder. return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); }
protected internal override string DoTransformation(Creature target, out bool isBadEnd) { isBadEnd = false; int changeCount = GenerateChangeCount(target, new int[] { 2, 2 }); int remainingChanges = changeCount; StringBuilder sb = new StringBuilder(); //sb.Append(InitialTransformText(target)); // Stat changes! if (target.intelligence > 90 && Utils.Rand(3) == 0) { target.ChangeIntelligence(-(Utils.Rand(2) + 1)); } if (Utils.Rand(3) == 0) { target.ChangeToughness(Utils.Rand(2) + 1); } if (target.speed < 75 && Utils.Rand(3) == 0) { target.ChangeSpeed(Utils.Rand(2) + 1); } if (Utils.Rand(3) == 0) { target.ChangeSensitivity(-(Utils.Rand(2) + 1)); } if (Utils.Rand(3) == 0) { target.ChangeCorruption(-(Utils.Rand(3) + 2)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (target.heightInInches > 67 && Utils.Rand(2) == 0) { target.build.DecreaseHeight((byte)(1 + Utils.Rand(4))); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (target.butt.size < 6 && Utils.Rand(3) == 0) { if (target.butt.size < 5) { target.butt.GrowButt((byte)(1 + Utils.Rand(2))); } else { target.butt.GrowButt(1); } } if (remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } //Neck restore if (target.neck.type != NeckType.defaultValue && Utils.Rand(4) == 0) { NeckData oldData = target.neck.AsReadOnlyData(); target.RestoreNeck(); sb.Append(RestoredNeckText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Rear body restore if (target.back.type != BackType.defaultValue && Utils.Rand(5) == 0) { BackData oldData = target.back.AsReadOnlyData(); target.RestoreBack(); sb.Append(RestoredBackText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (target.ears.type != EarType.SHEEP && Utils.Rand(3) == 0) { EarData oldData = target.ears.AsReadOnlyData(); target.UpdateEars(EarType.SHEEP); sb.Append(UpdateEarsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (target.tail.type != TailType.SHEEP && Utils.Rand(3) == 0) { TailData oldData = target.tail.AsReadOnlyData(); target.UpdateTail(TailType.SHEEP); sb.Append(UpdateTailText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (target.lowerBody.type != LowerBodyType.CLOVEN_HOOVED && target.tail.type == TailType.SHEEP && Utils.Rand(3) == 0) { LowerBodyData oldData = target.lowerBody.AsReadOnlyData(); target.UpdateLowerBody(LowerBodyType.CLOVEN_HOOVED); sb.Append(UpdateLowerBodyText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (target.horns.type != HornType.SHEEP && target.ears.type == EarType.SHEEP && Utils.Rand(3) == 0) { HornData oldData = target.horns.AsReadOnlyData(); target.UpdateHorns(HornType.SHEEP); sb.Append(UpdateHornsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (Utils.Rand(3) == 0 && target.lowerBody.type == LowerBodyType.CLOVEN_HOOVED && target.horns.type == HornType.SHEEP && target.tail.type == TailType.SHEEP && target.ears.type == EarType.SHEEP && target.body.type != BodyType.WOOL) { BodyData oldData = target.body.AsReadOnlyData(); target.UpdateBody(BodyType.WOOL); sb.Append(UpdateBodyText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //shrinks horns if too feminine and grows if masculine if (target.horns.type == HornType.SHEEP && target.body.type == BodyType.WOOL && target.femininity <= 45 && Utils.Rand(3) == 0) { HornData oldHornData = target.horns.AsReadOnlyData(); target.horns.StrengthenTransform(); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (target.body.type == BodyType.WOOL && target.hair.type != HairType.WOOL && target.femininity >= 65 && Utils.Rand(3) == 0) { HairData oldHair = target.hair.AsReadOnlyData(); target.UpdateHair(HairType.WOOL); } if (target.hips.size < 10 && target.femininity >= 65 && Utils.Rand(3) == 0) { byte oldSize = target.hips.size; if (target.hips.size == 9) { target.hips.GrowHips(1); } else { target.hips.GrowHips((byte)(Utils.Rand(2) + 1)); } if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } ; } if (target.breasts[0].cupSize < CupSize.DD && target.femininity >= 65 && Utils.Rand(3) == 0) { if (target.breasts[0].cupSize == CupSize.D) { target.breasts[0].GrowBreasts(1); } else { target.breasts[0].GrowBreasts((byte)(Utils.Rand(2) + 1)); } } return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); }
protected internal override string DoTransformation(Creature target, out bool isBadEnd) { isBadEnd = false; //by default, this is 2 rolls at 50%, so a 25% chance of 0 additional tfs, 50% chance of 1 additional tf, 25% chance of 2 additional tfs. //also takes into consideration any perks that increase or decrease tf effectiveness. if you need to roll out your own, feel free to do so. int changeCount = GenerateChangeCount(target, new int[] { 2, 2, 3, 4 }); int remainingChanges = changeCount; StringBuilder sb = new StringBuilder(); //For all of these, any text regarding the transformation should be instead abstracted out as an abstract string function. append the result of this abstract function //to the string builder declared above (aka sb.Append(FunctionCall(variables));) string builder is just a fancy way of telling the compiler that you'll be creating a //long string, piece by piece, so don't do any crazy optimizations first. //the initial text for starting the transformation. feel free to add additional variables to this if needed. sb.Append(InitialTransformationText(target)); //Add any free changes here - these can occur even if the change count is 0. these include things such as change in stats (intelligence, etc) //change in height, hips, and/or butt, or other similar stats. //this will handle the edge case where the change count starts out as 0. if (remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } //Any transformation related changes go here. these typically cost 1 change. these can be anything from body parts to gender (which technically also changes body parts, //but w/e). You are required to make sure you return as soon as you've applied changeCount changes, but a single line of code can be applied at the end of a change to do //this for you. //paste this line after any tf is applied, and it will: automatically decrement the remaining changes count. if it becomes 0 or less, apply the total number of changes //underwent to the target's change count (if applicable) and then return the StringBuilder content. //if (--remainingChanges <= 0) return ApplyChangesAndReturn(target, sb, changeCount - remainingChanges); #warning fix me int ngPlus(int value) => value; if (target.speed < ngPlus(100) && Utils.Rand(3) == 0) { //+3 spe if less than 50 if (target.speed < ngPlus(50)) { target.ChangeSpeed(1); } //+2 spe if less than 75 if (target.speed < ngPlus(75)) { target.ChangeSpeed(1); } //+1 if above 75. target.ChangeSpeed(1); } if (target.toughness > ngPlus(80) && Utils.Rand(4) == 0) { target.ChangeToughness(-1); } //-Reduces sensitivity. if (target.sensitivity > 20 && Utils.Rand(3) == 0) { target.ChangeSensitivity(-1); } //Raises libido greatly to 50, then somewhat to 75, then slowly to 100. if (target.libido < 100 && Utils.Rand(3) == 0) { //+3 lib if less than 50 if (target.libido < 50) { target.ChangeLibido(1); } //+2 lib if less than 75 if (target.libido < 75) { target.ChangeLibido(1); } //+1 if above 75. target.ChangeLibido(1); } //Sexual changes //-Lactation stoppage. if (target.genitals.isLactating && Utils.Rand(4) == 0) { if (target.HasPerk <Feeder>()) { target.RemovePerk <Feeder>(); } target.genitals.SetLactationTo(LactationStatus.NOT_LACTATING); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //-Nipples reduction to 1 per tit. if (target.genitals.hasQuadNipples && Utils.Rand(4) == 0) { target.genitals.SetQuadNipples(false); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //-Remove extra breast rows if (target.breasts.Count > 1 && Utils.Rand(3) == 0 && !hyperHappy) { target.RemoveExtraBreastRows(); } //-Butt > 5 - decrease butt size if (target.butt.size > 5 && Utils.Rand(4) == 0) { if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } target.butt.ShrinkButt(); } if (target.gender.HasFlag(Gender.FEMALE)) { CupSize minCup = EnumHelper.Max(CupSize.D, target.genitals.smallestPossibleFemaleCupSize); //Breasts > D cup - Decrease breast size by up to 3 cups //MOD NOTE: Now respects minimum cup size from perks. if (target.gender.HasFlag(Gender.FEMALE) && target.genitals.BiggestCupSize() > minCup && Utils.Rand(3) == 0) { foreach (Breasts breast in target.breasts) { if (breast.cupSize > CupSize.D) { breast.ShrinkBreasts((byte)(1 + Utils.Rand(3))); } } target.IncreaseSpeed(); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Breasts < B cup - Increase breast size by 1 cup if (target.gender.HasFlag(Gender.FEMALE) && target.genitals.SmallestCupSize() < CupSize.B && Utils.Rand(3) == 0) { for (int i = 0; i < target.breasts.Count; i++) { if (target.breasts[i].cupSize < CupSize.B) { target.breasts[i].GrowBreasts(); } } target.ChangeLibido(1); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Hips > 12 - decrease hip size by 1-3 sizes if (target.hips.size > 12 && Utils.Rand(3) == 0) { target.hips.ShrinkHips((byte)(1 + Utils.Rand(3))); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Hips < 6 - increase hip size by 1-3 sizes if (target.hips.size < 6 && Utils.Rand(3) == 0) { target.hips.GrowHips((byte)(1 + Utils.Rand(3))); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (target.genitals.nippleLength > 1 && Utils.Rand(3) == 0) { target.genitals.SetNippleLength(target.genitals.nippleLength / 2); } VaginalWetness desiredWetness = EnumHelper.Min(target.genitals.maxVaginalWetness, VaginalWetness.SLICK); //MOD NOTE: now respects all vaginas, and the maximum wetness allowed by perks (if applicable) if (target.hasVagina && target.genitals.SmallestVaginalWetness() < desiredWetness && Utils.Rand(4) == 0) { foreach (V****a vag in target.vaginas) { if (vag.wetness < desiredWetness) { vag.IncreaseWetness(); } } if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Increase tone (up to 65) if (target.build.muscleTone < 65 && Utils.Rand(3) == 0) { target.build.ChangeMuscleToneToward(65, 2); } //Decrease thickness (down to 35) if (target.build.thickness > 35 && Utils.Rand(3) == 0) { target.build.ChangeThicknessToward(35, 5); } //Grant oviposition. if (target.womb.canObtainOviposition && Species.COCKATRICE.Score(target) > 3 && Utils.Rand(5) == 0) { target.womb.GrantOviposition(); sb.Append(GrantOvipositionText(target)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } if (target.gender == Gender.MALE) { //Breasts > B cup - decrease by 1 cup size if (target.genitals.BiggestCupSize() > CupSize.B && Utils.Rand(3) == 0) { for (int i = 0; i < target.breasts.Count; i++) { if (target.breasts[i].cupSize > CupSize.B) { target.breasts[i].ShrinkBreasts(); } } target.IncreaseSpeed(); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (target.genitals.nippleLength > 1 && Utils.Rand(3) == 0) { target.genitals.SetNippleLength(target.genitals.nippleLength / 2); } //Hips > 10 - decrease hip size by 1-3 sizes if (target.hips.size > 10 && Utils.Rand(3) == 0) { target.hips.ShrinkHips((byte)(1 + Utils.Rand(3))); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Hips < 2 - increase hip size by 1-3 sizes if (target.hips.size < 2 && Utils.Rand(3) == 0) { target.hips.GrowHips((byte)(1 + Utils.Rand(3))); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Increase tone (up to 70) if (target.build.muscleTone < 70 && Utils.Rand(3) == 0) { target.build.ChangeMuscleToneToward(70, 2); } //Decrease thickness (down to 35) if (target.build.thickness > 35 && Utils.Rand(3) == 0) { target.build.ChangeThicknessToward(35, 5); } } if (target.gender.HasFlag(Gender.MALE)) { //C**k < 6 inches - increase by 1-2 inches C**k shortest = target.genitals.ShortestCock(); if (shortest.length < 6 && Utils.Rand(3) == 0) { double increment = shortest.IncreaseLength(1 + Utils.Rand(2)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } C**k longest = target.genitals.LongestCock(); //Shrink oversized cocks if (longest.length > 16 && Utils.Rand(3) == 0) { longest.DecreaseLength((Utils.Rand(10) + 5) / 10.0); if (longest.girth > 3) { longest.DecreaseThickness((Utils.Rand(4) + 1) / 10.0); } if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } C**k thinnest = target.genitals.ThinnestCock(); //C**k thickness <2 - Increase c**k thickness if (thinnest.girth < 2 && Utils.Rand(3) == 0) { thinnest.IncreaseThickness(1.5); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } int lizardCocks = target.genitals.CountCocksOfType(CockType.LIZARD); if (target.hasCock && target.cocks.Count > lizardCocks && Utils.Rand(4) == 0) { //-Lizard dick - first one if (lizardCocks == 0) { //Actually xform it nau if (target.genitals.hasSheath) { target.genitals.UpdateCock(0, CockType.LIZARD); } else { target.genitals.UpdateCock(0, CockType.LIZARD); } if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } target.DeltaCreatureStats(lib: 3, lus: 10); } //(CHANGE OTHER DICK) //Requires 1 lizard c**k, multiple cocks else //if (target.cocks.Count > 1 && target.cocks.Count > lizardCocks) { C**k firstNonLizard = target.cocks.First(x => x.type != CockType.LIZARD); target.genitals.UpdateCock(firstNonLizard, CockType.LIZARD); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } target.DeltaCreatureStats(lib: 3, lus: 10); } } //MOD NOTE: Worms are being removed??? from the game due to that absolutely shitty license that prevents me from porting any content 'created' by //its creator (forget the name at this time). it's a bad license because it takes credit from other content creators that use its content. that's like saying //the creator of the rubber tire gets credit for all modern car designs. that's bullshit. of course cars require tires, and the original copyright required users //to pay a licensing fee for their use. that didn't grant the copyright holder for rubber tires the credit for the cars that used them. If anyone wants to get ahold //of the og worms creator and get him/her to relax that requirement to make it reasonable (and future content-change/port friendly), we'll see. until then, this is //removed. //For the record, that would grant him creator's credit on this document. which he/she had no input on. that's not right. and, by extension, the inventory system, since //this item is in use in the inventory system. and the time engine, because worms regen over time. I am the content creator for both of those, and i refuse to allow him/her //any credit for either of those. those took time and effort and were difficult - i'm not freely handing credit to him/her because that license would require me to. Either //his/her license changes, or the offending content is removed, or the entire game engine goes. Right now i think it's better go with the game engine because it make all of //this shit work. - JSG. ////--Worms leave if 100% lizard dicks? ////Require mammals? //if (target.genitals.CountCocksOfType(CockType.LIZARD) == target.cocks.Count && target.hasStatusEffect(StatusEffects.Infested)) //{ // if (target.balls.count > 1) // target.removeStatusEffect(StatusEffects.Infested); // if (--remainingChanges <= 0) return ApplyChangesAndReturn(target, sb, changeCount - remainingChanges); //} //Increase height up to 5ft 7in. if (target.build.heightInInches < 67 && Utils.Rand(5) == 0) { target.build.IncreaseHeight((byte)(Utils.Rand(3) + 1)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Decrease height down to a maximum of 6ft 8in. if (target.build.heightInInches > 80 && Utils.Rand(5) == 0) { target.build.DecreaseHeight((byte)(Utils.Rand(3) + 1)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Physical changes: //Removes other antennae if (target.antennae.type != AntennaeType.COCKATRICE && !target.antennae.isDefault && Utils.Rand(3) == 0) { target.RestoreAntennae(); } //Gain antennae like feathers if (target.antennae.type == AntennaeType.NONE && target.face.type == FaceType.COCKATRICE && target.ears.type == EarType.COCKATRICE && Utils.Rand(3) == 0) { // Other antennae types are handled above! (Stadler76) AntennaeData oldData = target.antennae.AsReadOnlyData(); target.UpdateAntennae(AntennaeType.COCKATRICE); sb.Append(UpdateAntennaeText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Removes horns if (target.horns.type != HornType.NONE && Utils.Rand(5) == 0) { HornData oldData = target.horns.AsReadOnlyData(); target.RestoreHorns(); sb.Append(RestoredHornsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Face TF if (target.face.type != FaceType.COCKATRICE && target.arms.type == ArmType.COCKATRICE && target.lowerBody.type == LowerBodyType.COCKATRICE && Utils.Rand(3) == 0) { FaceData oldData = target.face.AsReadOnlyData(); target.UpdateFace(FaceType.COCKATRICE); sb.Append(UpdateFaceText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Hair TF if (target.hair.type != HairType.FEATHER && Utils.Rand(4) == 0) { HairData oldData = target.hair.AsReadOnlyData(); target.UpdateHair(HairType.FEATHER); sb.Append(UpdateHairText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Eye TF if (target.eyes.type != EyeType.COCKATRICE && target.face.type == FaceType.COCKATRICE && target.body.type == BodyType.COCKATRICE && target.ears.type == EarType.COCKATRICE && Utils.Rand(3) == 0) { EyeData oldData = target.eyes.AsReadOnlyData(); target.UpdateEyes(EyeType.COCKATRICE); sb.Append(UpdateEyesText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Lizard tongue TF if (target.tongue.type != TongueType.LIZARD && target.face.type == FaceType.COCKATRICE && Utils.Rand(3) == 0) { TongueData oldData = target.tongue.AsReadOnlyData(); target.UpdateTongue(TongueType.LIZARD); sb.Append(UpdateTongueText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Ears TF if (target.ears.type != EarType.COCKATRICE && target.face.type == FaceType.COCKATRICE && Utils.Rand(3) == 0) { EarData oldData = target.ears.AsReadOnlyData(); target.UpdateEars(EarType.COCKATRICE); sb.Append(UpdateEarsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Arm TF if (target.arms.type != ArmType.COCKATRICE && Utils.Rand(4) == 0) { ArmData oldData = target.arms.AsReadOnlyData(); target.UpdateArms(ArmType.COCKATRICE); sb.Append(UpdateArmsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Neck loss, if not cockatrice neck if (target.neck.type != NeckType.COCKATRICE && Utils.Rand(4) == 0) { NeckData oldData = target.neck.AsReadOnlyData(); target.RestoreNeck(); sb.Append(RestoredNeckText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Rear body restore if (target.back.type != BackType.NORMAL && Utils.Rand(5) == 0) { BackData oldData = target.back.AsReadOnlyData(); target.RestoreBack(); sb.Append(RestoredBackText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Body TF if (target.body.type != BodyType.COCKATRICE && target.face.type == FaceType.COCKATRICE && Utils.Rand(3) == 0) { Species.COCKATRICE.GetRandomCockatriceColors(out FurColor feathers, out Tones scales); target.UpdateBody(BodyType.COCKATRICE, feathers, scales); NeckData oldData = target.neck.AsReadOnlyData(); target.UpdateNeck(NeckType.COCKATRICE, feathers.primaryColor); sb.Append(UpdateNeckText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Neck TF, if not already TFed from Body TF above if (target.neck.type != NeckType.COCKATRICE && target.body.type == BodyType.COCKATRICE && target.face.type == FaceType.COCKATRICE && Utils.Rand(3) == 0) { NeckData oldData = target.neck.AsReadOnlyData(); target.UpdateNeck(NeckType.COCKATRICE, Utils.RandomChoice(Species.COCKATRICE.availablePrimaryFeatherColors)); sb.Append(UpdateNeckText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Leg TF if (target.lowerBody.type != LowerBodyType.COCKATRICE && Utils.Rand(4) == 0) { LowerBodyData oldData = target.lowerBody.AsReadOnlyData(); target.UpdateLowerBody(LowerBodyType.COCKATRICE); sb.Append(UpdateLowerBodyText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Tail TF if (target.tail.type != TailType.COCKATRICE && Utils.Rand(4) == 0) { TailData oldData = target.tail.AsReadOnlyData(); target.UpdateTail(TailType.COCKATRICE); sb.Append(UpdateTailText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Wings TF //feathered wings and not large and a target? that shouldn't happen. silently make them large if (target.wings.type == WingType.FEATHERED && !target.wings.isLarge && target is Player) { target.wings.GrowLarge(); } else if (target.wings.type != WingType.FEATHERED && target.arms.type == ArmType.COCKATRICE && Utils.Rand(4) == 0) { HairFurColors wingColor = !target.body.activeFur.isEmpty ? target.body.activeFur.fur.primaryColor : target.hair.hairColor; WingData oldData = target.wings.AsReadOnlyData(); target.UpdateWings(WingType.FEATHERED); sb.Append(UpdateWingsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //FAILSAFE CHANGE if (remainingChanges == changeCount) { if (target is CombatCreature failSafe) { failSafe.AddHP(50); } target.ChangeLust(3); } //this is the fallthrough that occurs when a tf item goes through all the changes, but does not proc enough of them to exit early. it will apply however many changes //occurred, then return the contents of the stringbuilder. return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); }
protected internal override string DoTransformation(Creature target, out bool isBadEnd) { isBadEnd = false; int changeCount = GenerateChangeCount(target, new int[] { 2, 2, 3, 4 }); int remainingChanges = changeCount; StringBuilder sb = new StringBuilder(); #warning fix me int ngPlus(int value) => value; int currentChanges() => changeCount - remainingChanges; //For all of these, any text regarding the transformation should be instead abstracted out as an abstract string function. append the result of this abstract function //to the string builder declared above (aka sb.Append(FunctionCall(variables));) string builder is just a fancy way of telling the compiler that you'll be creating a //long string, piece by piece, so don't do any crazy optimizations first. //the initial text for starting the transformation. feel free to add additional variables to this if needed. sb.Append(InitialTransformationText(target)); //Add any free changes here - these can occur even if the change count is 0. these include things such as change in stats (intelligence, etc) //change in height, hips, and/or butt, or other similar stats. //this will handle the edge case where the change count starts out as 0. if (remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } //Any transformation related changes go here. these typically cost 1 change. these can be anything from body parts to gender (which technically also changes body parts, //but w/e). You are required to make sure you return as soon as you've applied changeCount changes, but a single line of code can be applied at the end of a change to do //this for you. //paste this line after any tf is applied, and it will: automatically decrement the remaining changes count. if it becomes 0 or less, apply the total number of changes //underwent to the target's change count (if applicable) and then return the StringBuilder content. //if (--remainingChanges <= 0) return ApplyChangesAndReturn(target, sb, changeCount - remainingChanges); //clear screen //Statistical changes: //-Reduces speed down to 50. if (target.speed > ngPlus(50) && Utils.Rand(4) == 0) { target.ChangeSpeed(-1); } //-Raises toughness to 70 //(+3 to 40, +2 to 55, +1 to 70) if (target.toughness < ngPlus(70) && Utils.Rand(3) == 0) { //(+3) if (target.toughness < ngPlus(40)) { target.ChangeToughness(3); } //(+2) else if (target.toughness < ngPlus(55)) { target.ChangeToughness(2); } //(+1) else { target.ChangeToughness(1); } } //-Reduces sensitivity. if (target.relativeSensitivity > 20 && Utils.Rand(3) == 0) { target.ChangeSensitivity(-1); } //Raises libido greatly to 50, then somewhat to 75, then slowly to 100. if (target.relativeLibido < 100 && Utils.Rand(3) == 0) { //+3 lib if less than 50 if (target.relativeLibido < 50) { target.ChangeLibido(1); } //+2 lib if less than 75 if (target.relativeLibido < 75) { target.ChangeLibido(1); } //+1 if above 75. target.ChangeLibido(1); } //Sexual Changes: //-Lizard dick - first one if (target.cocks.Any(x => x.type != CockType.LIZARD) && target.cocks.Count > 0 && ScalingChance(2, currentChanges(), 4)) { //Find the first non-lizzy dick C**k firstNonLizard = target.cocks.First(x => x.type != CockType.LIZARD); //Actually xform it nau target.genitals.UpdateCock(firstNonLizard, CockType.LIZARD); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } target.DeltaCreatureStats(lib: 3, lus: 10); } //(CHANGE OTHER DICK) int lizardCocks = target.genitals.CountCocksOfType(CockType.LIZARD); //Requires 1 lizard c**k, multiple cocks if (target.hasCock && (lizardCocks != target.cocks.Count || target.cocks.Count == 1) && ScalingChance(2, currentChanges(), 4)) { if (target.cocks.Count > 1) { C**k nonLizard = target.cocks.First(x => x.type != CockType.LIZARD); target.genitals.UpdateCock(nonLizard, CockType.LIZARD); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } target.DeltaCreatureStats(lib: 3, lus: 10); } else { target.genitals.AddCock(CockType.LIZARD, target.cocks[0].length, target.cocks[0].girth); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } target.DeltaCreatureStats(lib: 3, lus: 10); } } //MOD NOTE: REMOVED. SEE RANT IN SALAMANDER TRANSFORMATIONS //--Worms leave if 100% lizard dicks? //Require mammals? //if (target.genitals.CountCocksOfType(CockType.LIZARD) == target.cocks.Count && target.hasStatusEffect(StatusEffects.Infested)) //{ // target.removeStatusEffect(StatusEffects.Infested); // if (--remainingChanges <= 0) // { // return ApplyChangesAndReturn(target, sb, changeCount - remainingChanges); // } //} //-Breasts vanish to 0 rating if male if (target.genitals.BiggestCupSize() > target.genitals.smallestPossibleMaleCupSize && target.gender == Gender.MALE && ScalingChance(2, currentChanges(), 3)) { //(HUEG) foreach (Breasts breast in target.breasts) { if (breast.cupSize > CupSize.E_BIG) { breast.ShrinkBreasts(((byte)breast.cupSize).div(2)); } else { breast.SetCupSize(target.genitals.smallestPossibleMaleCupSize); } } //(+2 speed) target.IncreaseSpeed(2); target.ChangeLibido(2); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //-Lactation stoppage. if (target.genitals.isLactating && ScalingChance(2, currentChanges(), 4)) { if (target.HasPerk <Feeder>()) { target.RemovePerk <Feeder>(); } target.genitals.SetLactationTo(LactationStatus.NOT_LACTATING); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //-Nipples reduction to 1 per tit. if (target.genitals.hasQuadNipples && ScalingChance(2, currentChanges(), 4)) { target.genitals.SetQuadNipples(false); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //-Remove extra breast rows if (target.breasts.Count > 1 && ScalingChance(2, currentChanges(), 3) && !hyperHappy) { target.RemoveExtraBreastRows(); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //-VAGs if (target.hasVagina && target.womb.canObtainOviposition && Species.LIZARD.Score(target) > 3 && ScalingChance(3, currentChanges(), 5)) { target.womb.GrantOviposition(); sb.Append(GrantOvipositionText(target)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Physical changes: //-Existing horns become draconic, max of 4, max length of 1' if (target.horns.type != HornType.DRACONIC && ScalingChance(3, currentChanges(), 5)) { HornData oldData = target.horns.AsReadOnlyData(); target.UpdateHorns(HornType.DRACONIC); sb.Append(UpdateHornsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Neck restore if (target.neck.type != NeckType.HUMANOID && ScalingChance(2, currentChanges(), 4)) { NeckData oldData = target.neck.AsReadOnlyData(); target.RestoreNeck(); sb.Append(RestoredNeckText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Rear body restore if (!target.back.isDefault && ScalingChance(3, currentChanges(), 5)) { BackData oldData = target.back.AsReadOnlyData(); target.RestoreBack(); sb.Append(RestoredBackText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //-Hair changes if (ScalingChance(2, currentChanges(), 4)) { if (target.eyes.type == EyeType.BASILISK) { if (target.corruption > 65 && target.face.IsReptilian() && target.body.type == BodyType.REPTILE && target.hair.type != HairType.BASILISK_SPINES) { HairData oldData = target.hair.AsReadOnlyData(); target.UpdateHair(HairType.BASILISK_SPINES); sb.Append(UpdateHairText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } else if (target.corruption < 15 && target.gender.HasFlag(Gender.FEMALE) && target.hair.type != HairType.BASILISK_PLUME) { target.hair.ResumeNaturalGrowth(); HairData oldData = target.hair.AsReadOnlyData(); target.UpdateHair(HairType.BASILISK_PLUME); sb.Append(UpdateHairText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } else { target.hair.StopNaturalGrowth(); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //Remove beard! #warning BEARDS NOT YET IMPLEMENTED //Mod note: Nords are so serious about beards. ... Mai'q thinks they wish they had GLORIOUS pubes like Khajiit. //if (target.hasBeard() && ScalingChance(2, currentChanges(), 3)) //{ // target.beard.length = 0; // target.beard.style = 0; //} //Big physical changes: //-Legs – Draconic, clawed feet if (target.lowerBody.type != LowerBodyType.LIZARD && ScalingChance(3, currentChanges(), 5)) { //Hooves - //TAURS - //feet types - //Else – LowerBodyData oldData = target.lowerBody.AsReadOnlyData(); target.UpdateLowerBody(LowerBodyType.LIZARD); sb.Append(UpdateLowerBodyText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } // <mod name="Predator arms" author="Stadler76"> //Gain predator arms //Claw transition //MOD OF MOD (LOL): predator arms are a collection of arm types now, not a single type. thus, we can combine the claw and type checks. //now, you get the arms (and thus, the claws) if they aren't a predator type and have lizard legs, or switch to lizard arms from any other predator type. if ((target.arms.IsPredatorArms() || target.lowerBody.type == LowerBodyType.LIZARD) && target.body.type == BodyType.REPTILE && ScalingChance(2, currentChanges(), 3)) { ArmData oldData = target.arms.AsReadOnlyData(); target.UpdateArms(ArmType.LIZARD); sb.Append(UpdateArmsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } // </mod> //-Tail – sinuous lizard tail if (target.tail.type != TailType.LIZARD && target.lowerBody.type == LowerBodyType.LIZARD && ScalingChance(3, currentChanges(), 5)) { //No tail //Yes tail TailData oldData = target.tail.AsReadOnlyData(); target.UpdateTail(TailType.LIZARD); sb.Append(UpdateTailText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Remove odd eyes if (ScalingChance(3, currentChanges(), 5) && target.eyes.type != EyeType.HUMAN && !target.eyes.isReptilian) { EyeData oldData = target.eyes.AsReadOnlyData(); target.RestoreEyes(); sb.Append(RestoredEyesText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //-Ears become smaller nub-like openings? if (target.ears.type != EarType.LIZARD && target.tail.type == TailType.LIZARD && target.lowerBody.type == LowerBodyType.LIZARD && ScalingChance(3, currentChanges(), 5)) { EarData oldData = target.ears.AsReadOnlyData(); target.UpdateEars(EarType.LIZARD); sb.Append(UpdateEarsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //-Scales – color changes to red, green, white, blue, or black. Rarely: purple or silver. if (target.body.type != BodyType.REPTILE && target.ears.type == EarType.LIZARD && target.tail.type == TailType.LIZARD && target.lowerBody.type == LowerBodyType.LIZARD && ScalingChance(3, currentChanges(), 5)) { Species.LIZARD.GetRandomSkinTone(out Tones primary, out Tones underbody); target.UpdateBody(BodyType.REPTILE, primary, underbody); //kGAMECLASS.rathazul.addMixologyXP(20); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //-Lizard-like face. if (target.face.type != FaceType.LIZARD && target.body.type == BodyType.REPTILE && target.ears.type == EarType.LIZARD && target.tail.type == TailType.LIZARD && target.lowerBody.type == LowerBodyType.LIZARD && ScalingChance(3, currentChanges(), 5)) { FaceData oldData = target.face.AsReadOnlyData(); target.UpdateFace(FaceType.LIZARD); sb.Append(UpdateFaceText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //-Lizard tongue if (target.tongue.type == TongueType.SNAKE && Utils.Rand(10) < 6) { // Higher (60%) chance to be 'fixed' if old variant TongueData oldData = target.tongue.AsReadOnlyData(); target.UpdateTongue(TongueType.LIZARD); sb.Append(UpdateTongueText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (target.tongue.type != TongueType.LIZARD && target.tongue.type != TongueType.SNAKE && target.face.IsReptilian() && ScalingChance(2, currentChanges(), 3)) { TongueData oldData = target.tongue.AsReadOnlyData(); target.UpdateTongue(TongueType.LIZARD); sb.Append(UpdateTongueText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //-Remove Gills if (ScalingChance(2, currentChanges(), 4) && !target.gills.isDefault) { GillData oldData = target.gills.AsReadOnlyData(); target.RestoreGills(); sb.Append(RestoredGillsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //<mod name="Reptile eyes" author="Stadler76"> //-Lizard eyes if (target.eyes.type != EyeType.LIZARD && target.face.type == FaceType.LIZARD && target.body.type == BodyType.REPTILE && target.ears.type == EarType.LIZARD && ScalingChance(2, currentChanges(), 4)) { EyeData oldData = target.eyes.AsReadOnlyData(); target.UpdateEyes(EyeType.LIZARD); sb.Append(UpdateEyesText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //</mod> //FAILSAFE CHANGE if (remainingChanges == changeCount) { (target as CombatCreature)?.AddHP(50); target.ChangeLust(3); } //this is the fallthrough that occurs when a tf item goes through all the changes, but does not proc enough of them to exit early. it will apply however many changes //occurred, then return the contents of the stringbuilder. return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); }
private static string DemonTransformStr(HornData previousHornData, PlayerBase player) { throw new InDevelopmentExceptionThatBreaksOnRelease(); }
protected override string MadeHornsBigger(Creature target, HornData oldHorns) { return(GlobalStrings.NewParagraph() + "Your small horns get a bit bigger, stopping as medium sized nubs."); }
private static string BullRestoreStr(HornData previousHornData, PlayerBase player) { throw new InDevelopmentExceptionThatBreaksOnRelease(); }
protected virtual string UpdateHornsText(Creature target, HornData oldData) { return(target.horns.TransformFromText(oldData)); }
protected internal override string DoTransformation(Creature target, out bool isBadEnd) { isBadEnd = false; int changeCount = GenerateChangeCount(target, new int[] { 2, 2 }); int remainingChanges = changeCount; StringBuilder sb = new StringBuilder(); sb.Append(InitialTransformText(target)); target.DeltaCreatureStats(lus: 3, corr: 1); uint hpDelta; if (target.hasCock) { if (target.cocks[0].length < 12) { CockData oldData = target.cocks[0].AsReadOnlyData(); double temp = target.cocks[0].IncreaseLength(Utils.Rand(2) + 2); sb.Append(OneCockGrewLarger(target, oldData, temp)); } hpDelta = 30; } else { hpDelta = 20; } if (target is CombatCreature healthCheck) { healthCheck.AddHP((uint)(hpDelta + healthCheck.toughness / 3)); sb.Append(GainVitalityText(target)); } if (remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } //Red or orange skin! if (Utils.Rand(30) == 0 && !Array.Exists(Species.IMP.availableTones, x => x == target.body.primarySkin.tone)) { Tones oldSkinTone = target.body.primarySkin.tone; if (target.body.ChangeMainSkin(Utils.RandomChoice(Species.IMP.availableTones))) { sb.Append(ChangeSkinColorText(target, oldSkinTone)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //Shrinkage! if (Utils.Rand(2) == 0 && target.build.heightInInches > 42) { byte heightDelta = target.build.DecreaseHeight((byte)(1 + Utils.Rand(3))); if (heightDelta > 0) { sb.Append(GetShorterText(target, heightDelta)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //Imp wings - I just kinda robbed this from demon changeCount ~Foxwells if (Utils.Rand(3) == 0 && ((target.wings.type != WingType.IMP && target.IsCorruptEnough(25)) || (target.wings.type == WingType.IMP && target.IsCorruptEnough(50)))) { bool changedWings = false; //grow smalls to large if (target.wings.type == WingType.IMP) { if (target.wings.GrowLarge()) { sb.Append(EnlargenedImpWingsText(target)); changedWings = true; } } else { WingData oldData = target.wings.AsReadOnlyData(); if (target.UpdateWings(WingType.IMP)) { sb.Append(GrowOrChangeWingsText(target, oldData)); changedWings = true; } } if (changedWings) { if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //Imp tail, because that's a unique thing from what I see? if (Utils.Rand(3) == 0 && target.tail.type != TailType.IMP) { TailData oldData = target.tail.AsReadOnlyData(); if (target.UpdateTail(TailType.IMP)) { sb.Append(GrowOrChangeTailText(target, oldData)); target.IncreaseCorruption(2); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //Feets, needs red/orange skin and tail if (Species.IMP.availableTones.Contains(target.body.primarySkin.tone) && target.tail.type == TailType.IMP && target.lowerBody.type != LowerBodyType.IMP && Utils.Rand(3) == 0) { LowerBodyData oldData = target.lowerBody.AsReadOnlyData(); if (target.UpdateLowerBody(LowerBodyType.IMP)) { sb.Append(ChangeLowerBodyText(target, oldData)); target.IncreaseCorruption(2); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //Imp ears, needs red/orange skin and horns if (target.horns.type == HornType.IMP && Array.Exists(Species.IMP.availableTones, x => target.body.primarySkin.tone == x) && target.ears.type != EarType.IMP && Utils.Rand(3) == 0) { EarData oldData = target.ears.AsReadOnlyData(); if (target.UpdateEars(EarType.IMP)) { sb.Append(ChangeEarsText(target, oldData)); target.IncreaseCorruption(2); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //Horns, because why not? if (target.horns.type != HornType.IMP && Utils.RandBool()) { HornData oldData = target.horns.AsReadOnlyData(); if (target.UpdateHorns(HornType.IMP)) { sb.Append(ChangeOrGrowHornsText(target, oldData)); target.IncreaseCorruption(2); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //Imp arms, needs orange/red skin. Also your hands turn human. if (Species.IMP.availableTones.Contains(target.body.primarySkin.tone) && target.arms.type != ArmType.IMP && Utils.Rand(3) == 0) { ArmData oldData = target.arms.AsReadOnlyData(); if (target.UpdateArms(ArmType.IMP)) { sb.Append(ChangeArmText(target, oldData)); target.IncreaseCorruption(2); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //Changes hair to red/dark red, shortens it, sets it normal, and makes it curly. if (!Species.IMP.availableHairColors.Contains(target.hair.hairColor) && Utils.Rand(3) == 0) { HairData oldHairData = target.hair.AsReadOnlyData(); HairFurColors hairColor = Utils.RandomChoice(Species.IMP.availableHairColors); double hairLength = 1; if (target.hair.type != HairType.NORMAL) { //also restarts hair growth if disabled. target.UpdateHair(HairType.NORMAL, true, hairColor, newHairLength: hairLength, newStyle: HairStyle.CURLY); } else { //also restarts hair growth if disabled. target.hair.SetAll(hairLength, true, hairColor, style: HairStyle.CURLY); } sb.Append(HairChangedText(target, oldHairData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Remove spare titties if (target.breasts.Count > 1 && Utils.Rand(3) == 0 && !hyperHappy) { BreastData toRemove = target.breasts[target.breasts.Count - 1].AsReadOnlyData(); if (target.genitals.RemoveBreastRows() > 0) { sb.Append(RemovedAnExtraRowOfBreasts(target, toRemove)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //Shrink titties if (target.genitals.BiggestCupSize() > CupSize.FLAT && Utils.Rand(3) == 0 && !hyperHappy) { byte rowsAlreadyModified = 0; //temp3 stores how many rows are changed foreach (Breasts breast in target.breasts) { //If this row is over threshhold if (breast.cupSize > CupSize.FLAT) { CupSize oldSize = breast.cupSize; byte delta; //Big change if (breast.cupSize > CupSize.EE_BIG) { delta = breast.ShrinkBreasts((byte)(2 + Utils.Rand(3))); } else { delta = breast.ShrinkBreasts(1); } if (delta != 0) { sb.Append(CurrentBreastRowChanged(target, breast.rowIndex, delta, rowsAlreadyModified)); rowsAlreadyModified++; } } } if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Free extra nipple removal service if (target.genitals.hasQuadNipples && Utils.Rand(3) == 0) { target.genitals.SetQuadNipples(false); sb.Append(RemovedQuadNippleText(target)); target.DecreaseSensitivity(3); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Neck restore if (target.neck.type != NeckType.defaultValue && Utils.Rand(4) == 0) { NeckData oldData = target.neck.AsReadOnlyData(); if (target.RestoreNeck()) { sb.Append(RestoredNeckText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //Rear body restore if (target.back.type != BackType.defaultValue && Utils.Rand(5) == 0) { BackData oldData = target.back.AsReadOnlyData(); if (target.RestoreBack()) { sb.Append(RestoredBackText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //Ovi perk loss if (target is Player && Utils.Rand(5) == 0) { if (((PlayerWomb)target.womb).ClearOviposition()) { sb.Append(RemovedOvipositionText(target)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //You lotta imp? Time to turn male! //Unless you're one of the hyper happy assholes I guess //For real tho doesn't seem like female imps exist? Guess they're goblins if (target.ImpScore() >= 4 && !hyperHappy) { bool changedSomething = false; GenitalsData oldGenitals = target.genitals.AsReadOnlyData(); changedSomething |= target.genitals.RemoveExtraBreastRows() > 0; changedSomething |= target.breasts[0].MakeMale(true); changedSomething |= target.RemoveAllVaginas() > 0; if (!target.hasCock) { changedSomething |= target.AddCock(CockType.HUMAN, 12, 2); } if (target.balls.count == 0) { changedSomething |= target.genitals.GrowBalls(2); } if (changedSomething) { sb.Append(ImpifiedText(target, oldGenitals)); remainingChanges--; target.IncreaseCorruption(20); } } return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); }