/// <summary> /// Update the mesh of the balls and set the visibility /// </summary> internal static void ReloadCharacterBalls(ChaControl chaControl, BallsData ballsData, bool showBalls) { #if KK if (chaControl.hiPoly == false) { return; } #endif if (ballsData != null) { GameObject balls = CommonLib.LoadAsset <GameObject>(ballsData.File, ballsData.Asset, true); foreach (var mesh in balls.gameObject.GetComponentsInChildren <SkinnedMeshRenderer>(true)) { if (BallsParts.Contains(mesh.name)) { UpdateMeshRenderer(chaControl, mesh, chaControl.objBody.GetComponentsInChildren <SkinnedMeshRenderer>(true).FirstOrDefault(x => x.name == mesh.name), true); } } Destroy(balls); } SkinnedMeshRenderer ballsSMR = chaControl?.objBody?.GetComponentsInChildren <SkinnedMeshRenderer>(true).FirstOrDefault(x => x?.name == "o_dan_f"); if (ballsSMR != null) { ballsSMR.gameObject.GetComponent <Renderer>().enabled = showBalls; } }
protected bool ChangeCock(Creature target, StringBuilder sb) { if (HyperHappySettings.isEnabled) { return(false); } //find the largest c**k. shrink it. if it gets small enough to remove it, do so. if it's the only c**k the creature has, grow a v****a in its place. if (target.hasCock) { GenitalsData oldGenitals = target.genitals.AsReadOnlyData(); C**k largest = target.genitals.LongestCock(); if (largest.DecreaseLengthAndCheckIfNeedsRemoval(Utils.Rand(3) + 1)) { target.genitals.RemoveCock(largest); if (!target.hasCock && !target.hasVagina) { target.AddVagina(.25); target.IncreaseCorruption(); BallsData oldBalls = target.balls.AsReadOnlyData(); target.balls.RemoveAllBalls(); } } sb.Append(CockChangedText(target, oldGenitals, largest.cockIndex)); return(true); } return(false); }
private static void SetLineVisibility(ChaControl chaControl, BallsData ballsData) { if (ballsData == null) { return; } foreach (ColorMatchPart colorMatchPart in ballsData.ColorMatchList) { SetLineVisibility(chaControl, colorMatchPart); } }
private static void SetSkinGloss(ChaControl chaControl, BallsData ballsData) { if (ballsData == null) { return; } foreach (ColorMatchPart colorMatchPart in ballsData.ColorMatchList) { SetSkinGloss(chaControl, colorMatchPart); } }
public override void ApplyData(BallsData data, bool force = false) { for (int i = 0; i < size; i++) { transforms[i].localPosition = data.positions[i]; materials[i].SetVector(positionId, data.positions[i]); } for (int i = 0; i < size; i++) { materials[i].SetVector(appearanceId, data.ballsAppearance[i]); } for (int i = 0; i < size; i++) { Vector4 thisPosition = data.positions[i]; thisPosition.w = 0f; Vector4 n1 = data.positions[data._neighborIndexes[i, 0]] - thisPosition; Vector4 n2 = data.positions[data._neighborIndexes[i, 1]] - thisPosition; Vector4 n3 = data.positions[data._neighborIndexes[i, 2]] - thisPosition; Vector4 n4 = data.positions[data._neighborIndexes[i, 3]] - thisPosition; Vector4 n5 = data.positions[data._neighborIndexes[i, 4]] - thisPosition; Vector4 n6 = data.positions[data._neighborIndexes[i, 5]] - thisPosition; if (i == 0) { Debug.LogFormat("{0} {1} {2}", (Vector3)n1, ((Vector3)n1).magnitude, n1.w); } materials[i].SetVector(neighborId1, n1); materials[i].SetVector(neighborId2, n2); materials[i].SetVector(neighborId3, n3); materials[i].SetVector(neighborId4, n4); materials[i].SetVector(neighborId5, n5); materials[i].SetVector(neighborId6, n6); } for (int i = 0; i < size; i++) { ApplyCachedVariables(materials[i]); } /* * if (data.highlightColorsDirty || force) { * material.SetVectorArray(highlightColorsArrayId, data.highlightColors); * data.highlightColorsDirty = false; * } * */ }
private static string EnlargedBallsText(Creature target, BallsData oldData) { if (oldData.count == 1) { return(GlobalStrings.NewParagraph() + "A wave of heat reaches your groin, quickly followed by a bit of discomfort. A sudden weight develops in your groin, alongside your uniball. " + "A quick examination confirms the obvious - your uniball is now a pair of regular balls."); } else if (oldData.size <= 2) { return(GlobalStrings.NewParagraph() + "A flash of warmth passes through you, finally settling in your groin, which feels heavier. You pause to examine the changes and " + "your roving fingers discover your " + target.balls.ShortDescription() + " have grown larger than a human's."); } else { return(GlobalStrings.NewParagraph() + "A sudden onset of heat envelops your groin, focusing on your " + target.balls.SackDescription() + ". Walking becomes difficult as you discover your " + target.balls.ShortDescription() + " have enlarged further."); } }
public void Init(int size, BallsRendererSettings _settings = null) { settings = (_settings == null) ? BallsRendererSettings.Batch : _settings; bucketData = new BallsData(size); balls = new BallInfo[size]; for (int i = 0; i < size; i++) { balls[i] = new BallInfo(bucketData, i); } // Switch-case settings? if (settings.mode == Mode.BATCH) { bucket = new BallsBatchBucket(settings, this.transform); } else if (settings.mode == Mode.SINGLE) { bucket = new BallsListBucket(settings, size, this.transform); } isInit = true; }
private void ApplyBatchData(BallsData data, bool force = false) { if (data.positionsDirty || force) { material.SetVectorArray(positionsArrayId, data.positions); data.positionsDirty = false; } if (data.ballsAppearanceDirty || force) { material.SetVectorArray(appearanceId, data.ballsAppearance); data.ballsAppearanceDirty = false; } if (data._neighborsDirty || force) { for (int i = 0; i < data.size; i++) { data._atomsNeighbors1[i] = new Vector4(data._neighborIndexes[i, 0], data._neighborIndexes[i, 1], data._neighborIndexes[i, 2], data._neighborIndexes[i, 3]) + INDEX_OFFSET * Vector4.one; data._atomsNeighbors2[i].x = data._neighborIndexes[i, 4] + INDEX_OFFSET; data._atomsNeighbors2[i].y = data._neighborIndexes[i, 5] + INDEX_OFFSET; } material.SetVectorArray(neighborsArrayId1, data._atomsNeighbors1); material.SetVectorArray(neighborsArrayId2, data._atomsNeighbors2); data._neighborsDirty = false; } if (data.highlightColorsDirty || force) { material.SetVectorArray(highlightColorsArrayId, data.highlightColors); data.highlightColorsDirty = false; } ApplyCachedVariables(material); }
/// <summary> /// Set the skin line visibility for every color matching object configured in the manifest.xml /// </summary> internal static void SetLineVisibility(ChaControl chaControl, BodyData bodyData, PenisData penisData, BallsData ballsData) { SetLineVisibility(chaControl, bodyData); SetLineVisibility(chaControl, penisData); SetLineVisibility(chaControl, ballsData); }
protected abstract string EnlargedBallsText(Creature target, BallsData oldData);
internal static IEnumerator ReloadCharacterUncensor(ChaControl chaControl, BodyData bodyData, PenisData penisData, bool penisVisible, BallsData ballsData, bool ballsVisible) { while (chaControl.objBody == null) { yield return(null); } if (ExType(chaControl) == 0) //exType of 1 indicates Janitor, don't modify his body. { ReloadCharacterBody(chaControl, bodyData); } ReloadCharacterPenis(chaControl, penisData, penisVisible); ReloadCharacterBalls(chaControl, ballsData, ballsVisible); UpdateSkin(chaControl, bodyData); if (ExType(chaControl) == 0) { chaControl.updateBustSize = true; Traverse.Create(chaControl).Method("UpdateSiru", new object[] { true }).GetValue(); SetChestNormals(chaControl, bodyData); chaControl.customMatBody.SetTexture(ChaShader._AlphaMask, Traverse.Create(chaControl).Property("texBodyAlphaMask").GetValue() as Texture); Traverse.Create(chaControl).Property("updateAlphaMask").SetValue(true); } }
//removed last/only c**k, obtained a v****a instead. protected override string MadeFemale(Creature target, CockData preChange, BallsData oldBalls) { bool removedBalls = oldBalls.hasBalls; StringBuilder sb = new StringBuilder(); sb.Append("Your " + preChange.LongDescription() + " suddenly starts tingling. It's a familiar feeling, similar to an o****m. " + "However, this one seems to start from the top down, instead of gushing up from your loins. You spend a few seconds frozen to the odd sensation, " + "when it suddenly feels as though your own body starts sucking on the base of your shaft. Almost instantly, your c**k sinks " + "into your crotch with a wet slurp. The tip gets stuck on the front of your body on the way down, but your glans soon loses all volume to turn " + "into a shiny new c**t."); if (target.balls.hasBalls) { sb.Append(" At the same time, your " + oldBalls.ShortDescription() + " fall victim to the same sensation; eagerly swallowed whole by your crotch."); } sb.Append(" Curious, you touch around down there, to find you don't have any exterior organs left. All of it got swallowed into the gash you " + "now have running between two fleshy folds, like sensitive lips. It suddenly occurs to you; <b>you now have a v****a!</b>"); return(sb.ToString()); }
/// <summary> /// Read all the manifest.xml files and generate a dictionary of uncensors to be used in config manager dropdown /// </summary> private static void PopulateUncensorLists() { BodyDictionary.Clear(); BodyConfigListFull.Clear(); PenisDictionary.Clear(); PenisConfigListFull.Clear(); BallsDictionary.Clear(); BallsConfigListFull.Clear(); //Add the default body options BodyConfigListFull["Random"] = "Random"; #if KK || EC BodyData DefaultMale = new BodyData(0, DefaultBodyMaleGUID, "Default Body M"); BodyDictionary[DefaultMale.BodyGUID] = DefaultMale; BodyConfigListFull[$"[{(DefaultMale.Sex == 0 ? "Male" : "Female")}] {DefaultMale.DisplayName}"] = DefaultMale.BodyGUID; #endif BodyData DefaultFemale = new BodyData(1, DefaultBodyFemaleGUID, "Default Body F"); BodyDictionary[DefaultFemale.BodyGUID] = DefaultFemale; BodyConfigListFull[$"[{(DefaultFemale.Sex == 0 ? "Male" : "Female")}] {DefaultFemale.DisplayName}"] = DefaultFemale.BodyGUID; //Add the default penis options PenisConfigListFull["Random"] = "Random"; PenisData DefaultPenis = new PenisData(DefaultPenisGUID, "Mosaic Penis"); PenisDictionary[DefaultPenis.PenisGUID] = DefaultPenis; PenisConfigListFull[DefaultPenis.DisplayName] = DefaultPenis.PenisGUID; //Add the default balls options BallsConfigListFull["Random"] = "Random"; BallsData DefaultBalls = new BallsData(DefaultBallsGUID, "Mosaic Balls"); BallsDictionary[DefaultBalls.BallsGUID] = DefaultBalls; BallsConfigListFull[DefaultBalls.DisplayName] = DefaultBalls.BallsGUID; var loadedManifests = Sideloader.Sideloader.Manifests; foreach (var manifest in loadedManifests.Values) { XDocument manifestDocument = manifest.manifestDocument; XElement uncensorSelectorElement = manifestDocument?.Root?.Element(PluginNameInternal); if (uncensorSelectorElement != null && uncensorSelectorElement.HasElements) { foreach (XElement uncensorElement in uncensorSelectorElement.Elements("body")) { BodyData bodyData = new BodyData(uncensorElement); if (bodyData.BodyGUID == null) { Logger.LogWarning("Body failed to load due to missing GUID."); continue; } if (bodyData.DisplayName == null) { Logger.LogWarning("Body failed to load due to missing display name."); continue; } if (bodyData.OOBase == Defaults.OOBase) { Logger.LogWarning("Body was not loaded because oo_base is the default."); continue; } BodyDictionary[bodyData.BodyGUID] = bodyData; BodyConfigListFull[$"[{(bodyData.Sex == 0 ? "Male" : "Female")}] {bodyData.DisplayName}"] = bodyData.BodyGUID; foreach (var part in bodyData.AdditionalParts) { AllAdditionalParts.Add(part); } } foreach (XElement uncensorElement in uncensorSelectorElement.Elements("penis")) { PenisData penisData = new PenisData(uncensorElement); if (penisData.PenisGUID == null) { Logger.LogWarning("Penis failed to load due to missing GUID."); continue; } if (penisData.DisplayName == null) { Logger.LogWarning("Penis failed to load due to missing display name."); continue; } if (penisData.File == null) { Logger.LogWarning("Penis failed to load due to missing file."); continue; } if (penisData.Asset == null) { Logger.LogWarning("Penis failed to load due to missing asset."); continue; } PenisDictionary[penisData.PenisGUID] = penisData; PenisConfigListFull[penisData.DisplayName] = penisData.PenisGUID; } foreach (XElement uncensorElement in uncensorSelectorElement.Elements("balls")) { BallsData ballsData = new BallsData(uncensorElement); if (ballsData.BallsGUID == null) { Logger.LogWarning("Balls failed to load due to missing GUID."); continue; } if (ballsData.DisplayName == null) { Logger.LogWarning("Balls failed to load due to missing display name."); continue; } if (ballsData.File == null) { Logger.LogWarning("Balls failed to load due to missing file."); continue; } if (ballsData.Asset == null) { Logger.LogWarning("Balls failed to load due to missing asset."); continue; } BallsDictionary[ballsData.BallsGUID] = ballsData; BallsConfigListFull[ballsData.DisplayName] = ballsData.BallsGUID; } foreach (XElement uncensorElement in uncensorSelectorElement.Elements("migration")) { MigrationData migrationData = new MigrationData(uncensorElement); if (migrationData.UncensorGUID == null) { Logger.LogWarning("Migration data failed to load due to missing Uncensor GUID."); continue; } if (migrationData.BodyGUID == null) { Logger.LogWarning("Migration data failed to load due to missing Body GUID."); continue; } MigrationDictionary[migrationData.UncensorGUID] = migrationData; } } } }
protected override string EnlargedBallsText(Creature target, BallsData oldData) => CaninePepperGeneric.EnlargedBallsText(target, oldData);
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 BallInfo(BallsData _data, int _index) { data = _data; index = _index; }
public abstract void ApplyData(BallsData data, bool force = false);
public override void ApplyData(BallsData data, bool force = false) { ApplyBatchData(data, force); }
/// <summary> /// Set the skin gloss for every color matching object configured in the manifest.xml /// </summary> internal static void SetSkinGloss(ChaControl chaControl, BodyData bodyData, PenisData penisData, BallsData ballsData) { SetSkinGloss(chaControl, bodyData); SetSkinGloss(chaControl, penisData); SetSkinGloss(chaControl, ballsData); }
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)); }
/// <summary> /// Read all the manifest.xml files and generate a dictionary of uncensors to be used in config manager dropdown /// </summary> private static void PopulateUncensorLists() { BodyDictionary.Clear(); BodyConfigListFull.Clear(); PenisDictionary.Clear(); PenisConfigListFull.Clear(); BallsDictionary.Clear(); BallsConfigListFull.Clear(); //Add the default body options BodyConfigListFull.Add("Random", "Random"); BodyData DefaultMale = new BodyData(0, "Default.Body.Male", "Default Body M"); BodyDictionary.Add(DefaultMale.BodyGUID, DefaultMale); BodyConfigListFull.Add($"[{(DefaultMale.Sex == 0 ? "Male" : "Female")}] {DefaultMale.DisplayName}", DefaultMale.BodyGUID); BodyData DefaultFemale = new BodyData(1, "Default.Body.Female", "Default Body F"); BodyDictionary.Add(DefaultFemale.BodyGUID, DefaultFemale); BodyConfigListFull.Add($"[{(DefaultFemale.Sex == 0 ? "Male" : "Female")}] {DefaultFemale.DisplayName}", DefaultFemale.BodyGUID); //Add the default penis options PenisConfigListFull.Add("Random", "Random"); PenisData DefaultPenis = new PenisData("Default.Penis", "Mosaic Penis"); PenisDictionary.Add(DefaultPenis.PenisGUID, DefaultPenis); PenisConfigListFull.Add(DefaultPenis.DisplayName, DefaultPenis.PenisGUID); //Add the default balls options BallsConfigListFull.Add("Random", "Random"); BallsData DefaultBalls = new BallsData("Default.Balls", "Mosaic Balls"); BallsDictionary.Add(DefaultBalls.BallsGUID, DefaultBalls); BallsConfigListFull.Add(DefaultBalls.DisplayName, DefaultBalls.BallsGUID); #if KK var loadedManifests = Sideloader.Sideloader.LoadedManifests; #elif EC var loadedManifests = Sideloader.LoadedManifests; #endif foreach (var manifest in loadedManifests) { XDocument manifestDocument = manifest.manifestDocument; XElement uncensorSelectorElement = manifestDocument?.Root?.Element(PluginNameInternal); if (uncensorSelectorElement != null && uncensorSelectorElement.HasElements) { foreach (XElement uncensorElement in uncensorSelectorElement.Elements("body")) { BodyData bodyData = new BodyData(uncensorElement); if (bodyData.BodyGUID == null) { Log(LogLevel.Warning, "Body failed to load due to missing GUID."); continue; } if (bodyData.DisplayName == null) { Log(LogLevel.Warning, "Body failed to load due to missing display name."); continue; } if (bodyData.OOBase == Defaults.OOBase) { Log(LogLevel.Warning, "Body was not loaded because oo_base is the default."); continue; } BodyDictionary.Add(bodyData.BodyGUID, bodyData); BodyConfigListFull.Add($"[{(bodyData.Sex == 0 ? "Male" : "Female")}] {bodyData.DisplayName}", bodyData.BodyGUID); foreach (var part in bodyData.AdditionalParts) { AllAdditionalParts.Add(part); } } foreach (XElement uncensorElement in uncensorSelectorElement.Elements("penis")) { PenisData penisData = new PenisData(uncensorElement); if (penisData.PenisGUID == null) { Log(LogLevel.Warning, "Penis failed to load due to missing GUID."); continue; } if (penisData.DisplayName == null) { Log(LogLevel.Warning, "Penis failed to load due to missing display name."); continue; } if (penisData.File == null) { Log(LogLevel.Warning, "Penis failed to load due to missing file."); continue; } if (penisData.Asset == null) { Log(LogLevel.Warning, "Penis failed to load due to missing asset."); continue; } PenisDictionary.Add(penisData.PenisGUID, penisData); PenisConfigListFull.Add(penisData.DisplayName, penisData.PenisGUID); } foreach (XElement uncensorElement in uncensorSelectorElement.Elements("balls")) { BallsData ballsData = new BallsData(uncensorElement); if (ballsData.BallsGUID == null) { Log(LogLevel.Warning, "Balls failed to load due to missing GUID."); continue; } if (ballsData.DisplayName == null) { Log(LogLevel.Warning, "Balls failed to load due to missing display name."); continue; } if (ballsData.File == null) { Log(LogLevel.Warning, "Balls failed to load due to missing file."); continue; } if (ballsData.Asset == null) { Log(LogLevel.Warning, "Balls failed to load due to missing asset."); continue; } BallsDictionary.Add(ballsData.BallsGUID, ballsData); BallsConfigListFull.Add(ballsData.DisplayName, ballsData.BallsGUID); } foreach (XElement uncensorElement in uncensorSelectorElement.Elements("migration")) { MigrationData migrationData = new MigrationData(uncensorElement); if (migrationData.UncensorGUID == null) { Log(LogLevel.Warning, "Migration data failed to load due to missing Uncensor GUID."); continue; } if (migrationData.BodyGUID == null) { Log(LogLevel.Warning, "Migration data failed to load due to missing Body GUID."); continue; } MigrationDictionary.Add(migrationData.UncensorGUID, migrationData); } } } }
protected abstract string MadeFemale(Creature target, CockData preChange, BallsData oldBalls);