protected virtual string RestoredGillsText(Creature target, GillData oldData) { return(target.gills.RestoredText(oldData)); }
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 }); 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); //Text go! //Speed raises up to 75 if (target.relativeSpeed < 75 && Utils.Rand(3) == 0) { //low speed if (target.relativeSpeed <= 30) { target.ChangeSpeed(2); } //medium speed else if (target.relativeSpeed <= 60) { target.ChangeSpeed(1); } //high speed else { target.ChangeSpeed(.5); } } //Strength raises to 40 if (target.relativeStrength < 40 && Utils.Rand(3) == 0) { target.ChangeStrength(1); } //Strength ALWAYS drops if over 60 //Does not add to change total else if (target.relativeStrength > 60 && Utils.Rand(2) == 0) { target.ChangeStrength(-2); } //Toughness drops if over 50 //Does not add to change total if (target.relativeToughness > 50 && Utils.Rand(2) == 0) { target.ChangeToughness(-2); } //Intelliloss if (Utils.Rand(4) == 0) { target.ChangeIntelligence(-1); } //Libido gain if (target.relativeLibido < 80 && Utils.Rand(4) == 0) { target.DeltaCreatureStats(lib: 1, sens: .25); } //Sexual changes would go here if I wasn't a tard. //Heat if (Utils.Rand(4) == 0) { bool intensified = target.HasTimedEffect <Heat>(); if (target.GoIntoHeat()) { if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //Shrink the boobalies down to A for men or C for girls. if (Utils.Rand(4) == 0 && !hyperHappy) { CupSize targetSize; //female or herm. targeting C cup, but will respect smallest possible cup if it's somehow above a c cup. if (target.gender.HasFlag(Gender.FEMALE)) { targetSize = EnumHelper.Max(CupSize.C, target.genitals.smallestPossibleFemaleCupSize); } //male or genderless. targeting A cup, but will respect smallest possible cup if somehow above an a cup. else { targetSize = EnumHelper.Max(CupSize.A, target.genitals.smallestPossibleMaleCupSize); } //IT IS! int rowsShrunk = 0; foreach (Breasts row in target.breasts) { //If this row is over threshhold if (row.cupSize > targetSize) { //Big change if (row.cupSize > CupSize.EE_BIG) { row.ShrinkBreasts((byte)(2 + Utils.Rand(3))); } //Small change else { row.ShrinkBreasts(1); } rowsShrunk++; } } //Count that t**s were shrunk if (rowsShrunk > 0) { remainingChanges--; if (remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //Cat dangly-doo. if (target.cocks.Count > 0 && target.cocks.Any(x => x.type != CockType.CAT) && (target.ears.type == EarType.CAT || Utils.Rand(3) > 0) && (target.tail.type == TailType.CAT || Utils.Rand(3) > 0) && Utils.Rand(4) == 0) { C**k nonCat = target.cocks.First(x => x.type != CockType.CAT); target.genitals.UpdateCock(nonCat, CockType.CAT); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Cat penorz shrink if (target.genitals.HasAnyCocksOfType(CockType.CAT) && Utils.Rand(3) == 0 && !hyperHappy) { //loop through and find a cat wang. foreach (C**k catCock in target.cocks.Where(x => x.type == CockType.CAT)) { //lose 33% size until under 10, then lose 2" at a time if (catCock.length > 16) { catCock.SetLength(catCock.length * .66); } else if (catCock.length > 6) { catCock.DecreaseLength(2); } if (catCock.length / 5 < catCock.girth && catCock.girth > 1.25) { catCock.SetGirth(catCock.length / 6); } } //(big sensitivity boost) target.ChangeSensitivity(5); //Make note of other dicks changing if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //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)); } } //Body type changes. Teh rarest of the rare. // Catgirl-face -> cat-morph-face if (target.face.type == FaceType.CAT && !target.face.isFullMorph && target.tongue.type == TongueType.CAT && target.ears.type == EarType.CAT && target.tail.type == TailType.CAT && target.lowerBody.type == LowerBodyType.CAT && target.arms.type == ArmType.CAT && (target.body.IsFurBodyType() /*|| (target.body.type == BodyType.REPTILE && Species.SPHINX.Score(target) >= 4)*/) && Utils.Rand(5) == 0) { target.face.StrengthenFacialMorph(); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //DA EARZ if (target.ears.type != EarType.CAT && Utils.Rand(5) == 0) { EarData oldData = target.ears.AsReadOnlyData(); target.UpdateEars(EarType.CAT); sb.Append(UpdateEarsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //DA TAIL (IF ALREADY HAZ URZ) if (target.tail.type != TailType.CAT && target.ears.type == EarType.CAT && Utils.Rand(5) == 0) { TailData oldData = target.tail.AsReadOnlyData(); target.UpdateTail(TailType.CAT); sb.Append(UpdateTailText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Da paws (if already haz ears & tail) if (target.tail.type == TailType.CAT && target.ears.type == EarType.CAT && Utils.Rand(5) == 0 && target.lowerBody.type != LowerBodyType.CAT) { //hoof to cat: if (target.lowerBody.type == LowerBodyType.HOOVED) { } //Goo to cat else if (target.lowerBody.type == LowerBodyType.GOO) { } //non hoof to cat: LowerBodyData oldData = target.lowerBody.AsReadOnlyData(); target.UpdateLowerBody(LowerBodyType.CAT); sb.Append(UpdateLowerBodyText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //TURN INTO A FURRAH! OH SHIT if (target.tail.type == TailType.CAT && target.ears.type == EarType.CAT && Utils.Rand(5) == 0 && target.lowerBody.type == LowerBodyType.CAT && !target.body.IsFurBodyType()) { BodyData oldData = target.body.AsReadOnlyData(); target.UpdateBody(BodyType.UNDERBODY_FUR); sb.Append(UpdateBodyText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } // Fix old cat faces without cat-eyes. if (target.face.type == FaceType.CAT && target.eyes.type != EyeType.CAT && Utils.Rand(3) == 0) { EyeData oldData = target.eyes.AsReadOnlyData(); target.UpdateEyes(EyeType.CAT); sb.Append(UpdateEyesText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //CAT-FACE! FULL ON FURRY! RAGE AWAY NEKOZ if (target.tail.type == TailType.CAT && target.ears.type == EarType.CAT && target.lowerBody.type == LowerBodyType.CAT && target.face.type != FaceType.CAT && Utils.Rand(5) == 0) { //Gain cat face, replace old face //MOD NOTE: but not a full-morph cat face. just level 1. FaceData oldData = target.face.AsReadOnlyData(); target.UpdateFace(FaceType.CAT); sb.Append(UpdateFaceText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } // Cat-tongue if (target.face.type == FaceType.CAT && target.tongue.type != TongueType.CAT && Utils.Rand(5) == 0) { TongueData oldData = target.tongue.AsReadOnlyData(); target.UpdateTongue(TongueType.CAT); sb.Append(UpdateTongueText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Arms if (target.arms.type != ArmType.CAT && target.body.IsFurBodyType() && target.tail.type == TailType.CAT && target.lowerBody.type == LowerBodyType.CAT && Utils.Rand(4) == 0) { ArmData oldData = target.arms.AsReadOnlyData(); target.UpdateArms(ArmType.CAT); sb.Append(UpdateArmsText(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)); } } //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)); }
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)); }
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, 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); //clear screen //Statistical changes: //-Reduces speed down to 70. if (target.relativeSpeed > 70 && Utils.Rand(4) == 0) { target.ChangeSpeed(-1); } //-Reduces intelligence down to 60. if (target.relativeIntelligence > 60 && Utils.Rand(4) == 0) { target.ChangeIntelligence(-1); } //-Raises toughness up to 90. //(+3 to 50, +2 to 70, +1 to 90) if (target.relativeToughness < 90 && Utils.Rand(3) == 0) { //(+3) if (target.relativeToughness < 50) { target.ChangeToughness(3); } //(+2) else if (target.relativeToughness < 70) { target.ChangeToughness(2); } //(+1) else { target.ChangeToughness(1); } } //-Raises strength to 80. if (target.relativeStrength < 80 && Utils.Rand(3) == 0) { target.ChangeStrength(1); } //-Raises libido up to 90. if (target.relativeLibido < 90 && Utils.Rand(3) == 0) { target.ChangeLibido(2); } //Sexual Changes: //MOD: lizard dicks get a common rng roll now. The only difference is the text. if (target.hasCock && !target.genitals.OnlyHasCocksOfType(CockType.LIZARD) && Utils.Rand(4) == 0) { C**k nonLizard = target.cocks.First(x => x.type != CockType.LIZARD); //Actually xform it nau target.genitals.UpdateCock(nonLizard, CockType.LIZARD); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } target.DeltaCreatureStats(lib: 3, lus: 10); } //-Breasts vanish to 0 rating if male if (target.genitals.BiggestCupSize() >= target.genitals.smallestPossibleMaleCupSize && target.gender == Gender.MALE && Utils.Rand(3) == 0) { //(HUEG) //Loop through behind the scenes and adjust all t**s. foreach (Breasts breastRow in target.breasts) { if (breastRow.cupSize > CupSize.E_BIG) { breastRow.ShrinkBreasts(((byte)breastRow.cupSize).div(2)); } else { breastRow.SetCupSize(target.genitals.smallestPossibleMaleCupSize); } } //(+2 speed) //target.IncreaseSpeed(2); target.ChangeLibido(2); 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)); } } Breasts smallestTits = target.genitals.SmallestBreast(); //Increase target's breast size, if they are big DD or smaller if (smallestTits.cupSize <= CupSize.DD_BIG && target.gender == Gender.FEMALE && Utils.Rand(4) == 0) { smallestTits.GrowBreasts(); 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(); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //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)); } } //Physical changes: //Tail - 1st gain reptilian tail, 2nd unlocks enhanced with fire tail whip attack if (target.tail.type != TailType.LIZARD && target.tail.type != TailType.SALAMANDER && Utils.Rand(3) == 0) { TailData oldData = target.tail.AsReadOnlyData(); target.UpdateTail(TailType.LIZARD); sb.Append(UpdateTailText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (target.tail.type == TailType.LIZARD && Utils.Rand(3) == 0) { TailData oldData = target.tail.AsReadOnlyData(); target.UpdateTail(TailType.SALAMANDER); sb.Append(UpdateTailText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Legs if (target.lowerBody.type != LowerBodyType.SALAMANDER && target.tail.type == TailType.SALAMANDER && Utils.Rand(3) == 0) { LowerBodyData oldData = target.lowerBody.AsReadOnlyData(); target.UpdateLowerBody(LowerBodyType.SALAMANDER); sb.Append(UpdateLowerBodyText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Arms if (target.arms.type != ArmType.SALAMANDER && target.lowerBody.type == LowerBodyType.SALAMANDER && Utils.Rand(3) == 0) { ArmData oldData = target.arms.AsReadOnlyData(); target.UpdateArms(ArmType.SALAMANDER); sb.Append(UpdateArmsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Remove odd eyes if (Utils.Rand(4) == 0 && !target.eyes.isDefault) { EyeData oldData = target.eyes.AsReadOnlyData(); target.RestoreEyes(); sb.Append(RestoredEyesText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Human face if (target.face.type != FaceType.HUMAN && Utils.Rand(4) == 0) { FaceData oldData = target.face.AsReadOnlyData(); target.UpdateFace(FaceType.HUMAN); sb.Append(UpdateFaceText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Human ears if (target.face.type == FaceType.HUMAN && target.ears.type != EarType.HUMAN && Utils.Rand(4) == 0) { EarData oldData = target.ears.AsReadOnlyData(); target.UpdateEars(EarType.HUMAN); sb.Append(UpdateEarsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //-Skin color change if (!Species.SALAMANDER.availableTones.Contains(target.body.primarySkin.tone) && Utils.Rand(4) == 0) { target.body.ChangeMainSkin(Utils.RandomChoice(Species.SALAMANDER.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 && Utils.Rand(3) == 0) { BodyData oldData = target.body.AsReadOnlyData(); target.RestoreBody(); sb.Append(RestoredBodyText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Removing 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)); } } //FAILSAFE CHANGE if (remainingChanges == changeCount) { (target as CombatCreature)?.AddHP(100); target.ChangeLust(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 internal override string DoTransformation(Creature target, out bool isBadEnd) { isBadEnd = false; int changeLimit = GenerateChangeCount(target, new int[] { 2, 2 }); int remainingChanges = changeLimit; //crit is our modifier for basically all stats. 1 is default, though any non-standard will proc the non-default //standard also has a 15% chance of proccing it too. int crit = 1; if (modifiers > CanineModifiers.STANDARD || Utils.Rand(20) < 3) { crit = Utils.Rand(20) / 10 + 2; } bool hasCrit() => crit > 1; StringBuilder sb = new StringBuilder(); bool DoKnotChanges(double delta) { if (target.hasCock) { bool changed = false; int dogCockCount = target.genitals.CountCocksOfType(CockType.DOG); if (dogCockCount > 0) { C**k smallestKnot = target.cocks.MinItem(x => x.type == CockType.DOG ? (double?)x.knotMultiplier : null); if (smallestKnot.knotMultiplier > 2) { delta /= 10; } else if (smallestKnot.knotMultiplier > 1.75) { delta /= 5; } else if (smallestKnot.knotMultiplier > 1.5) { delta /= 2; } double knotMultiplierDelta = smallestKnot.IncreaseKnotMultiplier(delta); if (knotMultiplierDelta != 0) { sb.Append(EnlargedSmallestKnotText(target, target.cocks.IndexOf(smallestKnot), knotMultiplierDelta, dogCockCount > 1)); changed = true; } } target.DeltaCreatureStats(sens: 0.5, lus: 5 * crit); return(changed); } return(false); } sb.Append(InitialTransformationText(modifiers, hasCrit())); //bad end related checks if (hasCrit() && target.body.hasActiveFurData && target.face.type == FaceType.DOG && target.ears.type == EarType.DOG && target.lowerBody.type == LowerBodyType.DOG && target.tail.type == TailType.DOG && target is IExtendedCreature extended) { //can get bad end. if (extended.extendedData.hasDoggoWarning && !extended.extendedData.resistsTFBadEnds) { //bad end. if (Utils.RandBool()) { sb.Append(BadEndText(target)); isBadEnd = true; return(ApplyChangesAndReturn(target, sb, 0)); } //get lucky, but warn that they got lucky else { sb.Append(DoggoWarningText(target, true)); } } //not warned else if (!extended.extendedData.hasDoggoWarning) { //warn extended.extendedData.hasDoggoWarning = true; sb.Append(DoggoWarningText(target, false)); } } //stat changes if (modifiers.HasFlag(CanineModifiers.BLACK)) { target.IncreaseCreatureStats(lus: (byte)(5 + Utils.Rand(5)), lib: (byte)(2 + Utils.Rand(4)), corr: (byte)(2 + Utils.Rand(4))); } //stat changes (cont.) double strengthIncrease = 0; double speedIncrease = 0; double intelligenceDecrease = 0; if (target.relativeStrength < 50 && Utils.Rand(3) == 0) { strengthIncrease = target.IncreaseStrength(crit); } if (target.relativeSpeed < 30 && Utils.Rand(3) == 0) { speedIncrease = target.IncreaseSpeed(crit); } if (target.relativeIntelligence > 30 && Utils.Rand(3) == 0) { intelligenceDecrease = target.DecreaseIntelligence(crit); } sb.Append(StatChangeText(target, strengthIncrease, speedIncrease, intelligenceDecrease)); //modifier effects (no cost) //double pepper if (modifiers.HasFlag(CanineModifiers.DOUBLE)) { int dogCocks = target.genitals.CountCocksOfType(CockType.DOG); //already has 2+ dog cocks. if (dogCocks >= 2) { //just treat it like a large. so we'll just bitwise or the //large flag in. modifiers |= CanineModifiers.LARGE; } //has no dog cocks. else if (dogCocks == 0) { //has no cocks. - grow 2 if (target.cocks.Count == 0) { target.AddCock(CockType.DOG, 7 + Utils.Rand(7), 1.5 + Utils.Rand(10) / 10, 1.7); target.AddCock(CockType.DOG, 7 + Utils.Rand(7), 1.5 + Utils.Rand(10) / 10, 1.7); sb.Append(GrewTwoDogCocksHadNone(target)); } //has one c**k. - grow one, change one else if (target.cocks.Count == 1) { CockData oldCockData = target.cocks[0].AsReadOnlyData(); target.genitals.UpdateCockWithKnot(0, CockType.DOG, 1.5); if (target.cocks[0].length < 10) { target.cocks[0].SetLength(10); } target.AddCock(CockType.DOG, 7 + Utils.Rand(7), 1.5 + Utils.Rand(10) / 10.0, 1.7); sb.Append(ConvertedFirstDogCockGrewSecond(target, oldCockData)); } //has 2+ cocks. -change 2 else { CockData firstOldData = target.cocks[0].AsReadOnlyData(); CockData secondOldData = target.cocks[1].AsReadOnlyData(); target.genitals.UpdateCockWithKnot(0, CockType.DOG, 1.5); if (target.cocks[0].length < 10) { target.cocks[0].SetLength(10); } target.genitals.UpdateCockWithKnot(1, CockType.DOG, 1.5); if (target.cocks[1].length < 10) { target.cocks[1].SetLength(10); } sb.Append(ConvertedTwoCocksToDog(target, firstOldData, secondOldData)); } } //one dog c**k. else { if (target.cocks.Count == 1) { target.AddCock(CockType.DOG, 7 + Utils.Rand(7), 1.5 + Utils.Rand(10) / 10.0, 1.7); sb.Append(GrewSecondDogCockHadOne(target)); } else { if (target.cocks[0].type == CockType.DOG) { CockData oldData = target.cocks[1].AsReadOnlyData(); target.genitals.UpdateCockWithKnot(1, CockType.DOG, 1.5); if (target.cocks[1].length < 10) { target.cocks[1].SetLength(10); } sb.Append(ConvertedOneCockToDogHadOne(target, 1, oldData)); } else { CockData oldData = target.cocks[0].AsReadOnlyData(); target.genitals.UpdateCockWithKnot(0, CockType.DOG, 1.5); if (target.cocks[0].length < 10) { target.cocks[0].SetLength(10); } sb.Append(ConvertedOneCockToDogHadOne(target, 0, oldData)); } } } target.IncreaseCreatureStats(lib: 2, lus: 50); } //there are two ways to proc this - either via a knotty modifier (written here), or via random chance and/or with a large pepper (written later) //however, a knotty pepper modifier has no tf cost, the other check does. also, this will modify a c**k if none have a dog knot, the other will not. if (modifiers.HasFlag(CanineModifiers.KNOTTY)) { double delta = ((Utils.Rand(2) + 5) / 20) * crit; if (!DoKnotChanges(delta)) { if (target.hasCock) { CockData oldCockData = target.cocks[0].AsReadOnlyData(); double knotSize = 1.75; if (target.cocks[0].hasKnot) { knotSize = Math.Max(2.1, target.cocks[0].knotMultiplier); } target.genitals.UpdateCockWithKnot(0, CockType.DOG, knotSize); if (target.cocks[0].length < 10) { target.cocks[0].SetLength(10); } sb.Append(ConvertedOneCockToDog(target, 0, oldCockData)); } else { sb.Append(WastedKnottyText(target)); } } } //bulby if (modifiers.HasFlag(CanineModifiers.BULBY)) { if (!target.hasBalls) { target.genitals.GrowBalls(2, 1); target.DeltaCreatureStats(lib: 2, lus: -10); sb.Append(GrewBallsText(target)); } else if (target.balls.uniBall) { BallsData oldData = target.balls.AsReadOnlyData(); target.genitals.ConvertToNormalBalls(); target.DeltaCreatureStats(lib: 1, lus: 1); sb.Append(EnlargedBallsText(target, oldData)); } else { BallsData oldData = target.balls.AsReadOnlyData(); byte enlargeAmount = target.genitals.balls.EnlargeBalls(1); target.IncreaseCreatureStats(lib: 1, lus: 3); sb.Append(EnlargedBallsText(target, oldData)); } } if (remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeLimit - remainingChanges)); } //tfs (cost 1). //restore neck if (target.neck.type != NeckType.defaultValue && Utils.Rand(4) == 0) { NeckData oldNeck = target.neck.AsReadOnlyData(); target.RestoreNeck(); sb.Append(RestoredNeckText(target, oldNeck)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeLimit - remainingChanges)); } } //remove oviposition if (target.womb.canRemoveOviposition && Utils.Rand(5) == 0) { if (target.womb.ClearOviposition()) { sb.Append(RemovedOvipositionText(target)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeLimit - remainingChanges)); } } } //remove feather-hair if (RemoveFeatheryHair(target)) { sb.Append(RemovedFeatheryHairText(target)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeLimit - remainingChanges)); } } //knot multiplier (but not knotty) if (!modifiers.HasFlag(CanineModifiers.KNOTTY) && target.genitals.CountCocksOfType(CockType.DOG) > 0 && (modifiers.HasFlag(CanineModifiers.LARGE) || Utils.Rand(7) < 5)) { double delta = ((Utils.Rand(2) + 1) / 20.0) * crit; if (DoKnotChanges(delta)) { if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeLimit - remainingChanges)); } } } //transform a c**k. if (target.genitals.CountCocksOfType(CockType.DOG) < target.cocks.Count && (modifiers.HasFlag(CanineModifiers.LARGE) || Utils.Rand(8) < 5)) { C**k nonDoggo = target.cocks.FirstOrDefault(x => x.type != CockType.DOG && x.type != CockType.DEMON); //find any c**k that isn't a dog, but also isn't a demon c**k. if (nonDoggo != null) { CockData oldData = nonDoggo.AsReadOnlyData(); int index = target.cocks.IndexOf(nonDoggo); target.genitals.UpdateCock(index, CockType.DOG); sb.Append(ConvertedOneCockToDog(target, index, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeLimit - remainingChanges)); } } else { C**k demonSpecialCase = target.cocks.FirstOrDefault(x => x.type == CockType.DEMON); int index = demonSpecialCase.cockIndex; if (demonSpecialCase != null) { double delta = demonSpecialCase.IncreaseThickness(2); if (delta != 0) { sb.Append(CouldntConvertDemonCockThickenedInstead(target, index, delta)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeLimit - remainingChanges)); } } } } } //update cum. now, if it reaches the cap, it simply uses the new flat amount adder (up to a certain point). it does not use the messy o****m perk //anymore because i've tried to remove calls to random perks because it's not very future-proof - what happens when a new perk is added that has a //similar effect? do we add that check literally everywhere too? (of course, if a perk is unique enough that nothing else will act in the same way, //that's fine. i dunno, it's difficult to try and clean everything up without being able to predict the future, which is admittedly impossible) if (target.hasCock && (target.genitals.cumMultiplier < 1.5 || target.genitals.additionalCum < 500) && Utils.RandBool()) { double delta; bool wasMultiplier; if (target.genitals.cumMultiplier < 1.5) { delta = target.genitals.IncreaseCumMultiplier(0.05 * crit); wasMultiplier = true; } else { delta = target.genitals.AddFlatCumAmount(50); wasMultiplier = false; } sb.Append(AddedCumText(target, delta, wasMultiplier)); } if (target.hasCock && modifiers.HasFlag(CanineModifiers.LARGE)) { C**k smallest = target.genitals.ShortestCock(); CockData oldData = smallest.AsReadOnlyData(); smallest.IncreaseLength(Utils.Rand(4) + 3); if (smallest.girth < 1) { double delta = 1 - smallest.girth; smallest.IncreaseThickness(delta); } sb.Append(GrewSmallestCockText(target, smallest.cockIndex, oldData)); } //do female changes. //if we have a vag and > flat breasts. if (target.hasVagina && target.genitals.BiggestCupSize() > CupSize.FLAT) { byte breastCount = (byte)target.breasts.Count; if (breastCount < 3) { 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, changeLimit - 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)); } } } //Go into heat if (EnterHeat(target, out bool increased)) { sb.Append(EnterOrIncreaseHeatText(target, increased)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeLimit - remainingChanges)); } } //doggo fantasies if (target.DogScore() > 3 && Utils.Rand(4) == 0) { sb.Append(DoggoFantasyText(target)); target.IncreaseLust(5 + (target.libidoTrue / 20)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeLimit - remainingChanges)); } } //doggo tfs. if (!target.eyes.isDefault && Utils.Rand(5) == 0) { EyeData oldData = target.eyes.AsReadOnlyData(); target.RestoreEyes(); sb.Append(RestoredEyesText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeLimit - remainingChanges)); } } if (modifiers.HasFlag(CanineModifiers.BLACK) && !target.body.mainEpidermis.fur.IsIdenticalTo(HairFurColors.BLACK)) { //for now, we're ignoring underbody, apparently. if (target.body.type != BodyType.SIMPLE_FUR) //if (target.body.mainEpidermis.currentType != EpidermisType.FUR) { BodyData oldBodyData = target.body.AsReadOnlyData(); target.UpdateBody(BodyType.SIMPLE_FUR, new FurColor(HairFurColors.BLACK), FurTexture.THICK); sb.Append(ChangedBodyTypeText(target, oldBodyData)); } else { ReadOnlyFurColor oldFur = target.body.mainEpidermis.fur.AsReadOnly(); target.body.ChangeMainFur(new FurColor(HairFurColors.MIDNIGHT_BLACK), FurTexture.THICK); sb.Append(ChangedFurText(target, oldFur)); } if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeLimit - remainingChanges)); } } //again, we're ignoring underbody for now, idk. else if (target.lowerBody.type == LowerBodyType.DOG && target.tail.type == TailType.DOG && //target.body.mainEpidermis.currentType != EpidermisType.FUR target.body.type != BodyType.SIMPLE_FUR && Utils.Rand(4) == 0) { BodyData oldBodyData = target.body.AsReadOnlyData(); FurColor oldFur = target.body.mainEpidermis.fur; target.UpdateBody(BodyType.SIMPLE_FUR, Utils.RandomChoice(Species.DOG.availableColors)); sb.Append(ChangedBodyTypeText(target, oldBodyData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeLimit - remainingChanges)); } } if (target.lowerBody.type != LowerBodyType.DOG && target.tail.type == TailType.DOG && target.ears.type == EarType.DOG && Utils.Rand(3) == 0) { LowerBodyData oldData = target.lowerBody.AsReadOnlyData(); target.UpdateLowerBody(LowerBodyType.DOG); sb.Append(ChangedLowerBodyText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeLimit - remainingChanges)); } } if (target.ears.type != EarType.DOG && target.tail.type == TailType.DOG && Utils.RandBool()) { EarData oldData = target.ears.AsReadOnlyData(); target.UpdateEars(EarType.DOG); sb.Append(ChangedEarsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeLimit - remainingChanges)); } } if (target.tail.type != TailType.DOG && Utils.Rand(3) == 0) { TailData oldData = target.tail.AsReadOnlyData(); target.UpdateTail(TailType.DOG); sb.Append(ChangedTailText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeLimit - remainingChanges)); } } if (target.arms.type != ArmType.DOG && target.body.isFurry && target.tail.type == TailType.DOG && target.lowerBody.type == LowerBodyType.DOG && Utils.Rand(4) == 0) { ArmData oldArmData = target.arms.AsReadOnlyData(); target.UpdateArms(ArmType.DOG); sb.Append(ChangedArmsText(target, oldArmData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeLimit - remainingChanges)); } } if (!target.gills.isDefault && Utils.Rand(4) == 0) { GillData oldGillData = target.gills.AsReadOnlyData(); target.RestoreGills(); sb.Append(RemovedGillsText(target, oldGillData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeLimit - remainingChanges)); } } if (target.body.isFurry && Utils.Rand(3) == 0) { target.DeltaCreatureStats(tou: 4, sens: -3); sb.Append(FallbackToughenUpText(target)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeLimit - remainingChanges)); } } if (target is CombatCreature cc2 && remainingChanges == changeLimit) { cc2.AddHP(20); sb.Append(NothingHappenedGainHpText(target)); target.IncreaseLust(3); } return(ApplyChangesAndReturn(target, sb, changeLimit - 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 virtual string UpdateGillsText(Creature target, GillData oldData) { return(target.gills.TransformFromText(oldData)); }
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 }); 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); //possible use effects: //- corruption increases by 1 up to low threshold (~20) if (Utils.Rand(3) == 0 && target.corruption < 20) { if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } target.ChangeCorruption(1); } //- toughess up, sensitivity down if (Utils.Rand(3) == 0 && target.relativeToughness < 50) { target.DeltaCreatureStats(tou: 1, sens: -1); } //- speed down if (Utils.Rand(3) == 0 && target.relativeSpeed > 40) { target.ChangeSpeed(-1); } //-always increases lust by a function of sensitivity //"The tingling of the tentacle //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)); } } //physical changes: //- may randomly remove bee abdomen, if present; always checks and does so when any changes to hair might happen if (Utils.Rand(4) == 0 && target.tail.type == TailType.BEE_STINGER) { TailData oldData = target.tail.AsReadOnlyData(); target.UpdateTail(TailType.NONE); sb.Append(UpdateTailText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //-may randomly remove bee wings: if (Utils.Rand(4) == 0 && target.wings.type == WingType.BEE_LIKE) { WingData oldData = target.wings.AsReadOnlyData(); target.RestoreWings(); sb.Append(RestoredWingsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //-hair morphs to anemone tentacles, retains color, hair shrinks back to med-short('shaggy') and stops growing, lengthening treatments don't work and goblins won't cut it, but more anemone items can lengthen it one level at a time if (target.gills.type == GillType.ANEMONE && target.hair.type != HairType.ANEMONE && Utils.Rand(5) == 0) { HairData oldData = target.hair.AsReadOnlyData(); target.UpdateHair(HairType.ANEMONE, newStyle: HairStyle.WAVY); sb.Append(UpdateHairText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //-feathery gills sprout from chest and drape sensually over nipples (cumulative swimming power boost with fin, if swimming is implemented) if (Utils.Rand(5) == 0 && target.gills.type != GillType.ANEMONE && target.body.primarySkin.tone == Tones.BLUE_BLACK) { GillData oldData = target.gills.AsReadOnlyData(); target.UpdateGills(GillType.ANEMONE); sb.Append(UpdateGillsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //-[aphotic] skin tone (blue-black) if (Utils.Rand(5) == 0 && target.body.primarySkin.tone != Tones.BLUE_BLACK) { target.body.ChangeAllSkin(Tones.BLUE_BLACK); //kGAMECLASS.rathazul.addMixologyXP(20); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //-eat more, grow more 'hair': if (target.hair.type == HairType.ANEMONE && target.hair.length < 36 && Utils.Rand(2) == 0) { double temp = 5 + Utils.Rand(3); //grow it, and force growth. ignore the natural growth because that's how anemone hair works - it lengthens with tf item. target.hair.GrowHair(temp, true); 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 }, 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 if (target.relativeSensitivity > 25 && Utils.Rand(3) < 2) { target.ChangeSensitivity((-1 - Utils.Rand(3))); } //Increase strength 1-2 points (Up to 50) (60 for tiger) if (((target.relativeStrength < 60 && isTigerShark) || target.relativeStrength < 50) && Utils.Rand(3) == 0) { target.ChangeStrength(1 + Utils.Rand(2)); } //Increase Speed 1-3 points (Up to 75) (100 for tigers) if (((target.relativeSpeed < 100 && isTigerShark) || target.relativeSpeed < 75) && Utils.Rand(3) == 0) { target.ChangeSpeed(1 + Utils.Rand(3)); } //Reduce sensitivity 1-3 Points (Down to 25 points) //Increase Libido 2-4 points (Up to 75 points) (100 for tigers) if (((target.relativeLibido < 100 && isTigerShark) || target.relativeLibido < 75) && Utils.Rand(3) == 0) { target.ChangeLibido((1 + Utils.Rand(3))); } //Decrease intellect 1-3 points (Down to 40 points) if (target.relativeIntelligence > 40 && Utils.Rand(3) == 0) { target.ChangeIntelligence(-(1 + Utils.Rand(3))); } //Smexual stuff! //-TIGGERSHARK ONLY: Grow a c**t (guaranteed if no gender) if (isTigerShark && (target.gender == 0 || (!target.hasVagina && Utils.Rand(3) == 0))) { if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } //(balls) //(dick) //(neither) target.genitals.AddVagina(); target.ChangeSensitivity(10); } //WANG GROWTH - TIGGERSHARK ONLY if (isTigerShark && (!target.hasCock) && Utils.Rand(3) == 0) { //Genderless: //Female: if (target.balls.count == 0) { target.balls.GrowBalls(); } target.genitals.AddCock(CockType.defaultValue, 7, 1.4); target.DeltaCreatureStats(lib: 4, sens: 5, lus: 20); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //(Requires the target having two testicles) if (isTigerShark && (target.balls.count == 0 || target.balls.count == 2) && target.hasCock && Utils.Rand(3) == 0) { if (target.balls.count == 2) { target.balls.AddBalls(2); } else if (target.balls.count == 0) { target.balls.GrowBalls(); } target.DeltaCreatureStats(lib: 2, sens: 3, lus: 10); 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(); } //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(); sb.Append(ClearOvipositionText(target)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Transformations: //Mouth TF if (target.face.type != FaceType.SHARK && Utils.Rand(3) == 0) { FaceData oldData = target.face.AsReadOnlyData(); target.UpdateFace(FaceType.SHARK); sb.Append(UpdateFaceText(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)); } } //Tail TF if (target.tail.type != TailType.SHARK && Utils.Rand(3) == 0) { TailData oldData = target.tail.AsReadOnlyData(); target.UpdateTail(TailType.SHARK); sb.Append(UpdateTailText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Gills TF if (target.gills.type != GillType.FISH && target.tail.type == TailType.SHARK && target.face.type == FaceType.SHARK && Utils.Rand(3) == 0) { GillData oldData = target.gills.AsReadOnlyData(); target.UpdateGills(GillType.FISH); sb.Append(UpdateGillsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Hair if (target.hair.hairColor != HairFurColors.SILVER && Utils.Rand(4) == 0) { target.hair.SetHairColor(HairFurColors.SILVER); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Skin //MOD NOTE: F**K. A TWO TONED SKIN TONE. F**K F**K F**K. //MOD NOTE (continued): tigershark skin tone is hacked in. it's a hack. it's an ugly as f**k hack and i need a shower now. but it'll work. i really, really, really //dont want to add a new body type for tigersharks, and i am not adding a fur color equivalent for tones for literally just tigersharks. if (((target.body.primarySkin.tone != Tones.GRAY && target.body.primarySkin.tone != Tones.TIGERSHARK) || target.body.type != BodyType.HUMANOID) && Utils.Rand(7) == 0) { Tones targetTone = isTigerShark ? Tones.TIGERSHARK : Tones.GRAY; SkinTexture targetTexture = SkinTexture.ROUGH; //getGame().rathazul.addMixologyXP(20); BodyData oldData = target.body.AsReadOnlyData(); target.UpdateBody(BodyType.HUMANOID, targetTone, targetTexture); sb.Append(UpdateBodyText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //FINZ R WINGS if ((target.wings.type != WingType.NONE || target.back.type != BackType.SHARK_FIN) && Utils.Rand(3) == 0) { target.UpdateBack(BackType.SHARK_FIN); WingData oldData = target.wings.AsReadOnlyData(); target.RestoreWings(); sb.Append(RestoredWingsText(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 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)); }
private string DoTransformationCommon(Creature target, bool currentlyInCombat, 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; bool statsChanged = false; 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, currentlyInCombat)); //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. if (target.relativeSpeed < 70 && Utils.Rand(2) == 0) { target.IncreaseSpeed(2 - (target.relativeSpeed / 50)); statsChanged = true; } //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); //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.type != BackType.SHARK_FIN && !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)); } } //Removes wings and shark fin if ((target.wings.type != WingType.NONE || target.back.type == BackType.SHARK_FIN) && Utils.Rand(3) == 0) { if (target.back.type == BackType.SHARK_FIN) { target.RestoreBack(); } WingData oldData = target.wings.AsReadOnlyData(); target.RestoreWings(); sb.Append(RestoredWingsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //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)); } } //Sexual changes //-Remove extra breast rows if (target.breasts.Count > 1 && Utils.Rand(3) == 0 && !HyperHappySettings.isEnabled) { target.genitals.RemoveExtraBreastRows(); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //adjust cocks until the target has 2 reptilian cocks. only occurs for males or herms, or genderless if the hyper happy flag is off and a 1/2 roll procs true. if ((target.gender.HasFlag(Gender.MALE) || (target.gender == Gender.GENDERLESS && !HyperHappySettings.isEnabled && Utils.Rand(2) == 0)) && (target.cocks.Count != 2 || target.genitals.CountCocksOfType(CockType.LIZARD) != 2) && Utils.Rand(3) == 0) { int lizardCocks = target.genitals.CountCocksOfType(CockType.LIZARD); //grant up to 2 lizard cocks. if (lizardCocks < 2) { //if we have two or less cocks, convert all that we do have to lizard. if (target.cocks.Count < 3) { foreach (C**k c**k in target.cocks) { target.genitals.UpdateCock(c**k, CockType.LIZARD); } //then, add c**k(s) until we have 2 lizard cocks while (target.cocks.Count < 2) { target.AddCock(CockType.LIZARD); } } else if (lizardCocks == 1) { int toChange = target.cocks[0].type == CockType.LIZARD ? 0 : 1; target.genitals.UpdateCock(toChange, CockType.LIZARD); } } //otherwise, we already have 2 lizard cocks (or more). we're only going to keep 2 lizard cocks, so we need to remove extra ones. else { //any non-lizard c**k gets removed first. C**k toRemove = target.cocks.FirstOrDefault(x => x.type != CockType.LIZARD); //if we can't find one, it means we only have lizard cocks. remove the last one. if (toRemove is null) { toRemove = target.cocks[target.cocks.Count - 1]; } } } //9c) II The tongue (sensitivity bonus, stored as a perk?) if (changeCount == remainingChanges && Utils.Rand(3) == 0) { TongueData oldData = target.tongue.AsReadOnlyData(); target.UpdateTongue(TongueType.SNAKE); sb.Append(UpdateTongueText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //9c) III The fangs if (changeCount == remainingChanges && target.tongue.type == TongueType.SNAKE && target.face.type != FaceType.SNAKE && Utils.Rand(3) == 0) { FaceData oldData = target.face.AsReadOnlyData(); target.UpdateFace(FaceType.SNAKE); sb.Append(UpdateFaceText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //9c) I The tail ( http://tvtropes.org/pmwiki/pmwiki.php/Main/TransformationIsAFreeAction ) (Shouldn't we try to avert this? -Ace) //Should the enemy "kill" you during the transformation, it skips the scene and immediately goes to tthe rape scene. //(Now that I'm thinking about it, we should add some sort of appendix where the target realizes how much he's/she's changed. -Ace) //MOD NOTE: this also silently grants a reptilian body. there's also a check for this if you somehow lose the reptilian body and have a naga lower body later. if (changeCount == remainingChanges && target.face.type == FaceType.SNAKE && target.lowerBody.type != LowerBodyType.NAGA && Utils.Rand(4) == 0) { target.UpdateLowerBody(LowerBodyType.NAGA); // Naga lower body plus a tail may look awkward, so silently discard it (Stadler76) target.RestoreTail(); //convert body to match lower body. if (target.body.type != BodyType.REPTILE) { target.UpdateBody(BodyType.REPTILE, Tones.GREEN, Tones.LIGHT_GREEN); } if (--remainingChanges <= 0 || currentlyInCombat) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (target.body.type != BodyType.REPTILE && target.lowerBody.type == LowerBodyType.NAGA) { BodyData oldData = target.body.AsReadOnlyData(); target.UpdateBody(BodyType.REPTILE, Tones.GREEN, Tones.LIGHT_GREEN); sb.Append(UpdateBodyText(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)); } } //Default change - blah if (changeCount == remainingChanges && !statsChanged) { } //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)); }
//trying to think of a good way to do nipple piercings for goblins when you go full goblin without being too intrusive. //can't. oh well. but hey, at least it removes inverted nipples without requiring piercings, i guess //fun fact: this is (as of writing) the only way to restore nipples back to normal after you've made them fuckable. it's now possible to remove fuckable nipples just //by shrinking them down (they become inverted), but they're still not 'normal.' this will convert inverted nipples back to normal. so, if you want to remove fuckable nipples, //shrink them down, then proc this a few times. It's also possible that nipple piercings remove inverted nipples over time, but as of writing, that's not (currently) implemented protected internal override string DoTransformation(Creature target, out bool isBadEnd) { isBadEnd = false; //rolls of 1/2, 1/3, 1/4, and 1/5 for extra changes. i don't feel like figuring out the odds, so here's the simple split: //the most changes (+4) has an odds of 1/120, and the least changes (+0) have an odds of 1/5. the remaining change counts vary, totaling 19/24. int changeCount = GenerateChangeCount(target, new int[] { 2, 3, 4, 5 }); 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. target.IncreaseLust(15); //Stronger if (target.relativeStrength > 50) { if (target.relativeStrength > 90) { target.DecreaseStrengthByPercent(3); } else if (target.relativeStrength > 70) { target.DecreaseStrengthByPercent(2); } else { target.DecreaseStrengthByPercent(1); } } ///Less tough if (target.relativeToughness > 50) { if (target.relativeToughness > 90) { target.DecreaseToughnessByPercent(4); } else if (target.relativeToughness > 70) { target.DecreaseToughnessByPercent(2); } else { target.DecreaseToughnessByPercent(1); } } //Speed boost if (Utils.Rand(3) == 0 && target.relativeSpeed < 50) { target.IncreaseSpeed(1 + Utils.Rand(2)); } //antianemone corollary: if (target.hair.type == HairType.ANEMONE && Utils.Rand(2) == 0) { //-insert anemone hair removal into them under whatever criteria you like, though hair removal should precede abdomen growth; here's some sample text: HairData oldData = target.hair.AsReadOnlyData(); target.RestoreHair(); sb.Append(RestoredHairText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Shrink if (Utils.Rand(2) == 0 && target.heightInInches > 48) { target.build.DecreaseHeight((byte)(1 + Utils.Rand(5))); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //this will handle the edge case where the change count starts out as 0. if (remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } //Normal transforms (Cost 1) //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)); } } //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)); } } //Restore arms to become human arms again if (Utils.Rand(4) == 0 && !target.arms.isDefault) { ArmData oldData = target.arms.AsReadOnlyData(); target.RestoreArms(); sb.Append(RestoredArmsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //SEXYTIEMS //Multidick killa! if (target.cocks.Count > 1 && Utils.Rand(3) == 0) { target.genitals.RemoveCock(); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Boost vaginal capacity without gaping if (Utils.Rand(3) == 0 && target.hasVagina && target.genitals.standardBonusVaginalCapacity < 40) { target.genitals.IncreaseBonusVaginalCapacity(5); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Boost fertility if (Utils.Rand(4) == 0 && target.fertility.totalFertility < 40 && target.hasVagina) { target.fertility.IncreaseFertility((byte)(2 + Utils.Rand(5))); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Shrink primary dick to no longer than 12 inches else if (target.cocks.Count == 1 && Utils.Rand(2) == 0 && !hyperHappy) { if (target.cocks[0].length > 12) { double delta = target.cocks[0].DecreaseLength(1 + Utils.Rand(3)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //GENERAL APPEARANCE STUFF BELOW //REMOVAL STUFF //Removes wings! if ((target.wings.type != WingType.NONE) && Utils.Rand(4) == 0) { WingData oldData = target.wings.AsReadOnlyData(); target.RestoreWings(); sb.Append(RestoredWingsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //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)); } } //Remove odd eyes if (Utils.Rand(5) == 0 && target.eyes.count != 2) { EyeData oldData = target.eyes.AsReadOnlyData(); target.RestoreEyes(); sb.Append(RestoredEyesText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //-Remove extra breast rows if (target.breasts.Count > 1 && Utils.Rand(3) == 0) { target.genitals.RemoveExtraBreastRows(); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Skin/fur if (target.body.type != BodyType.HUMANOID && Utils.Rand(4) == 0 && target.face.type == FaceType.HUMAN) { BodyData oldData = target.body.AsReadOnlyData(); target.RestoreBody(); sb.Append(RestoredBodyText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //skinTone if (!Species.GOBLIN.availableTones.Contains(target.body.primarySkin.tone) && Utils.Rand(2) == 0) { if (Utils.Rand(10) != 0) { target.body.ChangeMainSkin(Tones.DARK_GREEN); } else if (Utils.RandBool()) { target.body.ChangeMainSkin(Tones.PALE_YELLOW); } else { target.body.ChangeMainSkin(Tones.GRAYISH_BLUE); } //MOD note: rathazal mixology called here - how do we want to standardize that? if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Face! if (target.face.type != FaceType.HUMAN && Utils.Rand(4) == 0 && target.ears.type == EarType.ELFIN) { FaceData oldData = target.face.AsReadOnlyData(); target.UpdateFace(FaceType.HUMAN); sb.Append(UpdateFaceText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Ears! if (target.ears.type != EarType.ELFIN && Utils.Rand(3) == 0) { EarData oldData = target.ears.AsReadOnlyData(); target.UpdateEars(EarType.ELFIN); sb.Append(UpdateEarsText(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)); } } //Nipples Turn Back: if (target.genitals.hasBlackNipples && Utils.Rand(3) == 0) { target.genitals.SetBlackNipples(false); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //MOD: Added: remove inverted nipples. this by entension is able to remove fuckable nipples, assuming you shrunk them down until they became inverted. if (target.genitals.nippleType.IsInverted() && Utils.Rand(3) == 0) { target.genitals.SetNippleStatus(NippleStatus.NORMAL); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Debugcunt if (Utils.Rand(3) == 0 && target.hasVagina && target.vaginas.Any(x => !x.isDefault)) { foreach (V****a vag in target.vaginas) { if (!vag.isDefault) { target.genitals.RestoreVagina(vag); } } if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (Utils.Rand(4) == 0 && target.ass.wetness > target.ass.minWetness) { if (target.ass.wetness - target.ass.minWetness > 1) { target.ass.DecreaseWetness(2); } else { target.ass.DecreaseWetness(); } if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (Utils.Rand(3) == 0) { if (Utils.Rand(2) == 0) { target.femininity.ChangeFemininityToward(85, 3); } if (Utils.Rand(2) == 0) { target.build.ChangeThicknessToward(20, 3); } if (Utils.Rand(2) == 0) { target.build.ChangeMuscleToneToward(15, 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 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(); //Zero Cost/Stat changes. //None at the moment 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); // Normal TFs //------------ if (Utils.Rand(4) == 0 && target.hair.type != HairType.NORMAL && target.hair.type != HairType.NO_HAIR && target.hair.type != HairType.QUILL) { //sb.Append("\n\nYour scalp feels really strange, but the sensation is brief. You feel your hair, and you immediately notice the change. <b>It would seem that your hair is normal again!</b>"); HairData oldData = target.hair.AsReadOnlyData(); target.UpdateHair(HairType.NORMAL); sb.Append(UpdateHairText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (Utils.Rand(4) == 0 && target.arms.type == ArmType.HARPY) { //sb.Append("\n\nYour arm feathers fall out completely, <b>leaving only the " + target.skinFurScales() + " underneath.</b>"); ArmData oldData = target.arms.AsReadOnlyData(); target.RestoreArms(); sb.Append(RestoredArmsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Remove gills if (Utils.Rand(3) == 0 && target.gills.type != GillType.NONE) { GillData oldData = target.gills.AsReadOnlyData(); target.RestoreGills(); sb.Append(RestoredGillsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //restore spider eyes. if (Utils.Rand(3) == 0 && target.eyes.type == EyeType.SPIDER) { //sb.Append("\n\nYour eyes start throbbing painfully, your sight in them eventually going dark. You touch your head to inspect your eyes, only to find out that they have changed. <b>You have human eyes now!</b>"); EyeData oldData = target.eyes.AsReadOnlyData(); target.UpdateEyes(EyeType.HUMAN); sb.Append(UpdateEyesText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (Utils.Rand(3) == 0 && target.genitals.hasQuadNipples) { //sb.Append("\n\nA tightness arises in your nipples as three out of four on each breast recede completely, the leftover nipples migrating to the middle of your breasts. <b>You are left with only one nipple on each breast.</b>"); target.genitals.SetQuadNipples(false); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } // Main TFs //------------ //Change to fur if (Utils.Rand(3) == 0 && !target.body.IsFurBodyType()) { target.UpdateBody(BodyType.SIMPLE_FUR, new FurColor(HairFurColors.BROWN)); //sb.Append("\n\nYou shiver, feeling a bit cold. Just as you begin to wish for something to cover up with, it seems your request is granted; <b>fur begins to grow all over your body!</b> You tug at the tufts in alarm, but they're firmly rooted and... actually pretty soft. Huh. "); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Gain Echidna ears if (Utils.Rand(3) == 0 && target.ears.type != EarType.ECHIDNA) { target.UpdateEars(EarType.ECHIDNA); //sb.Append("\n\n"); //sb.Append(" <b>You now have echidna ears!</b>"); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Gain Echidna tail if (Utils.Rand(3) == 0 && target.ears.type == EarType.ECHIDNA && target.tail.type != TailType.ECHIDNA) { target.UpdateTail(TailType.ECHIDNA); //sb.Append("\n\n"); //sb.Append(" <b>You now have an echidna tail!</b>"); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Gain Echidna legs if (Utils.Rand(3) == 0 && target.ears.type == EarType.ECHIDNA && target.tail.type == TailType.ECHIDNA && target.lowerBody.type != LowerBodyType.ECHIDNA) { target.UpdateLowerBody(LowerBodyType.ECHIDNA); //sb.Append("\n\n"); //sb.Append(" <b>They actually look like the feet of an echidna!</b>"); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Convert one existing c**k to Echidna if (Utils.Rand(3) == 0 && target.hasCock && target.genitals.CountCocksOfType(CockType.ECHIDNA) < target.cocks.Count) { int firstNonEchidna = target.cocks.FirstIndexOf(x => x.type != CockType.ECHIDNA); target.genitals.UpdateCock(firstNonEchidna, CockType.ECHIDNA); //sb.Append("\n\n"); //if (target.cocks.Count == 1) //sb.Append("Your [c**k] suddenly becomes rock hard out of nowhere. You " + target.clothedOrNakedLower("pull it out from your [armor], right in the middle of the food tent, watching", "watch") + " as it begins to shift and change. It becomes pink in color, and you feel a pinch at the head as it splits to become four heads. " + (target.hasSheath() ? "" : "The transformation finishes off with a fleshy sheath forming at the base.") + " It ejaculates before going limp, retreating into your sheath."); //else //sb.Append("One of your penises begins to feel strange. You " + target.clothedOrNakedLower("pull the offending c**k out from your [armor], right in the middle of the food tent, watching", "watch") + " as it begins to shift and change. It becomes pink in color, and you feel a pinch at the head as it splits to become four heads. " + (target.hasSheath() ? "" : "The transformation finishes off with a fleshy sheath forming at the base.") + " It ejaculates before going limp, retreating into your sheath."); //sb.Append(" <b>You now have an echidna penis!</b>"); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Gain Echidna tongue if (Utils.Rand(3) == 0 && Species.ECHIDNA.Score(target) >= 2 && target.tongue.type != TongueType.ECHIDNA) { target.UpdateTongue(TongueType.ECHIDNA); //sb.Append("\n\nYou feel an uncomfortable pressure in your tongue as it begins to shift and change. Within moments, you are able to behold your long, thin tongue. It has to be at least a foot long. <b>You now have an echidna tongue!</b>"); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Gain quill hair if (Utils.Rand(4) == 0 && ((target.hair.type == HairType.NORMAL && !target.hair.isGrowing) || target.hair.type == HairType.NO_HAIR)) { target.UpdateHair(HairType.QUILL); //sb.Append("\n\nYour scalp begins to tingle as your hair falls out in clumps, leaving you with a bald head. You aren't bald for long, though. An uncomfortable pressure racks the entirety of your scalp as hard quills begin to sprout from your hair pores. Their growth stops as they reach shoulder length. <b>You now have quills in place of your hair!</b>"); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Gain Echidna face if you have the right conditions. if (Utils.Rand(4) == 0 && target.body.isFurry && target.ears.type == EarType.ECHIDNA && target.tail.type == TailType.ECHIDNA && target.tongue.type == TongueType.ECHIDNA) { target.UpdateFace(FaceType.ECHIDNA); //sb.Append("You groan loudly as the bones in your face begin to reshape and rearrange. Most notable, you feel your mouth lengthening into a long, thin snout. <b>You now have an echidna face!</b>"); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } // Other Changes //------------ //Hair stops growing if (Utils.Rand(4) == 0 && Species.ECHIDNA.Score(target) >= 2 && target.hair.isGrowing && !target.hair.growthArtificallyDisabled) { if (target.hair.StopNaturalGrowth()) { //sb.Append("\n\nYour scalp tingles oddly. In a panic, you reach up to your " + target.hairDescript() + ", but thankfully it appears unchanged.\n"); //sb.Append("(<b>Your hair has stopped growing.</b>)"); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //Sexual changes if (Utils.Rand(3) == 0 && target.hasCock && target.genitals.cumMultiplierTrue < 25) { double temp = 1 + Utils.Rand(5); //really not a fan of this hard coded check b/c its not future proof, but it seems to be limited in scope enough i guess i can allow it. //Lots of cum raises cum multiplier cap to 2 instead of 1.5 if (target.HasPerk <MessyOrgasms>()) { temp += 1 + Utils.Rand(10); } temp *= 0.1; target.genitals.IncreaseCumMultiplier(temp); //Flavor text //if (target.balls.count == 0) //sb.Append("\n\nYou feel a churning inside your gut as something inside you changes."); //else //if (target.balls.count > 0) //sb.Append("\n\nYou feel a churning in your " + target.ballsDescriptLight() + ". It quickly settles, leaving them feeling somewhat more dense."); //sb.Append(" A bit of milky pre dribbles from your " + target.multiCockDescriptLight() + ", pushed out by the change."); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (Utils.Rand(3) == 0 && target.gender == Gender.MALE && target.genitals.AverageCupSize() > target.genitals.smallestPossibleMaleCupSize && !hyperHappy) { //sb.Append("\n\nYou cup your t**s as they begin to tingle strangely. You can actually feel them getting smaller in your hands!"); foreach (Breasts tit in target.breasts.Where(x => x.cupSize > target.genitals.smallestPossibleMaleCupSize)) { tit.ShrinkBreasts(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)); } } //Ovi perk gain if (Utils.Rand(4) == 0 && Species.ECHIDNA.Score(target) >= 3 && target.hasVagina && target.womb.canObtainOviposition) { if (target.womb.GrantOviposition()) { sb.Append(GrantOvipositionText(target)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } if ((target.hasVagina && !target.HasTimedEffect <Heat>() && Utils.Rand(3) == 0) || (target.perks.HasTimedEffect <Heat>() && Utils.RandBool() && target.GetTimedEffectData <Heat>().totalAddedLibido < 30)) { target.GoIntoHeat(); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Thickness and hip modifier if (Utils.Rand(2) == 0 && target.build.thickness < 90) { target.build.GetThicker(2); } //old was rand(2.4) what the actual f**k. i assume that means a 1 in 2.4 chance, but why??? regardless, it's now a 5 in 12 chance (which is 1:2.4) if (Utils.Rand(12) < 5 && target.hasVagina && !target.genitals.AppearsMoreMaleThanFemale() && target.hips.size < 14) { target.build.GrowHips(); //sb.Append("\n\nAfter finishing, you find that your gait has changed. Did your [hips] widen?"); 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)); }