//5. Is a mammal that moves, sleeps, eats public Rabbit(string name, EyesColor eyes, FurColor fur, Genders gender, DateTime birthDate) { this.name = name; Eyes = eyes; Fur = fur; Gender = gender; BirthDate = birthDate; }
public Rabbit(EyesColor eyesColor, FurColor furColor, Gender gender, DateTime birthDate, Owner owner) { this.eyesColor = eyesColor; this.furColor = furColor; this.gender = gender; this.birthDate = birthDate; this.owner = owner; }
public Dog(string dogName, EyesColor eyesColor, FurColor furColor, Gender gender, DateTime birthDate, Owner owner) { this.dogName = dogName; this.eyesColor = eyesColor; this.furColor = furColor; this.gender = gender; this.birthDate = birthDate; this.owner = owner; }
internal static FurColor GetValidFurColor(FurColor overrideColor, FurColor primary, FurColor secondary, HairFurColors activeHairColor, FurColor fallback) { if (!FurColor.IsNullOrEmpty(overrideColor)) { return(overrideColor); } else if (!FurColor.IsNullOrEmpty(secondary)) { return(secondary); } else if (!FurColor.IsNullOrEmpty(primary)) { return(primary); } else if (!HairFurColors.IsNullOrEmpty(activeHairColor)) { return(new FurColor(activeHairColor)); } return(fallback); }
protected internal override string DoTransformation(Creature target, out bool isBadEnd) { isBadEnd = false; //by default, this is 2 rolls at 50%, so a 25% chance of 0 additional tfs, 50% chance of 1 additional tf, 25% chance of 2 additional tfs. //also takes into consideration any perks that increase or decrease tf effectiveness. if you need to roll out your own, feel free to do so. int changeCount = GenerateChangeCount(target, new int[] { 2, 2 }); int remainingChanges = changeCount; StringBuilder sb = new StringBuilder(); //For all of these, any text regarding the transformation should be instead abstracted out as an abstract string function. append the result of this abstract function //to the string builder declared above (aka sb.Append(FunctionCall(variables));) string builder is just a fancy way of telling the compiler that you'll be creating a //long string, piece by piece, so don't do any crazy optimizations first. //the initial text for starting the transformation. feel free to add additional variables to this if needed. //Add any free changes here - these can occur even if the change count is 0. these include things such as change in stats (intelligence, etc) //change in height, hips, and/or butt, or other similar stats. double crit = 0; if (Utils.Rand(100) < 15) { crit = Utils.Rand(20) / 10.0 + 2; } bool hasCrit() => crit > 1; sb.Append(InitialTransformationText(target, crit)); //STAT CHANGES - TOU SPE INT RANDOM CHANCE, LIB LUST COR ALWAYS UPPED target.DeltaCreatureStats(lib: 1 + Utils.Rand(2), lus: 5 + Utils.Rand(10), corr: 1 + Utils.Rand(5)); if (target.relativeToughness < 70 && Utils.Rand(3) == 0) { double delta = target.ChangeToughness(crit); sb.Append(IncreasedToughnessText(crit, delta)); } if (target.relativeSpeed > 30 && Utils.Rand(7) == 0) { double loss = target.DecreaseSpeed(crit); sb.Append(DecreasedSpeedText(crit, loss)); } if (target.relativeIntelligence < 60 && Utils.Rand(7) == 0) { double delta = target.ChangeIntelligence(crit); sb.Append(IncreasedIntelligenceText(crit, delta)); } //handle edge case where we start at 0. if (remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } //Non-free changes. //if (--remainingChanges <= 0) return ApplyChangesAndReturn(target, sb, changeCount - remainingChanges); //MUTATIONZZZZZ //PRE-CHANGES: become biped, remove horns, remove wings, give human tongue, remove claws, remove antennea //no claws if (Utils.Rand(4) == 0 && target.arms.hands.isClaws) { ArmData oldData = target.arms.AsReadOnlyData(); if (target.RestoreArms()) { sb.Append(RestoredArmsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //remove antennae if (target.antennae.type != AntennaeType.NONE && Utils.Rand(3) == 0) { AntennaeData oldData = target.antennae.AsReadOnlyData(); target.RestoreAntennae(); sb.Append(RestoredAntennaeText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //remove horns if (target.horns.type != HornType.NONE && Utils.Rand(3) == 0) { HornData oldData = target.horns.AsReadOnlyData(); target.RestoreHorns(); sb.Append(RestoredHornsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //remove wings if ((target.wings.type != WingType.NONE || target.back.type == BackType.SHARK_FIN) && Utils.Rand(3) == 0) { BackData oldBack = target.back.AsReadOnlyData(); if (target.back.type == BackType.SHARK_FIN) { target.RestoreBack(); } WingData oldWings = target.wings.AsReadOnlyData(); target.RestoreWings(); sb.Append(RestoredBackAndWings(target, oldWings, oldBack)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //give human tongue if (target.tongue.type != TongueType.HUMAN && Utils.Rand(3) == 0) { //MOD NOTE: this was incorrect - this actually was === (equal with strict typechecking) instead of = (assign). so this was an implicit bool. //this is part of the reason why the rework forces all value updates as function calls. the more you know. TongueData oldData = target.tongue.AsReadOnlyData(); target.RestoreTongue(); sb.Append(RestoredTongueText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //remove non-wolf eyes if (Utils.Rand(3) == 0 && target.eyes.type != EyeType.HUMAN && target.eyes.type != EyeType.WOLF) { EyeData oldData = target.eyes.AsReadOnlyData(); target.RestoreEyes(); sb.Append(RestoredEyesText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //normal legs if (target.lowerBody.type != LowerBodyType.WOLF && Utils.Rand(4) == 0) { LowerBodyData oldData = target.lowerBody.AsReadOnlyData(); target.RestoreLowerBody(); sb.Append(RestoredLowerBodyText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //normal arms if (Utils.Rand(4) == 0) { ArmData oldData = target.arms.AsReadOnlyData(); target.RestoreArms(); sb.Append(RestoredArmsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } HairData oldHair = target.hair.AsReadOnlyData(); //remove feather hair if (Utils.Rand(4) == 0 && RemoveFeatheryHair(target)) { sb.Append(RemovedFeatheryHairText(target, oldHair)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //remove basilisk hair if (Utils.Rand(4) == 0 && target.hair.IsBasiliskHair()) { HairData oldData = target.hair.AsReadOnlyData(); target.RestoreHair(); target.hair.SetHairLength(0); target.hair.ResumeNaturalGrowth(); sb.Append(RemovedBasiliskHair(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //MUTATIONZ AT ANY TIME: wolf dick, add/decrease breasts, decrease breast size if above D //get a wolf dick //if ya genderless we give ya a dick cuz we nice like that //MOD: Now respects hyper happy. if (target.gender == Gender.GENDERLESS && !hyperHappy) { target.genitals.AddCock(CockType.WOLF, Utils.Rand(4) + 4, Utils.Rand(8) / 4.0 + 0.25, 1.5); sb.Append(BecameMaleByGrowingCock(target)); target.DeltaCreatureStats(lib: 3, sens: 2, lus: 25); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //if ya got a dick that's ok too we'll change it to wolf //MOD NOTE: but only if you don't only have wolf cocks, of course (because if they are all wolf cocks, we can't make anything wolf cocks, duh). if (target.hasCock && !target.genitals.OnlyHasCocksOfType(CockType.WOLF) && Utils.RandBool()) { //MOD NOTE: no longer shamelessly copy/pasted from dog c**k, because we have better ways of looping in C#. C**k firstNonWolf = target.cocks.First(x => x.type != CockType.WOLF); CockData oldData = firstNonWolf.AsReadOnlyData(); //Select first non-wolf c**k //MOD: now using type description because we can, so the fact this used generic is irrelevant now :) if (firstNonWolf.type == CockType.HORSE) { //horses get changes if (firstNonWolf.length > 6) { firstNonWolf.DecreaseLength(2); } else { firstNonWolf.DecreaseLength(.5); } firstNonWolf.IncreaseThickness(.5); } target.DeltaCreatureStats(sens: 3, lus: 5 * crit); target.genitals.UpdateCockWithKnot(firstNonWolf, CockType.WOLF, 1.5); firstNonWolf.IncreaseThickness(2); sb.Append(ChangedCockToWolf(target, oldData, oldData.cockIndex)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //titties for those who got titties //wolfs have 8 nips so, 4 rows max. fen has no power here I'm making a wolf not a dog. //MOD: still stolen shamelessly from dog and updated, but now with the modern format. woo! //MOD: if breasts can be updated (not flat) and we flip a coin. if (target.genitals.BiggestCupSize() > CupSize.FLAT && Utils.RandBool()) { if (target.breasts.Count < 4) { byte breastCount = (byte)target.breasts.Count; BreastCollectionData oldBreastData = target.genitals.allBreasts.AsReadOnlyData(); //in vanilla code, we had some strange checks here that required the first row (and only the first row) be a certain size. //now, we check all the rows, but no longer require any of them to be a certain size. instead, if it's not the right size, we make it that size, //then add the row. so, for two rows, your first row must be at least a B-Cup. for 3: first must be a C cup, second an A cup. //if we supported 4 rows, it'd be D, B, A. for (int x = 0; x < target.breasts.Count; x++) { CupSize requiredSize = (CupSize)(byte)(target.breasts.Count - x); if (x == 0) { requiredSize++; } if (target.breasts[x].cupSize < requiredSize) { target.breasts[x].SetCupSize(requiredSize); } } target.genitals.AddBreastRow(target.breasts[breastCount - 1].cupSize.ByteEnumSubtract(1)); bool doCrit = false, uberCrit = false; if (target.breasts.Count == 2) { target.IncreaseCreatureStats(lus: 5, sens: 6); } else if (hasCrit()) { doCrit = true; if (crit > 2) { target.IncreaseCreatureStats(sens: 6, lus: 15); uberCrit = true; } else { target.IncreaseCreatureStats(sens: 3, lus: 10); } } sb.Append(UpdateAndGrowAdditionalRowText(target, oldBreastData, doCrit, uberCrit)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } else { BreastCollectionData oldBreastData = target.genitals.allBreasts.AsReadOnlyData(); //only call the normalize text if we actually did anything. related, anthro breasts now returns a bool. thanks, fox tfs. if (target.genitals.AnthropomorphizeBreasts()) { sb.Append(NormalizedBreastSizeText(target, oldBreastData)); } } } //Remove a breast row if over 4. afaik this should never happen. if (target.breasts.Count > 4 && Utils.Rand(3) == 0) { var oldData = target.breasts[target.breasts.Count - 1].AsReadOnlyData(); target.genitals.RemoveBreastRows(1); sb.Append(RemovedExcessRow(target, oldData)); } //Grow breasts if has v****a and has no breasts/nips //Shrink breasts if over D-cup CupSize targetSize = EnumHelper.Max(target.genitals.smallestPossibleCupSize, CupSize.D); if (!hyperHappy && target.genitals.BiggestCupSize() > targetSize && Utils.Rand(3) == 0) { BreastCollectionData oldCollection = target.genitals.allBreasts.AsReadOnlyData(); bool changedAnything = false; foreach (Breasts row in target.breasts) { //If this row is over threshhold if (row.cupSize > targetSize) { //Big change if (row.cupSize > CupSize.EE_BIG) { changedAnything |= row.ShrinkBreasts((byte)(2 + Utils.Rand(3))) > 0; } //Small change else { changedAnything |= row.ShrinkBreasts() > 0; } //Increment changed rows } } //Count shrinking if (changedAnything) { sb.Append(ShrunkRowsText(target, oldCollection)); remainingChanges--; if (remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //MUTATIONZ LEVEL 1: fur, stop hair growth, ears, tail //Gain fur if (Utils.Rand(5) == 0 && !target.body.IsFurBodyType()) { BodyData oldData = target.body.AsReadOnlyData(); Species.WOLF.GetRandomFurColors(out FurColor primary, out FurColor underbody); if (FurColor.IsNullOrEmpty(underbody)) { target.UpdateBody(BodyType.UNDERBODY_FUR, primary); } else { target.UpdateBody(BodyType.UNDERBODY_FUR, primary, underbody); } sb.Append(UpdateBodyText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Ears time if (Utils.Rand(3) == 0 && target.ears.type != EarType.WOLF) { EarData oldData = target.ears.AsReadOnlyData(); target.UpdateEars(EarType.WOLF); sb.Append(UpdateEarsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Wolf tail if (Utils.Rand(3) == 0 && target.tail.type != TailType.WOLF) { TailData oldData = target.tail.AsReadOnlyData(); target.UpdateTail(TailType.WOLF); sb.Append(UpdateTailText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Sets hair normal if (target.hair.type != HairType.NORMAL && Utils.Rand(3) == 0) { HairData oldData = target.hair.AsReadOnlyData(); target.RestoreHair(); sb.Append(RestoreHairText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //MUTATIONZ LEVEL 2: fur->arms fur+tail+ears->face stophair->nohair fur+tail->legs //gain wolf face if (target.face.type != FaceType.WOLF && target.ears.type == EarType.WOLF && target.tail.type == TailType.WOLF && target.body.IsFurBodyType() && Utils.Rand(5) == 0) { FaceData oldData = target.face.AsReadOnlyData(); target.UpdateFace(FaceType.WOLF); sb.Append(UpdateFaceText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //legz if (target.lowerBody.legCount == 2 && target.lowerBody.type != LowerBodyType.WOLF && target.tail.type == TailType.WOLF && target.body.IsFurBodyType() && Utils.Rand(4) == 0) { //Hooman feets //Hooves -> Paws LowerBodyData oldData = target.lowerBody.AsReadOnlyData(); target.UpdateLowerBody(LowerBodyType.WOLF); sb.Append(UpdateLowerBodyText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //MUTATIONZ LEVEL 3: face->eyes if (target.eyes.type != EyeType.WOLF && target.face.type == FaceType.WOLF && Utils.Rand(4) == 0) { EyeData oldData = target.eyes.AsReadOnlyData(); target.UpdateEyes(EyeType.WOLF); sb.Append(UpdateEyesText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //MISC CRAP //Neck restore if (target.neck.type != NeckType.HUMANOID && Utils.Rand(4) == 0) { NeckData oldData = target.neck.AsReadOnlyData(); target.RestoreNeck(); sb.Append(RestoredNeckText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Rear body restore if (!target.back.isDefault && Utils.Rand(5) == 0) { BackData oldData = target.back.AsReadOnlyData(); target.RestoreBack(); sb.Append(RestoredBackText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Ovi perk loss if (target.womb.canRemoveOviposition && Utils.Rand(5) == 0) { target.womb.ClearOviposition(); sb.Append(ClearOvipositionText(target)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (Utils.Rand(3) == 0) { var res = target.build.ChangeMuscleToneToward(100, 4); sb.Append(AdjustToneText(target, 4, res)); } if (Utils.Rand(3) == 0) { var adjustedAmount = target.build.ChangeThicknessToward(75, 3); sb.Append(AdjustThicknessText(target, adjustedAmount)); } //this is the fallthrough that occurs when a tf item goes through all the changes, but does not proc enough of them to exit early. it will apply however many changes //occurred, then return the contents of the stringbuilder. return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); }
public override int GetHashCode() { unchecked { return(((EyeColor != null ? EyeColor.GetHashCode() : 0) * 397) ^ (FurColor != null ? FurColor.GetHashCode() : 0)); } }
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 }, isEnhanced ? 3 : 1); int totalChanges = 0; 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. //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 //Increase player str: if (target.strength < 60 && Utils.Rand(3) == 0) { double delta = target.IncreaseStrength((60 - target.strength) / 10.0); sb.Append(StrengthUpText(delta)); } //Increase player tou: if (target.toughness < 60 && Utils.Rand(3) == 0) { double delta = target.IncreaseToughness((60 - target.toughness) / 10.0); sb.Append(ToughnessUpText(delta)); } //Decrease player spd if it is over 30: if (target.relativeSpeed > 30 && target.speed > 30 && Utils.Rand(3) == 0) { double decrease = target.DecreaseSpeed((target.speed - 30) / 10.0); sb.Append(SpeedDownText(decrease)); } //Increase Corr, up to a max of 50. //this is silent, apparently. if (!isPurified && target.corruption < 50) { target.IncreaseCorruptionBy((50 - target.corruption) / 10.0); } if (totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } //Sex bits - Duderiffic if (target.cocks.Count > 0 && Utils.Rand(2) == 0 && !hyperHappy) { //If the player has at least one dick, decrease the size of each slightly, C**k biggest = target.genitals.LongestCock(); CockData preChange = biggest.AsReadOnlyData(); if (biggest.DecreaseLengthAndCheckIfNeedsRemoval(Utils.Rand(3) + 1)) { target.genitals.RemoveCock(biggest); if (target.cocks.Count == 0 && !target.hasVagina) { BallsData oldBalls = target.balls.AsReadOnlyData(); target.AddVagina(0.25); target.genitals.RemoveAllBalls(); sb.Append(MadeFemale(target, preChange, oldBalls)); } else { sb.Append(ShrunkOneCock(target, preChange, true)); } } else { sb.Append(ShrunkOneCock(target, preChange, false)); } if (++totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } } //Sex bits - girly bool boobsGrew = false; //Increase player's breast size, if they are FF or bigger //do not increase size, but do the other actions: CupSize biggestCup = target.genitals.BiggestCupSize(); if ((biggestCup < CupSize.DD || (!isPurified && biggestCup < CupSize.FF)) && (isEnhanced || Utils.Rand(3) == 0)) { BreastData oldBreasts = target.breasts[0].AsReadOnlyData(); if (target.breasts[0].GrowBreasts((byte)(1 + Utils.Rand(3))) > 0) { boobsGrew = true; sb.Append(GrewFirstBreastRow(target, oldBreasts)); if (++totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } } target.DeltaCreatureStats(sens: .5); } //Remove feathery hair HairData oldHair = target.hair.AsReadOnlyData(); if (base.RemoveFeatheryHair(target)) { sb.Append(RemovedFeatheryHairText(target, oldHair)); if (++totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } } //refresh the biggest cup size because we may have grown some breasts earlier. biggestCup = target.genitals.BiggestCupSize(); //If breasts are D or bigger and are not lactating, they also start lactating: if (biggestCup >= CupSize.D && !target.genitals.isLactating && (isEnhanced || boobsGrew || Utils.Rand(3) == 0)) { BreastData preLactation = target.breasts[0].AsReadOnlyData(); target.genitals.StartLactating(); sb.Append(StartedLactatingText(target, preLactation)); if (++totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } target.DeltaCreatureStats(sens: .5); } //Quad nipples and other 'special isEnhanced things. if (isEnhanced) { //QUAD DAMAGE! if (!target.genitals.hasQuadNipples) { BreastCollectionData oldBreasts = target.genitals.allBreasts.AsReadOnlyData(); target.genitals.SetQuadNipples(true); sb.Append(GrantQuadNippleText(target, oldBreasts)); if (++totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } } else if (target.genitals.isLactating) { BreastCollectionData oldBreasts = target.genitals.allBreasts.AsReadOnlyData(); target.genitals.BoostLactation(2.5); double delta = 0; if (target.genitals.nippleLength < 1 || (target.genitals.nippleLength < 1.5 && !isPurified)) { delta = target.genitals.GrowNipples(0.25); target.DeltaCreatureStats(sens: .5); } sb.Append(BoostedLactationText(target, oldBreasts, delta)); if (++totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } } } //If breasts are already lactating and the player is not lactating beyond a reasonable level, they start lactating more: else { if (target.genitals.isLactating && (target.genitals.lactationStatus < LactationStatus.MODERATE || (!isPurified && target.genitals.lactationStatus < LactationStatus.STRONG)) && (isEnhanced || Utils.Rand(3) == 0)) { BreastCollectionData oldBreasts = target.genitals.allBreasts.AsReadOnlyData(); double delta = 0; target.genitals.BoostLactation(0.75); if (target.genitals.nippleLength < 1 || (target.genitals.nippleLength < 1.5 && !isPurified)) { delta = target.genitals.GrowNipples(0.25); target.DeltaCreatureStats(sens: .5); } sb.Append(BoostedLactationText(target, oldBreasts, delta)); if (++totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } } else if (isPurified && target.genitals.lactationStatus >= LactationStatus.STRONG) { BreastCollectionData oldData = target.genitals.allBreasts.AsReadOnlyData(); target.DeltaCreatureStats(sens: .5); target.genitals.BoostLactation(-1); sb.Append(BoostedLactationText(target, oldData, 0)); if (++totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } } } //If breasts are lactating at a fair level //and the player has not received this status, //apply an effect where the player really wants //to give their milk to other creatures //(capable of getting them addicted): biggestCup = target.genitals.BiggestCupSize(); if (!target.HasPerk <Feeder>() && target.genitals.lactationStatus >= LactationStatus.MODERATE && Utils.Rand(2) == 0 && biggestCup >= CupSize.DD && target.IsCorruptEnough(35)) { target.perks.AddPerk <Feeder>(); sb.Append(GainedFeederPerk(target)); if (++totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } } //UNFINISHED //If player has addictive quality and drinks pure version, removes addictive quality. //if the player has a v****a and it is tight, it loosens. if (target.hasVagina) { VaginalLooseness targetLooseness = EnumHelper.Min(VaginalLooseness.LOOSE, target.genitals.maxVaginalLooseness); V****a tightest = target.genitals.TightestVagina(); if (tightest.looseness < targetLooseness && Utils.Rand(2) == 0) { VaginaData preLoosened = tightest.AsReadOnlyData(); tightest.IncreaseLooseness(2); sb.Append(LoosenedTwatText(target, preLoosened)); if (++totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } target.DeltaCreatureStats(lus: 10); } } //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 (++totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } } //Rear body restore if (target.back.type != BackType.SHARK_FIN && Utils.Rand(5) == 0) { BackData oldData = target.back.AsReadOnlyData(); target.RestoreBack(); sb.Append(RestoredBackText(target, oldData)); if (++totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } } //Ovi perk loss if (!isPurified && target.womb.canRemoveOviposition && Utils.Rand(5) == 0) { target.womb.ClearOviposition(); sb.Append(ClearOvipositionText(target)); if (++totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } } //General Appearance (Tail -> Ears -> Paws(fur stripper) -> Face -> Horns //Give the player a bovine tail, same as the minotaur if (!isPurified && target.tail.type != TailType.COW && Utils.Rand(3) == 0) { TailData oldData = target.tail.AsReadOnlyData(); target.UpdateTail(TailType.COW); sb.Append(ChangedTailText(target, oldData)); if (++totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } } //Give the player bovine ears, same as the minotaur if (!isPurified && target.ears.type != EarType.COW && Utils.Rand(4) == 0 && target.tail.type == TailType.COW) { EarData oldEars = target.ears.AsReadOnlyData(); target.UpdateEars(EarType.COW); sb.Append(ChangedEarsText(target, oldEars)); if (++totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } } //If the player is under 7 feet in height, increase their height, similar to the minotaur if (((isEnhanced && target.build.heightInInches < 96) || target.build.heightInInches < 84) && Utils.Rand(2) == 0) { int temp = Utils.Rand(5) + 3; //Slow rate of growth near ceiling if (target.build.heightInInches > 74) { temp = (int)Math.Floor(temp / 2.0); } //Never 0 if (temp == 0) { temp = 1; } byte delta = target.build.IncreaseHeight((byte)temp); sb.Append(GrowTaller(target, delta)); if (++totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } } //Give the player hoofs, if the player already has hoofs STRIP FUR if (!isPurified && target.lowerBody.type != LowerBodyType.HOOVED && target.ears.type == EarType.COW) { if (Utils.Rand(3) == 0) { var oldData = target.lowerBody.AsReadOnlyData(); target.UpdateLowerBody(LowerBodyType.HOOVED); sb.Append(ChangedLowerBodyText(target, oldData)); if (++totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } } } //If the player's face is non-human, they gain a human face if (!isEnhanced && target.lowerBody.type == LowerBodyType.HOOVED && target.face.type != FaceType.HUMAN && Utils.Rand(4) == 0) { //Remove face before fur! var oldData = target.face.AsReadOnlyData(); target.RestoreFace(); sb.Append(RestoredFaceText(target, oldData)); if (++totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } } //isEnhanced get shitty fur var targetFur = new FurColor(HairFurColors.BLACK, HairFurColors.WHITE, FurMulticolorPattern.SPOTTED); if (isEnhanced && (!target.body.IsFurBodyType() || !target.body.mainEpidermis.fur.Equals(targetFur))) { var oldData = target.body.AsReadOnlyData(); if (target.body.type == BodyType.SIMPLE_FUR) { target.body.ChangeMainFur(targetFur); } else { target.UpdateBody(BodyType.SIMPLE_FUR, targetFur); } if (!oldData.IsFurBodyType()) { sb.Append(ChangedBodyText(target, oldData)); } else { sb.Append(ChandedFurToSpots(target, oldData)); } if (++totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } } //if isEnhanced to probova give a shitty cow face else if (isEnhanced && target.face.type != FaceType.COW_MINOTAUR) { var oldData = target.face.AsReadOnlyData(); target.UpdateFace(FaceType.COW_MINOTAUR); sb.Append(ChangedFaceText(target, oldData)); if (++totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } } //Give the player bovine horns, or increase their size, same as the minotaur //New horns or expanding mino horns if (!isPurified && Utils.Rand(3) == 0) { var oldHorns = target.horns.AsReadOnlyData(); if (target.horns.type != HornType.BOVINE) { target.UpdateHorns(HornType.BOVINE); sb.Append(ChangedHornsText(target, oldHorns)); if (++totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } } else if (target.horns.type == HornType.BOVINE && target.horns.CanStrengthen && target.horns.significantHornSize < 5) { target.horns.StrengthenTransform(); sb.Append(MadeHornsBigger(target, oldHorns)); if (++totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } } } //Increase the size of the player's hips, if they are not already childbearing or larger if (Utils.Rand(2) == 0 && target.hips.size < 15) { if (isPurified && target.hips.size < 8 || !isPurified) { var oldHips = target.hips.AsReadOnlyData(); if (target.build.GrowHips((byte)(1 + Utils.Rand(4))) > 0) { sb.Append(WidenedHipsText(target, oldHips)); if (++totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } } } } // Remove gills if (Utils.Rand(4) == 0 && target.gills.type != GillType.NONE) { var oldData = target.gills.AsReadOnlyData(); target.RestoreGills(); sb.Append(RestoredGillsText(target, oldData)); if (++totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } } //Increase the size of the player's ass (less likely then hips), if it is not already somewhat big if (Utils.Rand(2) == 0 && target.butt.size < 8 || (!isPurified && target.butt.size < 13)) { var oldButt = target.butt.AsReadOnlyData(); if (target.butt.GrowButt((byte)(1 + Utils.Rand(2))) > 0) { sb.Append(GrewButtText(target, oldButt)); if (++totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } } } //Nipples Turn Back: if (target.genitals.hasBlackNipples && Utils.Rand(3) == 0) { target.genitals.SetBlackNipples(false); sb.Append(RemovedBlackNippleText(target)); if (++totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } } //Debugcunt if (target.hasVagina && target.vaginas.Any(x => x.type != VaginaType.defaultValue) && Utils.Rand(3) == 0) { var oldCollection = target.genitals.allVaginas.AsReadOnlyData(); target.vaginas.ForEach(x => target.genitals.RestoreVagina(x)); sb.Append(RestoreAllVaginasText(target, oldCollection)); if (++totalChanges >= changeCount) { return(FinalizeTransformation(target, sb, totalChanges)); } } //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(FinalizeTransformation(target, sb, changeCount - totalChanges)); }
protected Animal(FurColor furColor, string name) { FurColor = furColor; Name = name; }
internal static FurColor GetValidFurColor(FurColor overrideColor, FurColor primary, HairFurColors activeHairColor, FurColor fallback) { return(GetValidFurColor(overrideColor, primary, null, activeHairColor, fallback)); }
internal virtual FurColor ParseFurColor(FurColor current, in BodyData data)
public Monkey(string name, FurColor furColor, int age) // конструктор { this.furColor = furColor; // this Казва да се използват нещата подадени в този конструктор this.name = name; this.age = age; }
public Mouse(int age, string name, FurColor furColor, int tailLength) : base(age, name) { this.FurColor = furColor; this.TailLength = tailLength; }
public TomCat(string name, int age, FurColor furColor) : base(name, age, AnimalsSex.male, furColor) { }
public Dog(int age, string name, FurColor furColor) : base(age, name) { this.FurColor = furColor; this.DogTag = "my name is " + name; }
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 }); 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); //use: //stat changes: //lose height + gain speed (42" height floor, no speed ceiling but no speed changes without height change) if (target.build.heightInInches >= 45 && Utils.Rand(3) == 0) { target.IncreaseSpeed(); target.build.DecreaseHeight(); if (target.build.heightInInches > 60) { target.build.DecreaseHeight(); } if (target.build.heightInInches > 70) { target.build.DecreaseHeight(); } if (target.build.heightInInches > 80) { target.build.DecreaseHeight(); } if (target.build.heightInInches > 90) { target.build.DecreaseHeight(2); } if (target.build.heightInInches > 100) { target.build.DecreaseHeight(2); } if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //lose tough if (target.relativeToughness > 50 && Utils.Rand(3) == 0) { target.ChangeToughness(-1); if (target.relativeToughness >= 75) { target.ChangeToughness(-1); } if (target.relativeToughness >= 90) { target.ChangeToughness(-1); } } //SEXYYYYYYYYYYY //vag-anal capacity up for non-goo (available after PC < 5 ft; capacity ceiling reasonable but not horse-like or gooey) if (target.build.heightInInches < 60 && (target.genitals.standardBonusAnalCapacity < 100 || (target.genitals.standardBonusVaginalCapacity < 100 && target.hasVagina)) && Utils.Rand(3) == 0) { //adds some lust target.ChangeLust(10 + target.sensitivity / 5); if (target.genitals.standardBonusVaginalCapacity < 100 && target.hasVagina) { target.genitals.IncreaseBonusVaginalCapacity(5); } else { target.genitals.IncreaseBonusAnalCapacity(5); } if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //fem fertility up and heat (suppress if pregnant) //not already in heat (add heat and lust) if (!target.HasTimedEffect <Heat>() || target.GetTimedEffectData <Heat>().totalAddedLibido < 30 && Utils.Rand(2) == 0) { bool intensified = target.HasTimedEffect <Heat>(); if (target.GoIntoHeat()) { if (intensified) { ////[(no mino cum in inventory)] //if (!target.hasItem(consumables.MINOCUM)) //{ //} ////(mino cum in inventory and non-horse, 100 lust) //else //{ // //(consumes item, increment addiction/output addict message, small chance of mino preg, reduce lust)]"); // target.minoCumAddiction(5); // target.knockUp(PregnancyStore.PREGNANCY_MINOTAUR, PregnancyStore.INCUBATION_MINOTAUR, 175); // ConsumableLib consumables = game.consumables; // target.consumeItem(consumables.MINOCUM); //} #warning Not Implemented: consume minotaur cum, or if you don't have it, go f**k a minotaur to get it, and immediately consume it. do whatever sex is required for getting it. } else { // Also make a permanent nudge. target.fertility.IncreaseFertility(); } 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)); } } //bodypart changes: //gain ears if (target.ears.type != EarType.MOUSE && Utils.Rand(4) == 0) { EarData oldData = target.ears.AsReadOnlyData(); target.UpdateEars(EarType.MOUSE); sb.Append(UpdateEarsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //gain tail //from no tail if (target.ears.type == EarType.MOUSE && target.tail.type != TailType.MOUSE && Utils.Rand(4) == 0) { //from other tail TailData oldData = target.tail.AsReadOnlyData(); target.UpdateTail(TailType.MOUSE); sb.Append(UpdateTailText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //get teeth - from human, bunny, coonmask, or other humanoid teeth faces if (target.ears.type == EarType.MOUSE && target.face.isHumanoid && target.face.type != FaceType.MOUSE && Utils.Rand(4) == 0) { FaceData oldData = target.face.AsReadOnlyData(); target.UpdateFace(FaceType.MOUSE); sb.Append(UpdateFaceText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //get mouse muzzle from mouse teeth or other muzzle if (target.body.IsFurBodyType() && target.face.hasMuzzle && Utils.Rand(4) == 0) { target.UpdateFace(FaceType.MOUSE); target.face.StrengthenFacialMorph(); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //get fur if (!target.body.IsFurBodyType() || (!target.body.mainEpidermis.fur.IsIdenticalTo(HairFurColors.BROWN) && !target.body.mainEpidermis.fur.IsIdenticalTo(HairFurColors.WHITE)) && Utils.Rand(4) == 0) { FurColor color; int temp = Utils.Rand(10); if (temp < 8) { color = new FurColor(HairFurColors.BROWN); } else { color = new FurColor(HairFurColors.WHITE); } BodyData oldData = target.body.AsReadOnlyData(); target.UpdateBody(BodyType.SIMPLE_FUR, color); sb.Append(UpdateBodyText(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)); }
public Bear(FurColor furColor, string name, int weight) : base(furColor, name) { Weight = weight; }
static void Main(string[] args) { //doing this cause of static main var animals = new AnimalsForSale(); var listOfAnimals = animals.GetAnimals(); //======================================= Console.WriteLine("What is the name of the animal? "); var resName = Console.ReadLine(); Console.WriteLine("What color is the fur? (black/brown/white) "); var resFur = Console.ReadLine().ToLower(); FurColor furColor = FurColor.Unspecified; switch (resFur) { case "black": furColor = FurColor.Black; break; case "brown": furColor = FurColor.Brown; break; case "white": furColor = FurColor.White; break; default: furColor = FurColor.Unspecified; break; } Console.WriteLine("What is the animal? (bear/lion)"); var resType = Console.ReadLine().ToLower(); if (resType == "bear") { Console.WriteLine("How much does the bear weigh? "); var resWeightString = Console.ReadLine(); var resWeight = Convert.ToInt32(resWeightString); var animal = new Bear(furColor, resName, resWeight); var forSale = new ForSale(animal); listOfAnimals.Add(forSale); Console.WriteLine("The cost of the animal is: " + animals.CostOfAnimal); } else if (resType == "lion") { Console.WriteLine("How many cubs does the Lion have? "); var resCubsString = Console.ReadLine(); var resCubs = Convert.ToInt32(resCubsString); var animal = new Lion(furColor, resName, resCubs); var forSale = new ForSale(animal); listOfAnimals.Add(forSale); Console.WriteLine("The cost of the animal is: " + animals.CostOfAnimal); } }
public Kitten(string name, int age, FurColor furColor) : base(name, age, AnimalsSex.female, furColor) { }
public Lion(FurColor furColor, string name, int numberOfCubs) : base(furColor, name) { NumberOfCubs = numberOfCubs; }
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)); }
public Cats(string name, int age, AnimalsSex sex, FurColor furColor) : base(name, age, sex) { this.furColor = furColor; }
//Original credits: //since March 26, 2018 //@author Stadler76 // //Porter's note: Nearly all of the comments here are from the vanilla. comments from modification of code will be marked with <MODIFICATION> protected internal override string DoTransformation(Creature target, out bool isBadEnd) { isBadEnd = false; //<MODIFICATION NOTE> //potent tf has an initial count of 3. int changeCount = GenerateChangeCount(target, new int[] { 2, 2 }, enhanced ? 3 : 1); int remainingChanges = changeCount; StringBuilder sb = new StringBuilder(); sb.Append(InitialTransformationText(target)); if (target.face.type == FaceType.FOX && target.tail.type == TailType.FOX && target.ears.type == EarType.FOX && target.lowerBody.type == LowerBodyType.FOX && target.body.IsFurBodyType() && Utils.Rand(3) == 0 && target is IExtendedCreature extended && !extended.extendedData.resistsTFBadEnds) { if (!extended.extendedData.hasFoxWarning) { extended.extendedData.hasFoxWarning = true; } else { isBadEnd = true; return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //<MODIFICATION NOTE> //Free Changes. //[decrease Strength] (to some floor) // I figured 15 was fair, but you're in a better position to judge that than I am. if (Utils.Rand(3) == 0 && target.relativeStrength > 40) { if (target.relativeStrength > 90) { target.DecreaseStrength(4); } else if (target.relativeStrength > 80) { target.DecreaseStrength(3); } else if (target.relativeStrength > 60) { target.DecreaseStrength(2); } else { target.DecreaseStrength(); } } //[decrease Toughness] (to some floor) // 20 or so was my thought here if (Utils.Rand(3) == 0 && target.relativeToughness > 30) { if (target.relativeToughness > 90) { target.DecreaseToughness(4); } else if (target.relativeToughness > 80) { target.DecreaseToughness(3); } else if (target.relativeToughness > 60) { target.DecreaseToughness(2); } else { target.DecreaseToughness(); } } //[increase Intelligence, Libido and Sensitivity] if (Utils.Rand(3) == 0 && (target.relativeLibido < 80 || target.relativeSensitivity < 80 || target.relativeIntelligence < 80)) { if (target.relativeIntelligence < 80) { target.IncreaseIntelligence(4); } if (target.relativeLibido < 80) { target.IncreaseLibido(1); } if (target.relativeSensitivity < 80) { target.IncreaseSensitivity(1); } //gain small lust also target.IncreaseLust(10); } //Modification Note: move this free change up here, where it makes the most sense. if (target.build.muscleTone > 40 && Utils.Rand(2) == 0) { target.build.DecreaseMuscleTone(4); } if (!Species.FOX.AvailableHairColors.Contains(target.hair.hairColor) && !Species.KITSUNE.elderKitsuneHairColors.Contains(target.hair.hairColor) && !Species.KITSUNE.kitsuneHairColors.Contains(target.hair.hairColor) && Utils.Rand(4) == 0) { HairFurColors targetColor; if (target.tail.type == TailType.FOX && target.tail.tailCount > 1) { if (target.tail.tailCount < 9) { targetColor = Utils.RandomChoice(Species.KITSUNE.kitsuneHairColors); } targetColor = Utils.RandomChoice(Species.KITSUNE.elderKitsuneHairColors); } else { targetColor = Utils.RandomChoice(Species.FOX.AvailableHairColors); } } //this will handle the edge case where the change count starts out as 0. if (remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } //<MODIFICATION NOTE> //Transformation Changes. //if (--remainingChanges <= 0) return ApplyChangesAndReturn(target, sb, changeCount - remainingChanges); //[Adjust hips toward 10 – wide/curvy/flared] if (Utils.Rand(3) == 0 && target.hips.size != 10) { //from narrow to wide if (target.hips.size < 7) { target.hips.GrowHips(2); } else if (target.hips.size < 10) { target.hips.GrowHips(); } //from wide to narrower else if (target.hips.size > 13) { target.hips.ShrinkHips(2); } else { target.hips.ShrinkHips(); } if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //[Remove tentacle hair] //required if the hair length change below is triggered if (target.hair.type == HairType.ANEMONE && Utils.Rand(3) == 0) { //-insert anemone hair removal into them under whatever criteria you like, though hair removal should precede abdomen growth; HairData oldData = target.hair.AsReadOnlyData(); target.RestoreHair(); sb.Append(RestoredHairText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //[Adjust hair length toward range of 16-26 – very long to ass-length] if (target.hair.type == HairType.ANEMONE && (target.hair.length > 26 || target.hair.length < 16) && target.hair.canGrowNaturally && Utils.Rand(4) == 0) { if (target.hair.length < 16) { target.hair.GrowHair(1 + Utils.Rand(4)); } else { target.hair.ShortenHair(1 + Utils.Rand(4)); } if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (Utils.Rand(10) == 0) { //MOD NOTE: Don't remove ?. operator. if ((target as CombatCreature)?.RecoverFatigue(10) > 0) { if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //dog cocks! //MOD NOTE: consider adding back in fox cocks and using them? they could literally just be dog cocks but with a slightly different text descriptions. //MOD NOTE: this is a linq check that sees if any available cocks aren't a dog c**k. it's actually faster than count of type, because it stops as soon as it hits //a c**k that isn't a dog, instead of checking all of them. Also, this function finds all non-dog cocks and converts one at random. if (Utils.Rand(3) == 0 && target.hasCock && target.cocks.Any(x => x.type != CockType.DOG)) { C**k toChange = Utils.RandomChoice(target.cocks.Where(x => x.type != CockType.DOG).ToArray()); if (toChange.type == CockType.HUMAN) { toChange.IncreaseThickness(.3); target.DeltaCreatureStats(sens: 10, lus: 5); } //Horse else if (toChange.type == CockType.HORSE) { //Tweak length/thickness. double deltaLength; if (toChange.length > 6) { deltaLength = -2; } else { deltaLength = -.5; } toChange.SetLengthAndGirth(toChange.length + deltaLength, toChange.girth + 0.5); target.DeltaCreatureStats(sens: 4, lus: 5); } else { target.DeltaCreatureStats(sens: 4, lus: 10); } target.genitals.UpdateCock(toChange, CockType.DOG); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Cum Multiplier Xform if (target.genitals.totalCum < 5000 && Utils.Rand(3) == 0 && target.hasCock) { int temp = 2 + Utils.Rand(4); //Lots of cum raises cum multiplier cap to 2 instead of 1.5 if (target.HasPerk <MessyOrgasms>()) { temp += Utils.Rand(10); } //MOD NOTE: not sure if cum calculations changed, (i think they have) and if so, that's a lot of multiplier gain holy shit. meh. whatever. target.genitals.IncreaseCumMultiplier(temp); //Flavor text if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (target.balls.count > 0 && target.balls.size > 4 && Utils.Rand(3) == 0) { int targetSize; //currently above max, but whatever, that'll probably get raised anyway. if (target.balls.size > 50) { targetSize = target.balls.size / 5; } else if (target.balls.size > 10) { targetSize = target.balls.size / 2; } else { targetSize = target.balls.size - 1; } //allow perks to work. target.balls.ShrinkBalls((byte)(target.balls.size - targetSize)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Sprouting more! if (enhanced && target.breasts.Count < 4 && target.breasts[target.breasts.Count - 1].cupSize > CupSize.A) { target.genitals.AddBreastRow(target.breasts[target.breasts.Count - 1].cupSize); target.DeltaCreatureStats(sens: 2, lus: 30); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Find out if t**s are eligible for evening //MOD NOTE: there's an easier way - just run the normalize breasts. it'll return true if it changed anything. since we display the results of the old //breast data anyway, this is way simpler. Also, normalize breasts now returns a bool. woo! //MOD NOTE 2: Fox rules here seem to use the same size as previous. if they want to function under anthro rules (size is in decreasing order, but otherwise //roughly even) you can use AnthropomorphizeBreasts() instead. see canine tfs for an example. if (target.genitals.NormalizeBreasts()) { if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //HEAT! if (!target.HasTimedEffect <Heat>() || target.GetTimedEffectData <Heat>().totalAddedLibido < 30 && Utils.Rand(6) == 0) { target.GoIntoHeat(); 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) { if (target.womb.ClearOviposition()) { if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //[Grow Fur] //FOURTH //MOD NOTE: Body has been reworked since this was written, we'll allow kitsune's to remain unchanged, but all others need to be full fur after this. if ((enhanced || target.lowerBody.type == LowerBodyType.FOX) && target.body.type != BodyType.KITSUNE && !target.body.IsFurBodyType() && Utils.Rand(4) == 0) { BodyData oldBodyData = target.body.AsReadOnlyData(); if (Species.KITSUNE.Score(target) >= 4) { FurColor[] colorChoices; if (Species.KITSUNE.elderKitsuneFurColors.Any(x => x.IsIdenticalTo(target.hair.hairColor)) || Species.KITSUNE.allKitsuneColors.Any(y => y.IsIdenticalTo(target.hair.hairColor))) { colorChoices = new FurColor[] { new FurColor(target.hair.hairColor) }; } else if (target.tail.type == TailType.FOX && target.tail.tailCount == TailType.FOX.maxTailCount) { colorChoices = Species.KITSUNE.allKitsuneColors; } else { colorChoices = Species.KITSUNE.elderKitsuneFurColors; } target.UpdateBody(BodyType.UNDERBODY_FUR, Utils.RandomChoice(colorChoices)); } else { Species.FOX.GetRandomFurColors(out FurColor primary, out FurColor underbody); target.UpdateBody(BodyType.UNDERBODY_FUR, primary, underbody); } //should always be true, but whatever. if (oldBodyData.type != target.body.type) { remainingChanges--; if (remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } } //[Grow Fox Legs] //THIRD if ((enhanced || target.ears.type == EarType.FOX) && target.lowerBody.type != LowerBodyType.FOX && Utils.Rand(5) == 0) { LowerBodyData oldData = target.lowerBody.AsReadOnlyData(); target.UpdateLowerBody(LowerBodyType.FOX); sb.Append(UpdateLowerBodyText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Grow Fox Ears] //SECOND if ((enhanced || target.tail.type == TailType.FOX) && target.ears.type != EarType.FOX && Utils.Rand(4) == 0) { EarData oldData = target.ears.AsReadOnlyData(); target.UpdateEars(EarType.FOX); sb.Append(UpdateEarsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //[Grow Fox Tail](fairly common) //FIRST if (target.tail.type != TailType.FOX && Utils.Rand(4) == 0) { TailData oldData = target.tail.AsReadOnlyData(); target.UpdateTail(TailType.FOX); sb.Append(UpdateTailText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //[Grow Fox Face] //LAST - muzzlygoodness //should work from any face, including other muzzles if (target.body.HasAny(EpidermisType.FUR) && target.face.type != FaceType.FOX && Utils.Rand(5) == 0) { FaceData oldData = target.face.AsReadOnlyData(); target.UpdateFace(FaceType.FOX); sb.Append(UpdateFaceText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } //Arms if (target.arms.type != ArmType.FOX && target.body.HasAny(EpidermisType.FUR) && target.tail.type == TailType.FOX && target.lowerBody.type == LowerBodyType.FOX && Utils.Rand(4) == 0) { ArmData oldData = target.arms.AsReadOnlyData(); target.UpdateArms(ArmType.FOX); sb.Append(UpdateArmsText(target, oldData)); if (--remainingChanges <= 0) { return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); } } if (remainingChanges == changeCount && !(target is null)) { (target as CombatCreature)?.RecoverFatigue(5); } //<MODIFICATION NOTE> //Fall through, cleanup and return. return(ApplyChangesAndReturn(target, sb, changeCount - remainingChanges)); }