code:
:: Transformation Widgets [widget]

<<widget "setupTransformationPiecesObject">>
	<<if $transformationParts is undefined>>
		<<set $transformationParts to{
			angel: {halo:"disabled", wings:"disabled"},
			fallenAngel: {halo:"disabled", wings:"disabled"},
			demon: {horns:"disabled", wings:"disabled", tail: "disabled"},
			cat: {ears:"disabled", tail:"disabled"},
			cow: {horns:"disabled", ears:"disabled", tail:"disabled"},
			wolf: {ears:"disabled", tail:"disabled", pubes:"disabled", pits:"disabled"},
			bird: {tail:"disabled", wings:"disabled", eyes:"disabled", malar:"disabled", plumage:"disabled", pubes:"disabled"},
			bunny: {ears: "disabled"}
		}>>
		<<if $specialTransform is 1>>
			<<if $angel gte 4>>
				<<set $transformationParts.angel.halo to "default">>
			<</if>>
			<<if $angel gte 6>>
				<<set $transformationParts.angel.wings to "default">>
			<</if>>
			<<if $fallenangel gte 2>>
				<<set $transformationParts.fallenAngel.halo to "default">>
				<<set $transformationParts.fallenAngel.wings to "default">>
			<</if>>
			<<if $demon gte 2>>
				<<set $transformationParts.demon.horns to "default">>
			<</if>>
			<<if $demon gte 4>>
				<<set $transformationParts.demon.tail to "default">>
			<</if>>
			<<if $demon gte 6>>
				<<set $transformationParts.demon.wings to "default">>
			<</if>>
		<</if>>
		<<if $physicalTransform is 1>>
			<<if $wolfgirl gte 4>>
				<<set $transformationParts.wolf.ears to "default">>
				<<set $transformationParts.wolf.pubes to "default">>
				<<set $transformationParts.wolf.pits to "default">>
			<</if>>
			<<if $wolfgirl gte 6>>
				<<set $transformationParts.wolf.tail to "default">>
			<</if>>
			<<if $cat gte 4>>
				<<set $transformationParts.cat.ears to "default">>
			<</if>>
			<<if $cat gte 6>>
				<<set $transformationParts.cat.tail to "default">>
			<</if>>
			<<if $bunny gte 4>>
				<<set $transformationParts.bunny.ears to "default">>
			<</if>>
			<<if $cow gte 2>>
				<<set $transformationParts.cow.horns to "default">>
			<</if>>
			<<if $cow gte 4>>
				<<set $transformationParts.cow.ears to "default">>
			<</if>>
			<<if $cow gte 6>>
				<<set $transformationParts.cow.tail to "default">>
			<</if>>
		<</if>>
	<</if>>
	<<if $transformationParts.fallenAngel.halo is 1>>
		<<set $transformationParts.fallenAngel.halo to "default">>
		<<set $transformationParts.fallenAngel.wings to "default">>
	<</if>>
	<<if $transformationParts.demon.horns is 1>>
		<<set $transformationParts.demon.horns to "default">>
		<<set $transformationParts.demon.tail to "default">>
		<<set $transformationParts.demon.wings to "default">>
	<</if>>
	<<if $angel lt 4>>
		<<set $transformationParts.angel.halo to "disabled">>
	<</if>>
	<<if $angel lt 6>>
		<<set $transformationParts.angel.wings to "disabled">>
	<</if>>
	<<if $fallenangel is 1>>
		<<set $transformationParts.fallenAngel.halo to "disabled">>
		<<set $transformationParts.fallenAngel.wings to "disabled">>
	<</if>>
	<<if $transformationParts.wolf.cheeks is undefined>>
		<<if $wolfgirl gte 6>>
			<<set $transformationParts.wolf.cheeks to "hidden">>
		<<else>>
			<<set $transformationParts.wolf.cheeks to "disabled">>
		<</if>>
	<</if>>
	<<if $transformationParts.bird is undefined>>
		<<set $transformationParts.bird to {tail:"disabled", wings:"disabled", eyes:"disabled", malar:"disabled", plumage:"disabled"}>>
	<</if>>
	<<if $transformationParts.bird.pubes is undefined>>
		<<if $harpy gte 6>>
			<<set $transformationParts.bird.pubes to "hidden">>
		<<else>>
			<<set $transformationParts.bird.pubes to "disabled">>
		<</if>>
	<</if>>
<</widget>>

<<widget "transformationStateUpdate">>

<<if $wolfbuild gte 1 and $worn.neck.name isnot "spiked collar" and !_wolfseal>>
	<<transform wolf -1>>
<</if>>

<<if $catbuild gte 1 and $worn.neck.name isnot "cat bell collar" and !_catseal>>
	<<transform cat -1>>
<</if>>

<<if $cowbuild gte 1 and $worn.neck.name isnot "cow bell" and !_cowseal>>
	<<transform cow -1>>
<</if>>

<<if $birdbuild gte 1 and $worn.head.name isnot "feathered hair clip" and !_birdseal>>
	<<transform bird -1>>
<</if>>

<<if $bunnybuild gte 1 and $worn.neck.name isnot "bunnycollar" and !_bunnyseal>>
	<<transform bunny -1>>
<</if>>

<<if $wolfgirl gte 6>>
	<<set $submissive -= 20>>
<</if>>

<<if $bunny gte 6>>
	<<set $submissive += 20>>
<</if>>

<<transformationAlteration>>

<<if $cat gt 0 or $wolfgirl gt 0 or $cow gt 0 or $harpy gt 0>>
	<<set $physicalTransform to 1>>
<<else>>
	<<set $physicalTransform to 0>>
<</if>>
<<if $physicalTransform is 1 or $specialTransform is 1>>
	<<if $harpy gte 6 and ($angel gte 6 or $fallenangel gte 2 or $demon gte 6)>>
		<<if $transformationParts.bird.wings is "hidden" and ($transformationParts.demon.wings is "hidden" or $transformationParts.angel.wings is "hidden" or $transformationParts.fallenAngel.wings is "hidden")>>
		<<else>>
			<<set _excludeWings to true>>
		<</if>>
	<</if>>
	<<set _keys to Object.keys($transformationParts)>>
	<<if $panicattacks gte 2>>
		<<for _i to 0; _i lt _keys.length; _i++>>
			<<set _key to _keys[_i]>>
			<<for _label, _value range $transformationParts[_key]>>
				<<if _value is "hidden" and _label isnot "pubes" and _label isnot "pits" and _label isnot "cheeks" and !(_label is "wings" and _excludeWings is true)>>
					<<set $transformationParts[clone(_key)][clone(_label)] to "default">>
					<<set _hidingFailed to true>>
				<</if>>
			<</for>>
		<</for>>
		<<if _hidingFailed>>
			Your mental state is too fragile to continue hiding your inner self.
		<</if>>
	<<else>>
		<<for _i to 0; _i lt _keys.length; _i++>>
			<<set _key to _keys[_i]>>
			<<for _label, _value range $transformationParts[_key]>>
				<<if _value is "hidden" and _label isnot "pubes" and _label isnot "pits" and _label isnot "cheeks" and !(_label is "wings" and _excludeWings is true)>>
					<<trauma 15>>
					<<set _hiddenTrauma to true>>
				<</if>>
			<</for>>
		<</for>>
		<<if _hiddenTrauma is true>>
			Hiding your inner self takes a toll on your mental state.
		<</if>>
	<</if>>
<</if>>
<</widget>>

<<widget "transformationAlteration">>
<<switch $wolfgirl>>
	<<case 0>>
		<<if $wolfbuild gte 5 and $transformdisable is "f" and $physicalTransform isnot 1>>
			<<set $wolfgirl to 1>><<set $physicalTransform to 1>>
			You have a strange toothache.

		<</if>>
	<<case 1>>
		<<if $wolfbuild gte 10 and $transformdisable is "f">>
			<<set $wolfgirl to 2>>
			Your mouth feels different. You explore your mouth and wince as your tongue presses against your new fangs.
			<<set $transformationParts.wolf.cheeks to "hidden">>

		<<elseif $wolfbuild lt 5>>
			<<set $wolfgirl to 0>><<set $physicalTransform to 0>>
			Your toothache has stopped.

		<</if>>
	<<case 2>>
		<<if $wolfbuild gte 15 and $transformdisable is "f">>
			<<set $wolfgirl to 3>>
			Your scalp <<print ($pbdisable is "f" ? "and pubic area itch" : "itches")>>.

		<<elseif $wolfbuild lt 10>>
			<<set $wolfgirl to 1>>
			Your fangs have turned into regular teeth.
			<<set $transformationParts.wolf.cheeks to "disabled">>

		<</if>>
	<<case 3>>
		<<if $wolfbuild gte 20 and $transformdisable is "f">>
			<<set $wolfgirl to 4>>
			You feel something on your head. You reach up and tug, but it hurts.
			You have a new pair of wolf ears.
			<<print ($pbdisable is "f" ? " You also notice long and fluffy hair has grown in your pubic area.":"")>>
			<<set $transformationParts.wolf.ears to "default">>
			<<set $transformationParts.wolf.pubes to ($pbdisable is "f"? "default" : "hidden")>>
			<<set $transformationParts.wolf.pits to ($pbdisable is "f"? "default" : "hidden")>>

		<<elseif $wolfbuild lt 15>>
			<<set $wolfgirl to 2>>
			Your scalp <<print ($pbdisable is "f" ? "and pubic area no longer itch" : "no longer itches")>>.

		<</if>>
	<<case 4>>
		<<if $wolfbuild gte 25 and $transformdisable is "f">>
			<<set $wolfgirl to 5>>
			Your lower back itches.

		<<elseif $wolfbuild lt 20>>
			<<set $wolfgirl to 3>>
			Your wolf ears <<print ($pbdisable is "f" ? "and extra body hair ":"")>>have disappeared.
			<<set $transformationParts.wolf.ears to "disabled">>
			<<set $transformationParts.wolf.pubes to "disabled">>
			<<set $transformationParts.wolf.pits to "disabled">>

		<</if>>
	<<case 5>>
		<<if $wolfbuild gte 30 and $transformdisable is "f">>
			<<set $wolfgirl to 6>>
			Your bottom feels heavier than usual. You reach behind you and feel your new wolf tail.
			<<set $transformationParts.wolf.tail to "default">>
			<<earnFeat "Wolf">>

		<<elseif $wolfbuild lt 25>>
			<<set $wolfgirl to 4>>
			Your lower back has stopped itching.

		<</if>>
	<<case 6>>
		<<if $wolfbuild lt 30>>
			Your balance feels different. Your wolf tail has disappeared.
			<<set $wolfgirl to 5>>
			<<set $transformationParts.wolf.tail to "disabled">>

		<</if>>
<</switch>>

<<switch $angel>>
	<<case 0>>
		<<if $angelbuild gte 25 and $transformdisabledivine is "f" and $specialTransform isnot 1>>
			<<set $angel to 1>><<set $specialTransform to 1>>
			Despite everything, you have managed to remain a pure <<gender>>. The thought makes you happy.

		<</if>>
	<<case 1>>
		<<if $angelbuild gte 30 and $transformdisabledivine is "f">>
			<<set $angel to 2>>
			You are pure and feel determined to keep it that way.

		<<elseif $angelbuild lt 25>>
			<<set $angel to 0>><<set $specialTransform to 0>>
			You feel soiled.

		<</if>>
	<<case 2>>
		<<if $angelbuild gte 35 and $transformdisabledivine is "f">>
			<<set $angel to 3>>
			You feel a weight lift from your shoulders.

		<<elseif $angelbuild lt 30>>
			<<set $angel to 1>>
			You feel dirty.

		<</if>>
	<<case 3>>
		<<if $angelbuild gte 40 and $transformdisabledivine is "f">>
			<<set $angel to 4>>
			A golden light shines down on you.
			<<set $transformationParts.angel.halo to "default">>

		<<elseif $angelbuild lt 35>>
			<<set $angel to 2>>
			You feel a weight bear down on you.

		<</if>>
	<<case 4>>
		<<if $angelbuild gte 45 and $transformdisabledivine is "f">>
			<<set $angel to 5>>
			You feel a soothing warmth in your back.

		<<elseif $angelbuild lt 40>>
			<<set $angel to 3>>
			The light above you fades.
			<<set $transformationParts.angel.halo to "disabled">>

		<</if>>
	<<case 5>>
		<<if $angelbuild gte 50 and $transformdisabledivine is "f">>
			<<set $angel to 6>>
			You feel lighter. Your new wings caress your face.
			<<set $transformationParts.angel.wings to "default">>
			<<if $transformationParts.bird.wings is "default">>
				<<set $transformationParts.angel.wings to "hidden">>
			<</if>>
			<<earnFeat "Angel">>

		<<elseif $angelbuild lt 45>>
			<<set $angel to 4>>
			The soothing warmth in your back fades.

		<</if>>
	<<case 6>>
		<<if $angelbuild lt 50>>
			Your wings fade away.
			<<set $angel to 5>>
			<<set $transformationParts.angel.wings to "disabled">>

		<</if>>
<</switch>>

<<switch $demon>>
	<<case 0>>
		<<if $demonbuild gte 5 and $transformdisabledivine is "f" and $specialTransform isnot 1>>
			<<set $demon to 1>><<set $specialTransform to 1>>
			Your scalp itches.
			<<garousal>><<arousal 600>>

		<</if>>
	<<case 1>>
		<<if $demonbuild gte 10 and $transformdisabledivine is "f">>
			<<set $demon to 2>>
			Horns sprout from your scalp.
			<<garousal>><<arousal 600>>
			<<set $transformationParts.demon.horns to "default">>

		<<elseif $demonbuild lt 5>>
			<<set $demon to 0>><<set $specialTransform to 0>>
			You feel an invisible light burn away your impurity.
			<<if $demonFeat is true>>
				<<unset $demonFeat>>
				<<earnFeat "The Path to Redemption">>
			<</if>>

		<</if>>
	<<case 2>>
		<<if $demonbuild gte 15 and $transformdisabledivine is "f">>
			<<set $demon to 3>>
			Your <<bottom>> itches.

		<<elseif $demonbuild lt 10>>
			<<set $demon to 1>>
			<<set $transformationParts.demon.horns to "disabled">>
			Your horns recede.

		<</if>>
	<<case 3>>
		<<if $demonbuild gte 20 and $transformdisabledivine is "f">>
			<<set $demon to 4>>
			A tail sprouts from your lower back.
			<<set $transformationParts.demon.tail to "default">>

		<<elseif $demonbuild lt 15>>
			<<set $demon to 2>>
			The itching in your <<bottom>> stops.

		<</if>>
	<<case 4>>
		<<if $demonbuild gte 25 and $transformdisabledivine is "f">>
			<<set $demon to 5>>
			You feel a burning sensation in your back.
			<<garousal>><<arousal 600>>

		<<elseif $demonbuild lt 20>>
			<<set $demon to 3>>
			Your tail recedes.
			<<set $transformationParts.demon.tail to "disabled">>

		<</if>>
	<<case 5>>
		<<if $demonbuild gte 30 and $transformdisabledivine is "f">>
			<<set $demon to 6>><<set $demonFeat to true>>
			You feel lighter. Your new wings caress your face.
			<<garousal>><<arousal 600>>
			<<set $transformationParts.demon.wings to "default">>
			<<if $transformationParts.bird.wings is "default">>
				<<set $transformationParts.demon.wings to "hidden">>
			<</if>>
			<<earnFeat "Demon">>

		<<elseif $demonbuild lt 25>>
			<<set $demon to 4>>
			The burning in your back ceases.

		<</if>>
	<<case 6>>
		<<if $demonbuild lt 30>>
			Your wings recede.
			<<set $demon to 5>>
			<<set $transformationParts.demon.wings to "disabled">>

		<<else>>
			<<set $demonFeat to true>>
		<</if>>
<</switch>>

<<switch $cat>>
	<<case 0>>
		<<if $catbuild gte 25 and $transformdisable is "f" and $physicalTransform isnot 1>>
			<<set $cat to 1>><<set $physicalTransform to 1>>
			You have a strange toothache. A beetle crawls by. You resist the urge to pounce.

		<</if>>
	<<case 1>>
		<<if $catbuild gte 30 and $transformdisable is "f">>
			<<set $cat to 2>>
			Your mouth feels different. You explore your mouth and wince as your tongue presses against your new fangs.

		<<elseif $catbuild lt 25>>
			<<set $cat to 0>><<set $physicalTransform to 0>>
			Your toothache has stopped.

		<</if>>
	<<case 2>>
		<<if $catbuild gte 35 and $transformdisable is "f">>
			<<set $cat to 3>>
			Your scalp itches.

		<<elseif $catbuild lt 30>>
			<<set $cat to 1>>
			Your fangs have turned into regular teeth.

		<</if>>
	<<case 3>>
		<<if $catbuild gte 40 and $transformdisable is "f">>
			<<set $cat to 4>>
			Your scalp twitches. You reach up and feel your new pair of cat ears.
			<<set $transformationParts.cat.ears to "default">>

		<<elseif $catbuild lt 35>>
			<<set $cat to 2>>
			Your scalp no longer itches.

		<</if>>
	<<case 4>>
		<<if $catbuild gte 45 and $transformdisable is "f">>
			<<set $cat to 5>>
			Your lower back itches.

		<<elseif $catbuild lt 40>>
			<<set $cat to 3>>
			Your cat ears have disappeared.
			<<set $transformationParts.cat.ears to "disabled">>

		<</if>>
	<<case 5>>
		<<if $catbuild gte 50 and $transformdisable is "f">>
			<<set $cat to 6>>
			Your bottom feels weighty, yet perfectly balanced.
			You reach behind and feel your new cat tail.
			<<set $transformationParts.cat.tail to "default">>
			<<earnFeat "Neko">>

		<<elseif $catbuild lt 45>>
			<<set $cat to 4>>
			The itching in your lower back stops.

		<</if>>
	<<case 6>>
		<<if $catbuild lt 50>>
			Your cat tail disappears.
			<<set $transformationParts.cat.tail to "disabled">>
			<<set $cat to 5>>

		<</if>>
<</switch>>

<<switch $bunny>>
	<<case 0>>
		<<if $bunnybuild gte 25 and $transformdisable is "f" and $physicalTransform isnot 1>>
			<<set $bunny to 1>><<set $physicalTransform to 1>>
			You're struck with an odd impulse to run and jump in circles.

		<</if>>
	<<case 1>>
		<<if $bunnybuild gte 30 and $transformdisable is "f">>
			<<set $bunny to 2>>
			You catch youself jumping at shadows.

		<<elseif $bunnybuild lt 25>>
			<<set $bunny to 0>><<set $physicalTransform to 0>>
			You feel slower for reasons you can't seem to place.

		<</if>>
	<<case 2>>
		<<if $bunnybuild gte 35 and $transformdisable is "f">>
			<<set $bunny to 3>>
			Your scalp itches.

		<<elseif $bunnybuild lt 30>>
			<<set $bunny to 1>>
			You don't know what you were so worried about before.

		<</if>>
	<<case 3>>
		<<if $bunnybuild gte 40 and $transformdisable is "f">>
			<<set $bunny to 4>>
			You jump as something falls in front of your face. You go to move it with your hands, but it moves away on its own. It's your own new pair of bunny ears.
			<<set $transformationParts.bunny.ears to "default">>

		<<elseif $bunnybuild lt 35>>
			<<set $bunny to 2>>
			Your scalp no longer itches.

		<</if>>
	<<case 4>>
		<<if $bunnybuild gte 45 and $transformdisable is "f">>
			<<set $bunny to 5>>
			Your lower back itches.

		<<elseif $bunnybuild lt 40>>
			<<set $bunny to 3>>
			Your bunny ears have disappeared.
			<<set $transformationParts.bunny.ears to "disabled">>

		<</if>>
	<<case 5>>
		<<if $bunnybuild gte 50 and $transformdisable is "f">>
			<<set $bunny to 6>>
			You feel something twitching behind you, between your hips. You reach around and feel a ball of fluff. Seems you have a new bunny tail.
			<<earnFeat "Bnuuy">>

		<<elseif $bunnybuild lt 45>>
			<<set $bunny to 4>>
			The itching in your lower back stops.

		<</if>>
	<<case 6>>
		<<if $bunnybuild lt 50>>
			Your bunny tail disappears.
			<<set $transformationParts.bunny.tail to "disabled">>
			<<set $bunny to 5>>

		<</if>>
<</switch>>

<<switch $cow>>
	<<case 0>>
		<<if $cowbuild gte 5 and $transformdisable is "f" and $physicalTransform isnot 1>>
			<<set $cow to 1>><<set $physicalTransform to 1>>
			You have a strange urge to munch grass.

		<</if>>
	<<case 1>>
		<<if $cowbuild gte 10 and $transformdisable is "f">>
			<<set $cow to 2>>
			<<set $transformationParts.cow.horns to "default">>
			Your scalp itches. You reach up, and find that a pair of small horns have sprouted.

		<<elseif $cowbuild lt 5>>
			<<set $cow to 0>><<set $physicalTransform to 0>>
			Grass no longer looks so tasty.

		<</if>>
	<<case 2>>
		<<if $cowbuild gte 15 and $transformdisable is "f">>
			<<set $cow to 3>>
			Your ears tingle.

		<<elseif $cowbuild lt 10>>
			<<set $cow to 1>>
			<<set $transformationParts.cow.horns to "disabled">>
			Your small horns have disappeared.

		<</if>>
	<<case 3>>
		<<if $cowbuild gte 20 and $transformdisable is "f">>
			<<set $cow to 4>>
			<<set $transformationParts.cow.ears to "default">>
			Your ears itch. You reach up to scratch them, and find them much bigger than you expected. You've grown a pair of cow ears.

		<<elseif $cowbuild lt 15>>
			<<set $cow to 2>>
			Your ears no longer tingle.

		<</if>>
	<<case 4>>
		<<if $cowbuild gte 25 and $transformdisable is "f">>
			<<set $cow to 5>>
			Your lower back tingles.

		<<elseif $cowbuild lt 20>>
			<<set $cow to 3>>
			<<set $transformationParts.cow.ears to "disabled">>
			Your cow ears have disappeared.

		<</if>>
	<<case 5>>
		<<if $cowbuild gte 30 and $transformdisable is "f">>
			<<set $cow to 6>>
			<<set $semen_max to 6000>>
			<<set $milk_max to 6000>>
			<<set $transformationParts.cow.tail to "default">>
			<<earnFeat "Cattle">>
			Your bottom feels heavier than usual. You reach behind you and feel your new cow tail. You suppress the urge to moo.

		<<elseif $cowbuild lt 25>>
			<<set $cow to 4>>
			Your lower back has stopped tingling.

		<</if>>
	<<case 6>>
		<<if $cowbuild lt 30>>
			<<set $semen_max to 3000>>
			<<set $milk_max to 3000>>
			Your balance feels different. Your cow tail has disappeared.
			<<set $cow to 5>>
			<<set $transformationParts.cow.tail to "disabled">>

		<</if>>
<</switch>>

<<switch $harpy>>
	<<case 0>>
		<<if $birdbuild gte 5 and $transformdisable is "f" and $physicalTransform isnot 1>>
			<<set $harpy to 1>><<set $physicalTransform to 1>>
			Your vision feels sharper.

		<</if>>
	<<case 1>>
		<<if $birdbuild gte 10 and $transformdisable is "f">>
			<<set $harpy to 2>>
			Your eyes feel strange. Your vision has improved.
			<<set $transformationParts.bird.eyes to "default">>
			<<set $transformationParts.bird.malar to "default">>

		<<elseif $birdbuild lt 5>>
			<<set $harpy to 0>><<set $physicalTransform to 0>>
			Your vision has returned to normal.

		<</if>>
	<<case 2>>
		<<if $birdbuild gte 15 and $transformdisable is "f">>
			<<set $harpy to 3>>
			Your lower back and neck itch.

		<<elseif $birdbuild lt 10>>
			<<set $harpy to 1>>
			Your vision is no longer so sharp.
			<<set $transformationParts.bird.eyes to "disabled">>
			<<set $transformationParts.bird.malar to "disabled">>

		<</if>>
	<<case 3>>
		<<if $birdbuild gte 20 and $transformdisable is "f">>
			<<set $harpy to 4>>
			Your bottom feels lighter. You reach behind you, and grasp a feathered tail. Small feathers cover your neck.
			<<set $transformationParts.bird.tail to "default">>
			<<set $transformationParts.bird.plumage to "default">>

		<<elseif $birdbuild lt 15>>
			<<set $harpy to 2>>
			The itching in your lower back and neck both stop.

		<</if>>
	<<case 4>>
		<<if $birdbuild gte 25 and $transformdisable is "f">>
			<<set $harpy to 5>>
			Your back <<print ($pbdisable is "f" ? "and pubic area itch" : "itches")>>.

		<<elseif $birdbuild lt 20>>
			<<set $harpy to 3>>
			Your feathered tail has disappeared, along with the feathers on your neck.
			<<set $transformationParts.bird.tail to "disabled">>
			<<set $transformationParts.bird.plumage to "disabled">>

		<</if>>
	<<case 5>>
		<<if $birdbuild gte 30 and $transformdisable is "f">>
			<<set $harpy to 6>>
			You feel light as a feather. Wings caress your face.
			<<print($pbdisable is "f" ? " You also notice that short, feathery hair has grown in your pubic area.":"")>>
			<<earnFeat "Harpy">>
			<<set $transformationParts.bird.wings to "default">>
			<<if $transformationParts.angel.wings is "default">>
				<<set $transformationParts.angel.wings to "hidden">>
			<<elseif $transformationParts.fallenAngel.wings is "default">>
				<<set $transformationParts.fallenAngel.wings to "hidden">>
			<<elseif $transformationParts.demon.wings is "default">>
				<<set $transformationParts.demon.wings to "hidden">>
			<</if>>
			<<if $pbdisable is "f">>
				<<set $transformationParts.bird.pubes to "default">>
			<<else>>
				<<set $transformationParts.bird.pubes to "hidden">>
			<</if>>

		<<elseif $birdbuild lt 25>>
			<<set $harpy to 4>>
			You feel heavier<<print ($pbdisable is "f" ? ", and your pubic area no longer itches" : "")>>.

		<</if>>
	<<case 6>>
		<<if $birdbuild lt 30>>
			You feel heavier. Your feathered wings<<print ($pbdisable is "f" ? " and feathery pubes":"")>> have disappeared.
			<<set $harpy to 5>>
			<<set $transformationParts.bird.wings to "disabled">>
			<<set $transformationParts.bird.pubes to "disabled">>
			<<if $angel gte 6>>
				<<set $transformationParts.angel.wings to "default">>
			<</if>>
			<<if $demon gte 6>>
				<<set $transformationParts.demon.wings to "default">>
			<</if>>
			<<if $fallenangel gte 2>>
				<<set $transformationParts.fallenAngel.wings to "default">>
			<</if>>

		<</if>>
<</switch>>

<<if $cat gt 0 or $wolfgirl gt 0 or $cow gt 0 or $harpy gt 0 or $bunny gt 0>>
	<<set $physicalTransform to 1>>
<<else>>
	<<set $physicalTransform to 0>>
<</if>>
<<if $physicalTransform is 1 or $specialTransform is 1>>
	<<if $harpy gte 6 and ($angel gte 6 or $fallenangel gte 2 or $demon gte 6)>>
		<<if $transformationParts.bird.wings is "hidden" and ($transformationParts.demon.wings is "hidden" or $transformationParts.angel.wings is "hidden" or $transformationParts.fallenAngel.wings is "hidden")>>
		<<else>>
			<<set _excludeWings to true>>
		<</if>>
	<</if>>
	<<set _keys to Object.keys($transformationParts)>>
	<<if $panicattacks gte 2>>
		<<for _i to 0; _i lt _keys.length; _i++>>
			<<set _key to _keys[_i]>>
			<<for _label, _value range $transformationParts[_key]>>
				<<if _value is "hidden" and _label isnot "pubes" and _label isnot "pits" and _label isnot "cheeks" and !(_label is "wings" and _excludeWings is true)>>
					<<set $transformationParts[clone(_key)][clone(_label)] to "default">>
					<<set _hidingFailed to true>>
				<</if>>
			<</for>>
		<</for>>
		<<if _hidingFailed>>
			Your mental state is too fragile to continue hiding your inner self.
		<</if>>
	<<else>>
		<<for _i to 0; _i lt _keys.length; _i++>>
			<<set _key to _keys[_i]>>
			<<for _label, _value range $transformationParts[_key]>>
				<<if _value is "hidden" and _label isnot "pubes" and _label isnot "pits" and _label isnot "cheeks" and !(_label is "wings" and _excludeWings is true)>>
					<<trauma 15>>
					<<set _hiddenTrauma to true>>
				<</if>>
			<</for>>
		<</for>>
		<<if _hiddenTrauma is true>>
			Hiding your inner self takes a toll on your mental state.
		<</if>>
	<</if>>
<</if>>
<</widget>>

<<widget "hirsuteHideCheck">>
<<if $pbdisable is "t" and !["hidden", "disabled"].includes($transformationParts.wolf.pubes)>>
	<<set $transformationParts.wolf.pubes to "hidden">>
<</if>>
<<if $pbdisable is "t" and !["hidden", "disabled"].includes($transformationParts.wolf.pits)>>
	<<set $transformationParts.wolf.pits to "hidden">>
<</if>>
<<if $pbdisable is "t" and !["hidden", "disabled"].includes($transformationParts.bird.pubes)>>
	<<set $transformationParts.bird.pubes to "hidden">>
<</if>>
<</widget>>

/* Used to temporarily hide all transformation parts, such as when needing to turn the player into Janet. showTransformations will bring back all parts this widget hid. */
<<widget "hideTransformations">>
	<<set $saveTransformtaions to clone($transformationParts)>>
	<<for _transformation, _parts range $transformationParts>>
		<<for _part, _value range _parts>>
			<<if _value isnot "disabled" and _value isnot "hidden">>
				<<set $transformationParts[_transformation][_part] to "hidden">>
			<</if>>
		<</for>>
	<</for>>
<</widget>>

<<widget "showTransformations">>
	<<if $saveTransformtaions isnot undefined>>
		<<set $transformationParts to clone($saveTransformtaions)>>
		<<unset $saveTransformtaions>>
	<</if>>
<</widget>>


code:
:: Widgets Weather [widget]
<<widget "weather_select">>

/*New
<!--Sets today's weather-->
	<<set $weather.current to $weather.sevendayforcast.shift()>>
	<<run $weather.rainydays.deleteAt(0)>>
	<<run $weather.chance.deleteAt(0)>>
	<<set $weather.chance[1] to 100>>

	<!--Sets the days for the tv-->
	<<set _yesterday to $weather.weekdaylist.shift()>>
	<<run $weather.weekdaylist.push(_yesterday)>>

	<!--Allows for the next rainy day streak to occur once the cooldown is over.-->
	<<if !$weather.rainydays.includes(-1)>>
		<<set $weather.rainstreak to false>>
		<<set $weather.raindaystart to 0>>
	<</if>>

	<!--Fills the weather forcast for the next 7 days and adds any missing days in-->
	<<if $weather.sevendayforcast.length isnot 7>>
		<<for _e to $weather.sevendayforcast.length; _e lt 7; _e++>>
			<<set _weatherOptions to ["clear", "clear", "clear", "clear", "overcast", "overcast", "overcast", "overcast", "rain", "rain"]>>

			<<if _e lte 1>>
				<<run $weather.sevendayforcast.push(either(_weatherOptions))>>
				<<run $weather.chance.push(100) >>
			<<else>>
				<<set $rng to random(30,74)>>

				<<run $weather.sevendayforcast.push(either(_weatherOptions))>>
				<<run $weather.chance.push($rng)>>
			<</if>>

			<<if $weather.rainydays.length lt 7>>
				<<run $weather.rainydays.push(0)>>
			<</if>>
		<</for>>
	<</if>>

	<!--Adjusts the weather forecast based on the previous day's weather. Changes to weather occur when rng is greater than the chance.-->
	<<for _i to 2; _i lte 7; _i++>>
		<<set $rng to random(1,100)>>
		<<set _prev to _i - 1>>

		<!--Changes the chance of weather based on previous day. Bonuses for same type and penalties for far steps.
	 	'else' boosts the weather's chance, while being less than rng lowers it. If it gets too low, the weather can change.-->
		<<if $weather.sevendayforcast[_i] is "clear">>

			<<if $weather.sevendayforcast[_prev] is "clear">>

				<<if $rng gt $weather.chance[_i]>>
					<<set $weather.chance[_i] -= random(1,5)>>
						<<if $weather.chance[_i] lte 50 and random(1,5) is 3 or $weather.chance[_i] lte 10>>
							<<set $weather.sevendayforcast[_i] to "overcast">>
							<<set $weather.chance[_i] += 15>>
						<<elseif $weather.chance[_i] lte 25 and random(1,7) is 3>>
							<<set $weather.sevendayforcast[_i] to "rain">>
							<<set $weather.chance[_i] += 15>>
						<</if>>
				<<else>>
					<<set $weather.chance[_i] += random(0,5)>>
				<</if>>

			<<elseif $weather.sevendayforcast[_prev] is "overcast">>

				<<if $rng gt $weather.chance[_i] + 5>>
					<<set $weather.chance[_i] -= random(5,12)>>
						<<if $weather.chance[_i] lte 55 and random(1,5) is 3 or $weather.chance[_i] lte 15>>
							<<set $weather.sevendayforcast[_i] to "overcast">>
							<<set $weather.chance[_i] += 13>>
						<<elseif $weather.chance[_i] lte 32 and random(1,7) is 3>>
							<<set $weather.sevendayforcast[_i] to "rain">>
							<<set $weather.chance[_i] += 7>>
						<</if>>
				<<else>>
					<<set $weather.chance[_i] += random(-2,5)>>
				<</if>>

			<<elseif $weather.sevendayforcast[_prev] is "rain">>

				<<if $rng gt $weather.chance[_i] + 20>>
					<<set $weather.chance[_i] -= random(8,14)>>
						<<if $weather.chance[_i] lte 60 and random(1,5) is 3 or $weather.chance[_i] lte 20>>
							<<set $weather.sevendayforcast[_i] to "overcast">>
							<<set $weather.chance[_i] += 15>>
						<<elseif $weather.chance[_i] lte 37 and random(1,10) is 6>>
							<<set $weather.sevendayforcast[_i] to "rain">>
							<<set $weather.chance[_i] += 9>>
								<<if $weather.rainstreak is false>>
									<<set $weather.rainstreak to true>>
								<<elseif $weather.rainstreak is true>>
									<<rainstreak $weather.rainstreak _i>>
									<<set $weather.rainstreak to 0>>
								<</if>>
						<</if>>
				<<else>>
					<<set $weather.chance[_i] += random(-4,7)>>
				<</if>>

			<</if>>

			<<if $weather.rainstreak[_i] is 1>>
				<<set $weather.sevendayforcast[_i] to "rain">>
				<<set $weather.chance[_i] to 100>>
			<</if>>

		<<elseif $weather.sevendayforcast[_i] is "overcast">>

			<<if $weather.sevendayforcast[_prev] is "overcast">>

				<<if $rng gt $weather.chance[_i]>>
					<<set $weather.chance[_i] -= random(1,5)>>
						<<if $weather.chance[_i] lte 50 and random(1,5) is 3>>
							<<set $weather.sevendayforcast[_i] to "clear">>
							<<set $weather.chance[_i] += 15>>
						<<elseif $weather.chance[_i] lte 45 and random(1,5) is 3 or $weather.chance[_i] lte 15>>
							<<set $weather.sevendayforcast[_i] to "rain">>
							<<set $weather.chance[_i] += 15>>
						<</if>>
				<<else>>
					<<set $weather.chance[_i] += random(0,9)>>
				<</if>>

			<<elseif $weather.sevendayforcast[_prev] is "clear">>

				<<if $rng gt $weather.chance[_i] + 5>>
					<<set $weather.chance[_i] -= random(5,10)>>
						<<if $weather.chance[_i] lte 55 and random(1,5) is 3>>
							<<set $weather.sevendayforcast[_i] to "clear">>
							<<set $weather.chance[_i] += 13>>
						<<elseif $weather.chance[_i] lte 55 and random(1,5) is 3 or $weather.chance[_i] lte 10>>
							<<set $weather.sevendayforcast[_i] to "rain">>
							<<set $weather.chance[_i] += 7>>
						<</if>>
				<<else>>
					<<set $weather.chance[_i] += random(-2,5)>>
				<</if>>

			<<elseif $weather.sevendayforcast[_prev] is "rain">>

				<<if $rng gt $weather.chance[_i] + 20>>
					<<set $weather.chance[_i] -= random(8,15)>>
						<<if $weather.chance[_i] lte 50 and random(1,10) is 3>>
							<<set $weather.sevendayforcast[_i] to "clear">>
							<<set $weather.chance[_i] += 15>>
						<<elseif $weather.chance[_i] lte 50 and random(1,4) is 3 or $weather.chance[_i] lte 15>>
							<<set $weather.sevendayforcast[_i] to "rain">>
							<<set $weather.chance[_i] += 9>>
								<<if $weather.rainstreak is false>>
									<<set $weather.rainstreak to true>>
									<<if $weather.raindaystart is 0>>
										<<set $weather.raindaystart to $weather.weekdaylist[_i]>>
									<</if>>
								<<elseif $weather.rainstreak is true>>
									<<rainstreak $weather.rainstreak _i>>
									<<set $weather.rainstreak to 0>>
									<<if $weather.raindaystart is 0>>
										<<set $weather.raindaystart to $weather.weekdaylist[_i]>>
									<</if>>
								<</if>>
						<</if>>
				<<else>>
					<<set $weather.chance[_i] += random(-4,7)>>
				<</if>>

			<</if>>

			<<if $weather.rainstreak[_i] is 1>>
				<<set $weather.sevendayforcast[_i] to "rain">>
				<<set $weather.chance[_i] to 100>>
			<</if>>

		<<elseif $weather.sevendayforcast[_i] is "rain">>

			<<if $weather.sevendayforcast[_prev] is "rain">>

				<<if $rng gt $weather.chance[_i]>>
					<<set $weather.chance[_i] -= random(1,5)>>
						<<if $weather.chance[_i] lte 50 and random(1,5) is 3 or $weather.chance[_i] lte 20>>
							<<set $weather.sevendayforcast[_i] to "overcast">>
							<<set $weather.chance[_i] += 15>>
						<<elseif $weather.chance[_i] lte 45 and random(1,6) is 3>>
							<<set $weather.sevendayforcast[_i] to "clear">>
							<<set $weather.chance[_i] += 15>>
						<</if>>
				<<else>>
					<<set $weather.chance[_i] += random(0,5)>>
						<<if $weather.rainstreak is false>>
							<<set $weather.rainstreak to true>>
							<<if $weather.raindaystart is 0>>
								<<set $weather.raindaystart to $weather.weekdaylist[_i]>>
							<</if>>
						<<elseif $weather.rainstreak is true>>
							<<rainstreak $weather.rainstreak _i>>
							<<set $weather.rainstreak to 0>>
							<<if $weather.raindaystart is 0>>
								<<set $weather.raindaystart to $weather.weekdaylist[_i]>>
							<</if>>
						<</if>>
				<</if>>

				<<if $weather.rainstreak[_i] is 1>>
					<<set $weather.sevendayforcast[_i] to "rain">>
					<<set $weather.chance[_i] to 100>>
				<</if>>

			<<elseif $weather.sevendayforcast[_prev] is "overcast">>

				<<if $rng gt $weather.chance[_i] + 5>>
					<<set $weather.chance[_i] -= random(5,13)>>
						<<if $weather.chance[_i] lte 55 and random(1,4) is 3 or $weather.chance[_i] lte 15>>
							<<set $weather.sevendayforcast[_i] to "overcast">>
							<<set $weather.chance[_i] += 13>>
						<<elseif $weather.chance[_i] lte 55 and random(1,6) is 3>>
							<<set $weather.sevendayforcast[_i] to "clear">>
							<<set $weather.chance[_i] += 7>>
						<</if>>
				<<else>>
					<<set $weather.chance[_i] += random(-2,7)>>
						<<if $weather.rainstreak is false>>
							<<set $weather.rainstreak to true>>
							<<if $weather.raindaystart is 0>>
								<<set $weather.raindaystart to $weather.weekdaylist[_i]>>
							<</if>>
						<<elseif $weather.rainstreak is true>>
							<<rainstreak $weather.rainstreak _i>>
							<<set $weather.rainstreak to 0>>
							<<if $weather.raindaystart is 0>>
								<<set $weather.raindaystart to $weather.weekdaylist[_i]>>
							<</if>>
						<</if>>
				<</if>>

			<<elseif $weather.sevendayforcast[_prev] is "clear">>

				<<if $rng gt $weather.chance[_i] + 20>>
					<<set $weather.chance[_i] -= random(8,15)>>
						<<if $weather.chance[_i] lte 50 and random(1,6) is 3 or $weather.chance[_i] lte 15>>
							<<set $weather.sevendayforcast[_i] to "overcast">>
							<<set $weather.chance[_i] += 15>>
						<<elseif $weather.chance[_i] lte 45 and random(1,8) is 4>>
							<<set $weather.sevendayforcast[_i] to "clear">>
							<<set $weather.chance[_i] += 9>>
						<</if>>
				<<else>>
					<<set $weather.chance[_i] += random(-4,7)>>
						<<if $weather.rainstreak is false>>
							<<set $weather.rainstreak to true>>
							<<if $weather.raindaystart is 0>>
								<<set $weather.raindaystart to $weather.weekdaylist[_i]>>
							<</if>>
						<<elseif $weather.rainstreak is true>>
							<<rainstreak $weather.rainstreak _i>>
							<<set $weather.rainstreak to 0>>
							<<if $weather.raindaystart is 0>>
								<<set $weather.raindaystart to $weather.weekdaylist[_i]>>
							<</if>>
						<</if>>
				<</if>>

			<</if>>

			<<if $weather.rainstreak[_i] is 1>>
				<<set $weather.sevendayforcast[_i] to "rain">>
				<<set $weather.chance[_i] to 100>>
			<</if>>

		<</if>>

		<<if $weather.chance[_i] lte 9>>
			<<set $weather.chance[_i] to random(10,20)>>
		<</if>>
		<<if $weather.chance[_i] gte 101>>
			<<set $weather.chance[_i] to 100>>
		<</if>>

	<</for>>

	<!--Checks to see if there are several days of rain in a row and if a rainstreak is valid.-->
	<<if $weather.rainstreak is true>>
		<<set _check to 0>>

		<<for _i to 1; _i lt 7; _i++>>
			<<set _prev to _i-1>>

			<<if $weather.sevendayforcast[_prev] is "rain" and $weather.sevendayforcast[_i] is "rain">>
				<<set _check to 1>>
				<<break>>
			<</if>>

		<</for>>

		<<if _check isnot 1>>
			<<set $weather.rainstreak to false>>
			<<set $weather.raindaystart to 0>>
		<<else>>
			<<set _check to 0>>
		<</if>>

	<</if>>
*/
<<if $month is "november" and $monthday is 29>>
	<<set _weatherOptions to ["snow"]>>
<<elseif $season is "winter">>
	<<set _weatherOptions to ["clear", "clear", "clear", "clear", "overcast", "overcast", "overcast", "overcast", "snow", "snow"]>>
<<else>>
	<<set _weatherOptions to ["clear", "clear", "clear", "clear", "overcast", "overcast", "overcast", "overcast", "rain", "rain"]>>
<</if>>
<<if $nextWeather is undefined>>
	<<set $nextWeather to [either(_weatherOptions),either(_weatherOptions),either(_weatherOptions)]>>
<<else>>
	<<run $nextWeather.push(either(_weatherOptions))>>
<</if>>
<<set $weather to $nextWeather[0]>>
<<run $nextWeather.deleteAt(0)>>

<<set $chill_day to 0>>
<<switch $season>>
<<case "spring">>
	<<set $chill_day += 50>>
<<case "summer">>

<<case "autumn">>
	<<set $chill_day += 60>>
<<case "winter">>
	<<set $chill_day += 150>>
<</switch>>
<<if $weather is "snow">>
	<<set $chill_day += 50>>
<</if>>
<<set $chill to $chill_day>>

<</widget>>

<!--Sets the number of days that a rainy streak will last. Pass it $weather.rainstreak and the day the streak starts as arguments. If true, sets up the streak.-->
<<widget "rainstreak">>

	<<if $args[0] is true and $args[1] isnot undefined>>
		<<set _rainydaysmax to random(2,7)>>

		<<if _rainydaysmax gte $weather.lastrainmax>>
			<<set _rainydaysmax to $weather.lastrainmax - 1>>
			<<set $weather.lastrainmax to 0>>
		<<else>>
			<<set $weather.lastrainmax to _rainydaysmax>>
		<</if>>

		<<set _rainycooldown to random( Math.floor(_rainydaysmax/2) + 1,9)>>

		<<for _e to $args[1]-1; _e lte $args[1] + _rainydaysmax + _rainycooldown; _e++>>
			<<if _e lte $args[1] + _rainydaysmax and $weather.rainydays[_e] isnot -1>>
				<<set $weather.rainydays[_e] to 1>>
				<<set $weather.sevendayforcast[_e] to "rain">>
				<<set $weather.chance[_e] to 100>>
			<<else>>
				<<set $weather.rainydays[_e] to -1>>
			<</if>>
		<</for>>
	<<else>>
		Error in rain streak widget. It was not passed an argument that was true and the current day or was passed no arguments.
	<</if>>

<</widget>>

<!--Initializes the weather.-->
<<widget "weatherinit">>
	<<set _weatherOptions to ["clear", "clear", "clear", "clear", "overcast", "overcast", "overcast", "overcast", "rain", "rain"]>>
	<<set $weather.current to either(_weatherOptions)>>

		<<for _e to 0; _e lt 7; _e++>>

			<<if _e is 0>>
				<<run $weather.sevendayforcast.push(either(_weatherOptions))>>
				<<run $weather.chance.push(100)>>
			<<elseif _e lte 1>>
				<<run $weather.sevendayforcast.push(either(_weatherOptions))>>
				<<run $weather.chance.push(100)>>
			<<else>>
				<<set $rng to random(40,74)>>

				<<run $weather.sevendayforcast.push(either(_weatherOptions))>>
				<<run $weather.chance.push($rng)>>
			<</if>>
			<<set $weather.rainydays[_e] to 0>>
		<</for>>

	<<run $weather.weekdaylist.push("Sunday")>>
	<<run $weather.weekdaylist.push("Monday")>>
	<<run $weather.weekdaylist.push("Tuesday")>>
	<<run $weather.weekdaylist.push("Wednesday")>>
	<<run $weather.weekdaylist.push("Thursday")>>
	<<run $weather.weekdaylist.push("Friday")>>
	<<run $weather.weekdaylist.push("Saturday")>>

<</widget>>

repo_name: Area/degrees

license: mit


code:
function setfemininitymultiplierfromgender(gender) {
	if (gender === "f") {
		T.femininity_multiplier = 1;
	} else if (gender === "m") {
		T.femininity_multiplier = -1;
	} else {
		T.femininity_multiplier = 0;
	}
}
DefineMacro("setfemininitymultiplierfromgender", setfemininitymultiplierfromgender);

function addfemininityfromfactor(femininity_boost, factor_description, no_overwear_check) {
	if (no_overwear_check) {
		T.gender_appearance_factors_noow.push({
			femininity: femininity_boost,
			factor: factor_description
		});
		T.apparent_femininity_noow += femininity_boost;
	} else {
		T.apparent_femininity += femininity_boost;
		T.gender_appearance_factors.push({
			femininity: femininity_boost,
			factor: factor_description
		});
	}
}
DefineMacro("addfemininityfromfactor", addfemininityfromfactor);

function addfemininityofclothingarticle(slot, clothing_article, no_overwear_check) {
	if (setup.clothes[slot][clothesIndex(slot,clothing_article)].femininity) {
		addfemininityfromfactor(setup.clothes[slot][clothesIndex(slot,clothing_article)].femininity, setup.clothes[slot][clothesIndex(slot,clothing_article)].name_cap, no_overwear_check);
	}
}
DefineMacro("addfemininityofclothingarticle", addfemininityofclothingarticle);

/** Calculate the player's gender appearance */
function genderappearancecheck() {
	/* Calculate bulge size */
	T.penis_compressed = V.player.penisExist && V.worn.genitals.type.includes("hidden");
	if (V.worn.genitals.type.includes("cage")) {
		T.bulge_size = Math.clamp(V.penissize, 0, Infinity);
	} else {
		if (!V.player.penisExist) {
			T.erection_state = 0;
		} else if (T.penis_compressed) {
			T.erection_state = 0;
		} else if (V.arousal < 6000) {
			T.erection_state = 0;
		} else if (V.arousal < 8000) {
			T.erection_state = 1;
		} else {
			T.erection_state = 2;
		}
		T.bulge_size = Math.clamp(V.penissize * T.erection_state, 0, Infinity);
	}
	/* Determine how visible the player's bottom is */
	if ((setup.clothes.lower[clothesIndex('lower',V.worn.lower)].skirt === 1 && V.worn.lower.skirt_down === 1 && V.worn.lower.state === "waist") ||
		(setup.clothes.over_lower[clothesIndex('over_lower',V.worn.over_lower)].skirt === 1 && V.worn.over_lower.skirt_down === 1 && V.worn.over_lower.state === "waist")) {
		T.bottom_visibility = 0;
	} else {
		T.bottom_visibility = 1;
	}
	/* Gender appearance factors */
	T.gender_appearance_factors = [];
	T.apparent_femininity = 0;
	T.breast_indicator = 0;
	/* Head clothing */
	addfemininityofclothingarticle('over_head',V.worn.over_head);
	addfemininityofclothingarticle('head',V.worn.head);
	/* Always visible clothing */
	addfemininityofclothingarticle('face',V.worn.face);
	addfemininityofclothingarticle('neck',V.worn.neck);
	addfemininityofclothingarticle('legs',V.worn.legs);
	addfemininityofclothingarticle('feet',V.worn.feet);
	/* Hair length */
	if ((V.worn.over_head.hood !== 1 && V.worn.head.hood !== 1) || V.hoodDown == 1) {
		addfemininityfromfactor(Math.trunc((V.hairlength - 200) / 2), "Hair length");
	}
	/* Makeup */
	addfemininityfromfactor(V.makeup.lipstick == 0 ? 0 : 50, "Lipstick");
	addfemininityfromfactor(V.makeup.eyeshadow == 0 ? 0 : 50, "Eye shadow");
	addfemininityfromfactor(V.makeup.mascara == 0 ? 0 : 50, "Mascara");
	/* Body structure */
	addfemininityfromfactor(Math.trunc(V.bottomsize * T.bottom_visibility * 50), "Bottom size (" + Math.trunc(T.bottom_visibility * 100) + "% visible)");
	setfemininitymultiplierfromgender(V.player.gender_body);
	addfemininityfromfactor(T.femininity_multiplier * 200, "Natural features");
	addfemininityfromfactor(Math.trunc((-1 * (V.physique + V.physiquesize / 2) / V.physiquesize) * 100), "Toned muscles");
	/* Behaviour */
	setfemininitymultiplierfromgender(V.player.gender_posture);
	T.acting_multiplier = V.englishtrait + 1;
	addfemininityfromfactor(T.femininity_multiplier * 100 * T.acting_multiplier, "Posture (x" + T.acting_multiplier + " effectiveness due to English skill)");
	/* Special handling for calculating topless gender */
	T.over_lower_protected = V.worn.over_lower.exposed < 2;
	T.lower_protected = V.worn.lower.exposed < 2;
	T.under_lower_protected = !V.worn.under_lower.exposed;
	T.apparent_femininity_noow = T.apparent_femininity;
	T.gender_appearance_factors_noow = clone(T.gender_appearance_factors);
	T.over_lower_femininity = (setup.clothes.over_lower[clothesIndex('over_lower',V.worn.over_lower)].femininity ? setup.clothes.over_lower[clothesIndex('over_lower',V.worn.over_lower)].femininity : 0);
	T.lower_femininity = (setup.clothes.lower[clothesIndex('lower',V.worn.lower)].femininity ? setup.clothes.lower[clothesIndex('lower',V.worn.lower)].femininity : 0);
	T.under_lower_femininity = (setup.clothes.under_lower[clothesIndex('under_lower',V.worn.under_lower)].femininity ? setup.clothes.under_lower[clothesIndex('under_lower',V.worn.under_lower)].femininity : 0);;
	/* find maximum possible femininity of the last lower piece you can strip down to, and add it to the counter */
	addfemininityfromfactor(Math.max(T.over_lower_femininity, T.lower_femininity, T.under_lower_femininity), "Lower clothes", "noow");
	/* bulge and genitals checks for topless gender */
	if (T.under_lower_protected && V.NudeGenderDC > 0) {
		addfemininityfromfactor(-T.bulge_size * 100, "Bulge visible through underwear", "noow");
	} else if ((T.over_lower_protected || T.lower_protected) && V.NudeGenderDC > 0) {
		addfemininityfromfactor(-Math.clamp((T.bulge_size - 3) * 100, 0, Infinity), "Bulge visible through clothing", "noow");
	} else if (V.worn.genitals.exposed && V.NudeGenderDC == 1) {
		if (V.player.penisExist) {
			addfemininityfromfactor((-V.penissize-2.5) * 150, "Penis exposed", "noow");
		}
		if (V.player.vaginaExist) {
			addfemininityfromfactor(450, "Vagina exposed", "noow");
		}
	} else if (V.worn.genitals.exposed && V.NudeGenderDC == 2) {
		addfemininityfromfactor(V.player.vaginaExist * 100000 - V.player.penisExist * 100000, "Genitals exposed", "noow");
	}
	/* plain breasts factor */
	addfemininityfromfactor((V.breastsize - 0.5) * 100, "Exposed breasts", "noow");
	/* Lower clothing, bulge, and genitals */
	addfemininityofclothingarticle('over_lower',V.worn.over_lower);
	if (!T.over_lower_protected) {
		addfemininityofclothingarticle('lower',V.worn.lower);
	}
	if (!T.over_lower_protected && !T.lower_protected) {
		/* Lower underwear is visible */
		addfemininityofclothingarticle('under_lower',V.worn.under_lower);
		if (!T.under_lower_protected) {
			/* Genitals slot is visible */
			addfemininityofclothingarticle('genitals',V.worn.genitals);
			if (V.worn.genitals.exposed) {
				/* Bare genitals are visible */
				if (V.NudeGenderDC == 1) {
					if (V.player.penisExist) {
						addfemininityfromfactor((-V.penissize-2.5) * 150, "Penis visible");
					}
					if (V.player.vaginaExist) {
						addfemininityfromfactor(450, "Vagina visible");
					}
				} else if (V.NudeGenderDC == 2) {
					if (V.player.penisExist) {
						addfemininityfromfactor(-100000, "Penis visible");
					}
					if (V.player.vaginaExist) {
						addfemininityfromfactor(100000, "Vagina visible");
					}
				}
			}
		} else {
			/* Bottom visible through underwear */
			T.bottom_visibility *= 0.75;
			/* Bulge visible through underwear */
			if (V.NudeGenderDC > 0) {
				addfemininityfromfactor(-T.bulge_size * 100, "Bulge visible through underwear");
			}
		}
	} else {
		/* Bottom covered by lower clothes */
		T.bottom_visibility *= 0.75;
		/* Bulge covered by lower clothes */
		if (V.NudeGenderDC > 0) {
			addfemininityfromfactor(-Math.clamp((T.bulge_size - 3) * 100, 0, Infinity), "Bulge visible through clothing");
		}
	}
	/* Upper clothing and breasts */
	addfemininityofclothingarticle('over_upper',V.worn.over_upper);
	if (V.worn.over_upper.exposed >= 2) {
		addfemininityofclothingarticle('upper',V.worn.upper);
	}
	if (V.worn.over_upper.exposed >= 2 && V.worn.upper.exposed >= 2) {
		/* Upper underwear is visible */
		addfemininityofclothingarticle('under_upper',V.worn.under_upper);
		if (V.worn.under_upper.exposed >= 1) {
			/* Exposed breasts */
			T.breast_indicator = 1;
			addfemininityfromfactor((V.breastsize - 0.5) * 100, "Exposed breasts");
		} else if (!V.worn.under_upper.type.includes("chest_bind")) {
			/* Breasts covered by only underwear */
			addfemininityfromfactor(Math.clamp(
				(V.breastsize - 2) * 100, 0, Infinity
			), "Breast size visible through underwear");
		}
	} else if (!V.worn.under_upper.type.includes("chest_bind")) {
		/* Breast fully covered */
		addfemininityfromfactor(Math.clamp(
			(V.breastsize - 4) * 100, 0, Infinity
		), "Breast size visible through clothing");
	}
	/* Pregnant Belly */
	if (V.sexStats === undefined) {
	}else if (V.sexStats.vagina.pregnancy.bellySize >= 8) {
		addfemininityfromfactor(Math.clamp(
			100000, 0, Infinity
		), "Pregnant Belly");
	}else if (V.sexStats.vagina.pregnancy.bellySize >= 5) {
		addfemininityfromfactor(Math.clamp(
			(V.sexStats.vagina.pregnancy.bellySize - 4) * 500, 0, Infinity
		), "Pregnant Belly");
	}
	/* Body writing */
	Wikifier.wikifyEval("<<bodywriting_exposure_check>>"); // TODO convert to JS when possible
	T.skinValue = 0;
	T.skinValue_noow = 0;
	Object.keys(V.skin).forEach(label=>{
		let value = V.skin[label];
		if (T.skin_array.includes(label)) {
			if (value.gender === "m") {
				T.skinValue -= 50 * (value.pen !== "pen"?2:1);
			} else if (value.gender === "f") {
				T.skinValue += 50 * (value.pen !== "pen"?2:1);
			}
		} else {
			if (value.gender === "m") {
				T.skinValue_noow -= 50 * (value.pen !== "pen"?2:1);
			} else if (V.skin.breasts.gender === "f") {
				T.skinValue_noow += 50 * (value.pen !== "pen"?2:1);
			}
		}
	});
	addfemininityfromfactor(T.skinValue, "Visible skin markings");
	addfemininityfromfactor(T.skinValue + T.skinValue_noow, "Visible skin markings", "noow");
	if (T.apparent_femininity > 0) {
		T.gender_appearance = "f";
	} else if (T.apparent_femininity < 0) {
		T.gender_appearance = "m";
	} else if (V.player.gender == "h") { // if herm pc and perfect 0 apparent_femininity
		if (["m", "f"].includes(V.player.gender_body)) // use natural features as a tie breaker if not androgynous
			T.gender_appearance = V.player.gender_body;
		else if (["m", "f"].includes(V.player.gender_posture)) // use gender posture as a tie breaker if not acting naturally
			T.gender_appearance = V.player.gender_posture;
		else
			T.gender_appearance = "f"; // you've done it. you've broken me. default to "f".
	} else {
		T.gender_appearance = V.player.gender;
	}
	if (T.apparent_femininity_noow > 0) {
		T.gender_appearance_noow = "f";
	} else if (T.apparent_femininity_noow < 0) {
		T.gender_appearance_noow = "m";
	} else if (V.player.gender == "h") {
		if (["m", "f"].includes(V.player.gender_body))
			T.gender_appearance_noow = V.player.gender_body;
		else if (["m", "f"].includes(V.player.gender_posture))
			T.gender_appearance_noow = V.player.gender_posture;
		else
			T.gender_appearance_noow = "f";
	} else {
		T.gender_appearance_noow = V.player.gender;
	}
}

function apparentbreastsizecheck(){
	T.tempbreast = V.breastsize;
	if ( clothingData('upper',V.worn.upper,'bustresize') != undefined ){ T.tempbreast += clothingData('upper',V.worn.upper,'bustresize') };
	if ( clothingData('under_upper',V.worn.under_upper,'bustresize') != undefined ){ T.tempbreast += clothingData('under_upper',V.worn.under_upper,'bustresize') };
	if ( clothingData('over_upper',V.worn.over_upper,'bustresize') != undefined){ T.tempbreast += clothingData('over_upper',V.worn.over_upper,'bustresize')  };
	V.player.perceived_breastsize = Math.clamp( V.breastsizemin, T.tempbreast, V.breastsizemax );
}

function apparentbottomsizecheck(){
	T.tempbutt = V.bottomsize;
	if ( V.worn.lower.rearresize != undefined ){ T.tempbutt += V.worn.lower.rearresize };
	if ( V.worn.under_lower.rearresize != undefined ){ T.tempbutt += V.worn.under_lower.rearresize };
	if ( V.worn.lower.rearresize != undefined ){ T.tempbutt += V.worn.over_lower.rearresize };
	V.player.perceived_bottomsize = Math.clamp( V.bottomsizemin, T.tempbutt, V.bottomsizemax );
}

function exposedcheck() {
	if ( !V.combat || V.args[0] === true ){
		genderappearancecheck();
		V.player.gender_appearance = T.gender_appearance;
		T.gender_appearance_factors.sort((a, b) => a.femininity > b.femininity);
		V.player.gender_appearance_factors = T.gender_appearance_factors;
		V.player.femininity = T.apparent_femininity;

		V.player.gender_appearance_without_overwear = T.gender_appearance_noow;
		T.gender_appearance_factors_noow.sort((a, b) => a.femininity > b.femininity);
		V.player.gender_appearance_without_overwear_factors = T.gender_appearance_factors_noow;
		V.player.femininity_without_overwear = T.apparent_femininity_noow;

		V.breastindicator = T.breast_indicator;

		apparentbreastsizecheck();
		apparentbottomsizecheck();
	}
}
DefineMacro("exposedcheck", exposedcheck);

function updatehistorycontrols(){
	if (V.maxStates === undefined || V.maxStates > 20) {
		/* initiate new variable based on engine config and limit it to 20 */
		V.maxStates = Math.clamp(1, 20, Config.history.maxStates);
	}
	if (V.maxStates == 1) {
		/* when disabled, irreversibly delete history controls the way sugarcube intended */
		Config.history.maxStates = 1;
		jQuery('#ui-bar-history').remove();
	} else {
		/* set actual maxStates in accordance with our new variable */
		Config.history.maxStates = V.maxStates;
		/* ensure that controls are enabled so sugarcube won't destroy them on reload */
		Config.history.controls = true;
		/* if irreversibly deleted, restore #ui-bar-history from oblivion and pop it after #ui-bar-toggle */
		if (jQuery("#ui-bar-history").length == 0){
			jQuery("#ui-bar-toggle").after(`
				<div id="ui-bar-history">
					<button id="history-backward" tabindex="0" title="'+t+'" aria-label="'+t+'">\uE821</button>
					<button id="history-forward" tabindex="0" title="'+n+'" aria-label="'+n+'">\uE822</button>
				</div>`);
			/* make buttons active/inactive based on the available history states */
			jQuery(document).on(':historyupdate.ui-bar', (($backward, $forward) => () => {
					$backward.ariaDisabled(State.length < 2);
					$forward.ariaDisabled(State.length === State.size);
				})(jQuery('#history-backward'), jQuery('#history-forward')));
			jQuery('#history-backward')
				.ariaDisabled(State.length < 2)
				.ariaClick({
					label : L10n.get('uiBarBackward')
				}, () => Engine.backward());
			jQuery('#history-forward')
				.ariaDisabled(State.length === State.size)
				.ariaClick({
					label : L10n.get('uiBarForward')
				}, () => Engine.forward());
		}
		jQuery("#ui-bar-history").show();
	}
}
DefineMacro("updatehistorycontrols", updatehistorycontrols);