code:
:: slave creation widgets [widget nobr]

/%
 Call as <<StartingGirlsWorkaround>>
%/
<<widget "StartingGirlsWorkaround">>
	<<set $activeSlave = GenerateNewSlave()>>
	<<set $startingGirlCopied = 0>>
	<<set $activeSlave.health = 0>>
	<<set $activeSlave.devotion = 0>>
	<<set $activeSlave.trust = 0>>
	<<set $activeSlave.sexualQuirk = "none">>
	<<set $activeSlave.behavioralQuirk = "none">>
	<<set $activeSlave.fetishKnown = 1>>
	<<if $activeSlave.vagina < 0>>
		<<set $activeSlave.ovaries = 0>>
	<<elseif $activeSlave.vagina < 1>>
		<<set $activeSlave.skill.vaginal = 0>>
	<</if>>
	<<if $activeSlave.anus < 1>>
		<<set $activeSlave.skill.anal = 0>>
	<</if>>

	<<set $activeSlave.actualAge = Number($activeSlave.actualAge) || 18>>
	<<set $activeSlave.devotion = Number($activeSlave.devotion) || 0>>
	<<set $activeSlave.trust = Number($activeSlave.trust) || 0>>
	<<if $activeSlave.indenture >= 0>>
		<<set $activeSlave.indenture = Math.clamp($activeSlave.indenture, 26, 208) || 26>>
	<</if>>
	<<set $activeSlave.height = Math.clamp($activeSlave.height, 85, 274) || 140>>
	<<set $activeSlave.boobs = Math.clamp(Math.trunc($activeSlave.boobs/50)*50, 0, 50000) || 200>>
<</widget>>

/%
 Call as <<SaleDescription>>
%/
<<widget "SaleDescription">>
	<<replace #slaveinfo>>
		<<set $saleDescription = 1>>
		<<include "Long Slave Description">>
	<</replace>>
<</widget>>

<<widget "SlaveCostDescription">>
	<<set $slaveCost = startingSlaveCost($activeSlave)>>
	<<if $slaveCost > $cash>>
	@@.red;This slave will cost ''<<print cashFormat($slaveCost)>>.''

	You only have: <<print cashFormat($cash)>>@@
	<<else>>
	This slave will cost @@.yellowgreen;''<<print cashFormat($slaveCost)>>.''@@

	You have <<print cashFormat($cash)>>.
	<</if>>
<</widget>>
/%
 Call as <<StartingGirlsCost>>
%/
<<widget "StartingGirlsCost">>

<<replace "#cost">>
<<SlaveCostDescription>>
<</replace>>
<<if $cash >= $slaveCost>>
	<<set $activeSlave.actualAge = Number($activeSlave.actualAge) || 18>>
	<<set $activeSlave.devotion = Number($activeSlave.devotion) || 0>>
	<<set $activeSlave.trust = Number($activeSlave.trust) || 0>>
	<<if $activeSlave.indenture >= 0>>
		<<set $activeSlave.indenture = Math.clamp($activeSlave.indenture, 26, 208) || 26>>
	<</if>>
	<<set $activeSlave.height = Math.clamp($activeSlave.height, 85, 274) || 140>>
	<<set $activeSlave.boobs = Math.clamp(Math.trunc($activeSlave.boobs/50)*50, 0, 50000) || 200>>
	<<set $slaveWithoutBonuses = $activeSlave>>
	<<if $PC.career != "engineer">>

		<<link "Add this slave">>
			<<set $returnTo = "Commit Starting Girl", $createRelatedSlave = 0, $applyCareerBonus = 1, $careerBonusApplied = 0>>
			<<set $slaveCost = startingSlaveCost($activeSlave)>>
			<<run cashX(forceNeg($slaveCost), "slaveTransfer", $activeSlave)>>
			<<goto "RG AS Dump">>
		<</link>>
		//This will apply your @@.springgreen;career bonus@@ to $him:
		<<if $PC.career == "capitalist">>
			one free level of @@.cyan;prostitution skill.@@
		<<elseif $PC.career == "mercenary">>
			@@.mediumaquamarine;+10 trust.@@
		<<elseif $PC.career == "slaver">>
			@@.hotpink;+10 devotion.@@
		<<elseif $PC.career == "medicine">>
			free @@.lime;basic implants.@@
		<<elseif $PC.career == "celebrity">>
			one free level of @@.cyan;entertainment skill.@@
		<<elseif $PC.career == "gang">>
			@@.green;+5 health@@ and a free level of @@.cyan;combat skill@@
		<<elseif $PC.career == "escort">>
			two free levels of @@.cyan;sex skills,@@ one free level of @@.cyan;prostitution skill,@@ and one free level of @@.cyan;entertainment skill.@@
		<<elseif $PC.career == "servant">>
			@@.mediumaquamarine;+10 trust@@ and @@.hotpink;+10 devotion.@@
		<<elseif $PC.career == "wealth">>
			two free levels of @@.cyan;sex skills.@@
		<<elseif $PC.career == "BlackHat">>
			one free level of @@.cyan;intelligence.@@
		<<else>>
			@@.hotpink;+10 devotion,@@ one free level of @@.cyan;prostitution skill@@ and @@.cyan;entertainment skill,@@ and two free levels of @@.cyan;sex skills.@@
		<</if>>//

		<<link "Add slave without career bonus">>
			<<set $returnTo = "Commit Starting Girl", $createRelatedSlave = 0, $applyCareerBonus = 0, $careerBonusApplied = 0>>
			<<set $slaveCost = startingSlaveCost($activeSlave)>>
			<<run cashX(forceNeg($slaveCost), "slaveTransfer", $activeSlave)>>
			<<goto "RG AS Dump">>
		<</link>>
	<<else>>

		<<link "Add slave">>
			<<set $returnTo = "Commit Starting Girl", $createRelatedSlave = 0, $applyCareerBonus = 0, $careerBonusApplied = 0>>
			<<set $slaveCost = startingSlaveCost($activeSlave)>>
			<<run cashX(forceNeg($slaveCost), "slaveTransfer", $activeSlave)>>
			<<goto "RG AS Dump">>
		<</link>>

	<</if>>
<<else>>

//You lack the necessary funds to add this slave.//
<</if>>

[[Discard this slave and continue|Acquisition]]
<</widget>>

/%
 Call as <<CustomSlaveAge>>
%/
<<widget "CustomSlaveAge">>
	<<replace #age>>
		<<if $customSlave.age < 3>>2- years old.
		<<elseif $customSlave.age < 5>>3-4 years old.
		<<elseif $customSlave.age < 7>>5-6 years old.
		<<elseif $customSlave.age < 10>>7-9 years old.
		<<elseif $customSlave.age < 13>>10-12 years old.
		<<elseif $customSlave.age < 15>>13-14 years old.
		<<elseif $customSlave.age < 18>>15-17 years old.
		<<elseif $customSlave.age < 20>>18-19 years old.
		<<elseif $customSlave.age < 25 && $retirementAge >= 25>>20-24 years old.
		<<elseif $customSlave.age < 25 && $retirementAge >= 20>>20+ years old.
		<<elseif $customSlave.age < 30 && $retirementAge >= 30>>25-29 years old.
		<<elseif $customSlave.age < 30 && $retirementAge >= 25>>25+ years old.
		<<elseif $customSlave.age < 40 && $retirementAge >= 40>>30-39 years old.
		<<elseif $customSlave.age < 40 && $retirementAge >= 30>>30+ years old.
		<<elseif $customSlave.age < 50 && $retirementAge >= 50>>40-49 years old.
		<<elseif $customSlave.age < 50 && $retirementAge >= 40>>40+ years old.
		<<elseif $customSlave.age < 60 && $retirementAge >= 60>>50-59 years old.
		<<elseif $customSlave.age < 60 && $retirementAge >= 50>>50+ years old.
		<<elseif $customSlave.age < 70 && $retirementAge >= 70>>60-69 years old.
		<<elseif $customSlave.age < 70 && $retirementAge >= 60>>60+ years old.
		<<elseif $customSlave.age < 80 && $retirementAge >= 80>>70-79 years old.
		<<elseif $customSlave.age < 80 && $retirementAge >= 70>>70+ years old.
		<<elseif $customSlave.age < 90 && $retirementAge >= 90>>80-89 years old.
		<<elseif $customSlave.age < 90 && $retirementAge >= 80>>80+ years old.
		<<elseif $customSlave.age < 100 && $retirementAge >= 100>>90-99 years old.
		<<elseif $customSlave.age < 100 && $retirementAge >= 90>>90+ years old.
		<<elseif $customSlave.age < 110 && $retirementAge >= 110>>100-109 years old.
		<<elseif $customSlave.age < 110 && $retirementAge >= 100>>100+ years old.
		<<elseif $customSlave.age < 120 && $retirementAge >= 120>>110-119 years old.
		<<elseif $customSlave.age < 120 && $retirementAge >= 110>>110+ years old.
		<<elseif $customSlave.age < 130 && $retirementAge >= 130>>120-129 years old.
		<<elseif $customSlave.age < 130 && $retirementAge >= 120>>120+ years old.
		<<else>>130+ years old.
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveHealth>>
%/
<<widget "CustomSlaveHealth">>
	<<replace #health>>
		<<if $customSlave.health == 0>>Healthy.
		<<else>>Extremely healthy.
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveMuscles>>
%/
<<widget "CustomSlaveMuscles">>
	<<replace #muscles>>
		<<if $customSlave.muscles > 95>>
			Ripped.
		<<elseif $customSlave.muscles > 50>>
			Muscular.
		<<elseif $customSlave.muscles > 30>>
			Well built.
		<<elseif $customSlave.muscles > 5>>
			Toned.
		<<elseif $customSlave.muscles > -6>>
			Soft.
		<<elseif $customSlave.muscles > -31>>
			Quite weak.
		<<elseif $customSlave.muscles > -51>>
			Rather weak.
		<<elseif $customSlave.muscles > -96>>
			Very weak.
		<<else>>
			Frail.
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveLips>>
%/
<<widget "CustomSlaveLips">>
	<<replace #lips>>
		<<if $customSlave.lips <= 10>>Thin lips.
		<<elseif $customSlave.lips <= 20>>Normal lips.
		<<elseif $customSlave.lips <= 40>>Plush lips.
		<<elseif $customSlave.lips <= 70>>Big lips.
		<<elseif $customSlave.lips <= 95>>Huge lips.
		<<else>>Facepussy.
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveVoice>>
%/
<<widget "CustomSlaveVoice">>
	<<replace #voice>>
		<<if $customSlave.voice == 3>>High, girly voice.
		<<elseif $customSlave.voice == 2>>Feminine voice.
		<<elseif $customSlave.voice == 1>>Deep voice.
		<<elseif $customSlave.voice == 0>>Mute.
		<<else>>Voice is unimportant.
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveHeight>>
%/
<<widget "CustomSlaveHeight">>
	<<replace #height>>
		<<if $customSlave.heightMod == "greatly below average">>Petite.
		<<elseif $customSlave.heightMod == "below average">>Short.
		<<elseif $customSlave.heightMod == "normal">>Average height.
		<<elseif $customSlave.heightMod == "above average">>Tall.
		<<else>>Very tall.
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveWeight>>
%/
<<widget "CustomSlaveWeight">>
	<<replace #weight>>
		<<if $customSlave.weight == -50>>Very thin.
		<<elseif $customSlave.weight == -15>>Thin.
		<<elseif $customSlave.weight == 0>>Average weight.
		<<elseif $customSlave.weight == 15>>Chubby.
		<<elseif $customSlave.weight == 50>>Plump.
		<<elseif $customSlave.weight == 100>>Fat.
		<<elseif $customSlave.weight == 150>>Very Fat.
		<<else>>Immobile.
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveFace>>
%/
<<widget "CustomSlaveFace">>
	<<replace #face>>
		<<if $customSlave.face < -40>>Very unattractive face.
		<<elseif $customSlave.face < -10>>Unattractive face.
		<<elseif $customSlave.face <= 10>>Average face.
		<<elseif $customSlave.face <= 40>>Attractive face.
		<<elseif $customSlave.face > 40>>Very attractive face.
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveRace>>
%/
<<widget "CustomSlaveRace">>
	<<replace #ethnicity>>
		<<textbox "$customSlave.race" $customSlave.race "Custom Slave">>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveSkin>>
%/
<<widget "CustomSlaveSkin">>
	<<replace #skin>>
		<<textbox "$customSlave.skin" $customSlave.skin "Custom Slave">>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveBoobs>>
%/
<<widget "CustomSlaveBoobs">>
	<<replace #boobs>>
		<<if $customSlave.boobs == 200>>Flat chest.
		<<elseif $customSlave.boobs <= 500>>Healthy breasts.
		<<elseif $customSlave.boobs <= 800>>Big breasts.
		<<elseif $customSlave.boobs <= 1400>>Huge breasts.
		<<elseif $customSlave.boobs <= 2100>>Giant breasts.
		<<else>>Massive breasts.
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveButt>>
%/
<<widget "CustomSlaveButt">>
	<<replace #butt>>
		<<if $customSlave.butt == 1>>Flat buttocks.
		<<elseif $customSlave.butt < 4>>Healthy buttocks.
		<<elseif $customSlave.butt < 6>>Huge buttocks.
		<<else>>Massive buttocks.
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveSex>>
%/
<<widget "CustomSlaveSex">>
	<<replace #sex>>
		<<if $customSlave.sex == 1>>Female (cock & balls options not applied).
		<<elseif $customSlave.sex == 2>>Male (pussy options not applied).
		<<else>>Futanari (clit options not applied).
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveVirgin>>
%/
<<widget "CustomSlaveVirgin">>
	<<replace #virgin>>
		<<if $customSlave.virgin == 0>>Vaginal virgin.
		<<else>>Virginity not important.
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveVagina>>
%/
<<widget "CustomSlaveVagina">>
	<<replace #vagina>>
		<<if $customSlave.vagina == -1>>No vagina.
		<<elseif $customSlave.vagina == 0>>Vaginal virgin.
		<<else>>Normal vagina.
		<</if>>
		<<link "No vagina">>
			<<set $customSlave.vagina = -1, $customSlave.preg = 0, WombFlush($activeSlave), $customSlave.ovaries = 0>>
			<<CustomSlaveVagina>>
		<</link>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveDick>>
%/
<<widget "CustomSlaveDick">>
	<<replace #dick>>
		<<if $customSlave.dick == 0>>No penis.
		<<elseif $customSlave.dick == 2>>Small penis.
		<<else>>Large penis.
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveBalls>>
%/
<<widget "CustomSlaveBalls">>
	<<replace #balls>>
		<<if $customSlave.balls == 0>>No testicles.
		<<elseif $customSlave.balls == 2>>Small testicles.
		<<elseif $customSlave.balls == 4>>Large testicles.
		<<else>>Huge Balls.
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveClit>>
%/
<<widget "CustomSlaveClit">>
	<<replace #clit>>
		<<if $customSlave.clit == 0>>Normal clitoris.
		<<elseif $customSlave.clit == 1>>Big clitoris.
		<<elseif $customSlave.clit == 3>>Enormous clitoris.
		<<else>>Pseudophallus.
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveLabia>>
%/
<<widget "CustomSlaveLabia">>
	<<replace #labia>>
		<<if $customSlave.labia == 0>>Normal labia.
		<<elseif $customSlave.labia == 1>>big labia.
		<<elseif $customSlave.labia == 2>>Huge labia.
		<<else>>Enormous labia.
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveClitBalls>>
%/
<<widget "CustomSlaveClitBalls">>
	<<replace #clitballs>>
	<<if $customSlave.dick > 0>>
	<<if $customSlave.balls == 0>>No testicles.<<elseif $customSlave.balls == 2>>Small testicles.<<else>>Large testicles.<</if>>
	<<link "No testicles">>
		<<set $customSlave.balls = 0,$customSlave.clit = 0>>
		<<CustomSlaveClitBalls>>
	<</link>>
	|
	<<link "Small testicles">>
		<<set $customSlave.balls = 2,$customSlave.clit = 0>>
		<<CustomSlaveClitBalls>>
	<</link>>
	|
	<<link "Large testicles">>
		<<set $customSlave.balls = 4,$customSlave.clit = 0>>
		<<CustomSlaveClitBalls>>
	<</link>>
	<<else>>
	<<if $customSlave.clit == 0>>Normal clitoris.<<elseif $customSlave.clit == 0>>Big clitoris.<<else>>Enormous clitoris.<</if>>
	<<link "Normal clitoris">>
		<<set $customSlave.clit = 0>>
		<<CustomSlaveClitBalls>>
	<</link>>
	|
	<<link "Big clitoris">>
		<<set $customSlave.clit = 1>>
		<<CustomSlaveClitBalls>>
	<</link>>
	|
	<<link "Enormous clitoris">>
		<<set $customSlave.clit = 2>>
		<<CustomSlaveClitBalls>>
	<</link>>

	<<if $customSlave.labia == 0>>Minimal labia.<<elseif $customSlave.labia == 1>>Normal labia.<<elseif $customSlave.labia == 2>>Huge labia.<<else>>Enormous labia.<</if>>
	<<link "Minimal labia">>
		<<set $customSlave.labia = 0>>
		<<CustomSlaveClitBalls>>
	<</link>>
	|
	<<link "Normal labia">>
		<<set $customSlave.labia = 1>>
		<<CustomSlaveClitBalls>>
	<</link>>
	|
	<<link "Huge labia">>
		<<set $customSlave.labia = 2>>
		<<CustomSlaveClitBalls>>
	<</link>>
	|
	<<link "Enormous labia">>
		<<set $customSlave.labia = 3>>
		<<CustomSlaveClitBalls>>
	<</link>>
	<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveLube>>
%/
<<widget "CustomSlaveLube">>
	<<replace #lube>>
		<<if $customSlave.vaginaLube == 0>>Dry vagina.
		<<elseif $customSlave.vaginaLube == 1>>Wet vagina.
		<<else>>Sopping wet vagina.
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveAnalVirginity>>
%/
<<widget "CustomSlaveAnalVirginity">>
	<<replace #anus>>
		<<if $customSlave.analVirgin == 0>>Anal virgin.
		<<else>>Anal virginity is not important.
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveAnus>>
%/
<<widget "CustomSlaveAnus">>
	<<replace #anus>>
		<<if $customSlave.anus == 0>>Anal virgin.
		<<else>>Normal anus.
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveSkills>>
%/
<<widget "CustomSlaveSkills">>
	<<replace #skills>>
		<<if $customSlave.skills <= 10>>Sexually unskilled.
		<<elseif $customSlave.skills <= 15>>Basic sex skills.
		<<else>>Sexually skilled.
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveWhoreSkills>>
%/
<<widget "CustomSlaveWhoreSkills">>
	<<replace #whoreskills>>
		<<if $customSlave.skill.whore <= 10>>Unskilled at prostitution and entertainment.
		<<elseif $customSlave.skill.whore <= 15>>Basic prostitution and entertainment skills.
		<<else>>Skilled at prostitution and entertainment.
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveCombatSkills>>
%/
<<widget "CustomSlaveCombatSkills">>
	<<replace #combatskills>>
		<<if $customSlave.skill.combat == 0>>Unskilled at combat.
		<<else>>Skilled at combat.
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveIntelligence>>
%/
<<widget "CustomSlaveIntelligence">>
	<<replace #intelligence>>
		<<if $customSlave.intelligence >= 3>>Brilliant.
		<<elseif $customSlave.intelligence == 2>>Very smart.
		<<elseif $customSlave.intelligence == 1>>Smart.
		<<elseif $customSlave.intelligence == 0>>Average intelligence.
		<<elseif $customSlave.intelligence == -1>>Stupid.
		<<elseif $customSlave.intelligence == -2>>Very stupid.
		<<else>>Moronic.
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveEducation>>
%/
<<widget "CustomSlaveEducation">>
	<<replace #education>>
		<<if $customSlave.intelligenceImplant >= 30>>Well educated.
		<<elseif $customSlave.intelligenceImplant >= 15>>Educated.
		<<else>>Uneducated.
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveNationality>>
%/
<<widget "CustomSlaveNationality">>
	<<replace #nationality>>
		Nationality: $customSlave.nationality.
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveEyes>>
%/
<<widget "CustomSlaveEyes">>
	<<replace #eyes>>
		<<if $seeExtreme == 1>>
			<<if $customSlave.eyes == -2>>Blind.
			<<elseif $customSlave.eyes == -1>>Nearsighted.
			<<else>>Normal.
			<</if>>
		<<else>>
			<<if $customSlave.eyes == -1>>Nearsighted.
			<<else>>Normal.
			<</if>>
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveEars>>
%/
<<widget "CustomSlaveEars">>
	<<replace #hears>>
		<<if $seeExtreme == 1>>
			<<if $customSlave.hears == -2>>Deaf.
			<<elseif $customSlave.hears == -1>>Hard of hearing.
			<<else>>Normal.
			<</if>>
		<<else>>
			<<if $customSlave.hears == -1>>Hard of hearing.
			<<else>>Normal.
			<</if>>
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveSmell>>
%/
<<widget "CustomSlaveSmell">>
	<<replace #smelling>>
		<<if $seeExtreme == 1>>
			<<if $customSlave.smells == -1>>None.
			<<else>>Normal.
			<</if>>
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveTaste>>
%/
<<widget "CustomSlaveTaste">>
	<<replace #tasting>>
		<<if $seeExtreme == 1>>
			<<if $customSlave.tastes == -1>>None.
			<<else>>Normal.
			<</if>>
		<</if>>
	<</replace>>
<</widget>>

/%
 Call as <<CustomSlaveAmp>>
%/
<<widget "CustomSlaveAmp">>
	<<replace #amputation>>
		<<if $customSlave.amp == 1>>Limbless.
		<<else>>Limbed.
		<</if>>
	<</replace>>
<</widget>>

/%
	Call as <<MarketName 'market' ['arcology']>>
	If $args[0] is undefined, will generate a kidnapper's market slave.
	If $args[0] is "corporate" and $args[1] is undefined, will use neighboring arcology 1.
%/
<<widget MarketName>>
<<if $args[0]>>
	<<set _market = $args[0]>>
<<else>>
	<<set _market = "kidnappers">>
<</if>>

<<switch _market>>
<<case "corporate">>
	your corporation
<<case "neighbor">>
	<<if $args[1]>>
		<<print $arcologies[$args[1]].name>>
	<<else>>
		<<print $arcologies[1].name>>
	<</if>>
<<case "kidnappers">>
	the Kidnappers' Market
<<case "indentures">>
	the Indentures Market
<<case "hunters">>
	the Runaway Hunters' Market
<<case "raiders">>
	the Raiders' Market
<<case "underage raiders">>
	the Raiders' Black Market
<<case "heap">>
	the Flesh Heap as alive as when you purchased them.
<<case "wetware">>
	the Wetware CPU market
<<case "trainers">>
	the Trainers' Market
<<case "TSS">>
	The Slavegirl School
<<case "GRI">>
	Growth Research Institute
<<case "SCP">>
	St. Claver Preparatory
<<case "LDE">>
	L'école des Enculées
<<case "TGA">>
	The Gymnasium-Academy
<<case "TCR">>
	The Cattle Ranch
<<case "TFS">>
	The Futanari Sisters
<<case HA>>
	The Hippolyta Academy
<<case NUL>>
	Nueva Universidad de Libertad
<<case "low tier criminals" "gangs and smugglers" "white collar" "military prison">>
	the prisoner sale
<<default>>
	Someone messed up. _market is not known.

<</switch>>
<</widget>>

/%
	Call as <<MarketNamePeriod 'market' ['arcology']>>
	If $args[0] is undefined, will generate a kidnapper's market slave.
	If $args[0] is "corporate" and $args[1] is undefined, will use neighboring arcology 1.
%/
<<widget MarketNamePeriod>>
<<if $args[0]>>
	<<set _market = $args[0]>>
<<else>>
	<<set _market = "kidnappers">>
<</if>>

<<switch _market>>
<<case "corporate">>
	your corporation.
<<case "neighbor">>
	<<if $args[1]>>
		<<print $arcologies[$args[1]].name>>.
	<<else>>
		<<print $arcologies[1].name>>.
	<</if>>
<<case "kidnappers">>
	the Kidnappers' Market.
<<case "indentures">>
	the Indentures Market.
<<case "hunters">>
	the Runaway Hunters' Market.
<<case "raiders">>
	the Raiders' Market.
<<case "underage raiders">>
	the Raiders' Black Market.
<<case "heap">>
	the Flesh Heap, alive and not dead.
<<case "wetware">>
	the Wetware CPU market.
<<case "trainers">>
	the Trainers' Market.
<<case "TSS">>
	The Slavegirl School.
<<case "GRI">>
	Growth Research Institute.
<<case "SCP">>
	St. Claver Preparatory.
<<case "LDE">>
	L'école des Enculées.
<<case "TGA">>
	The Gymnasium-Academy.
<<case "TCR">>
	The Cattle Ranch.
<<case "TFS">>
	The Futanari Sisters.
<<case HA>>
	The Hippolyta Academy.
<<case NUL>>
	Nueva Universidad de Libertad.
<<case "low tier criminals" "gangs and smugglers" "white collar" "military prison">>
	the prisoner sale.
<<default>>
	Someone messed up. _market is not known.

<</switch>>
<</widget>>

/%
 Call as <<JFCSlave>>
%/
<<widget "JFCSlave">>
	<<set $activeSlaveOneTimeMinAge = 20>>
	<<set $activeSlaveOneTimeMaxAge = 36>>
	<<set $one_time_age_overrides_pedo_mode = 1>>
	<<set $oneTimeDisableDisability = 1>>
	<<set $activeSlave = GenerateNewSlave("XX")>>
	<<set $activeSlave.weight = random(-30,20), $activeSlave.waist = random(-30,10), $activeSlave.face = random(40,60)>>
	<<if $activeSlave.faceShape == "masculine">>
		<<set $activeSlave.faceShape = "sensual">>
	<</if>>
	<<if $activeSlave.boobShape == "saggy" || $activeSlave.boobShape == "downward-facing">>
		<<set $activeSlave.boobShape = "perky">>
	<</if>>
	<<set $activeSlave.eyes = 1, $activeSlave.hears = 0, $activeSlave.voice = 2>>
	<<set $activeSlave.intelligenceImplant = 30, $activeSlave.intelligence = random(20,100)>>
	<<set $activeSlave.trust = 80, $activeSlave.devotion = 80>>
	<<set $activeSlave.health = random(80,95)>>
	<<set $activeSlave.origin = "The Job Fulfillment Center offered her contract to fill your request for a ">>
	<<set $activeSlave.origin += $Role>>
	<<set $activeSlave.origin += ".">>
	<<switch $Role>>
	/* Opens security */
		<<case "Lieutenant Colonel">>
			<<set $activeSlave.devotion = random(96,100), $activeSlave.trust = random(96, 100), $activeSlave.energy = random(96,100), $activeSlave.intelligence = 70, $activeSlave.skill.combat = 1>>
			<<set $activeSlave.career = either("a bodyguard", "a bouncer", "a bounty hunter", "a gang member", "a law enforcement officer", "a mercenary", "a prison guard", "a private detective", "a revolutionary", "a security guard", "a soldier", "a street thug", "a transporter", "an assassin", "an enforcer", "in a militia")>>
		<<case "Bodyguard">>
			<<set $activeSlave.devotion = 90, $activeSlave.muscles = random(30,70), $activeSlave.height = Math.round(Height.random($activeSlave, {skew: 3, spread: .2, limitMult: [1, 4]})), $activeSlave.weight = random(-10,10), $activeSlave.teeth = either("normal", "pointy"), $activeSlave.amp = either(-4, -4, 0, 0, 0, 0), $activeSlave.skill.combat = 1>>
			<<set $activeSlave.career = either("a bodyguard", "a kunoichi", "a law enforcement officer", "a military brat", "a revolutionary", "a soldier", "a transporter", "an assassin", "in a militia")>>
		<<case "Wardeness">>
			<<set $activeSlave.energy = random(80,100), $activeSlave.sexualFlaw = either("malicious", "none", "none", "none", "none"), $activeSlave.fetish = "sadist", $activeSlave.fetishStrength = 100, $activeSlave.muscles = random(50,80), $activeSlave.skill.combat = 1>>
			<<set $activeSlave.career = either("a bouncer", "a bounty hunter", "a gang member", "a mercenary", "a prison guard", "a private detective", "a security guard", "a street thug", "an enforcer")>>
			<<if $seeDicks > 0>>
				<<set $activeSlave.dick = random(3,6), $activeSlave.balls = random(3,6), $activeSlave.scrotum = $activeSlave.balls, $activeSlave.prostate = either(1,1,1,2,2,3)>>
			<</if>>
	/* Closes Security */
	/* Opens management */
		<<case "Headgirl">>
			<<set $activeSlave.devotion = 90, $activeSlave.trust = 100, $activeSlave.fetish = "dom", $activeSlave.fetishStrength = 100, $activeSlave.energy = random(70,90), $activeSlave.intelligence = random(60,100), $activeSlave.skill.entertainment = 100, $activeSlave.skill.whoring = 100, $activeSlave.skill.anal = 100, $activeSlave.skill.oral = 100, $activeSlave.skill.vaginal = 100, $activeSlave.career = either("a lawyer", "a military officer", "a politician")>>
			<<if $seeDicks > 0>>
				<<set $activeSlave.dick = random(3,5), $activeSlave.balls = random(3,6), $activeSlave.scrotum = $activeSlave.balls, $activeSlave.prostate = either(1,1,2)>>
			<</if>>
			<<set $activeSlave.vagina = random(3,4)>>
			<<if $AgePenalty == 1>>
				<<set $activeSlave.actualAge = random(36,$retirementAge-5)>>
			<<else>>
				<<set $activeSlave.actualAge = random(20,$retirementAge-5)>>
			<</if>>
			<<set $activeSlave.physicalAge = $activeSlave.actualAge, $activeSlave.visualAge = $activeSlave.actualAge, $activeSlave.ovaryAge = $activeSlave.actualAge>>
		<<case "Teacher">>
			<<set $activeSlave.fetish = "dom", $activeSlave.fetishStrength = 100, $activeSlave.energy = random(70,90), $activeSlave.intelligence = 100, $activeSlave.skill.entertainment = 100, $activeSlave.skill.whoring = 100, $activeSlave.skill.anal = 100, $activeSlave.skill.oral = 100, $activeSlave.skill.vaginal = 100, $activeSlave.face = random(41,90), $activeSlave.career = either("a librarian", "a principal", "a private instructor", "a professor", "a scholar", "a scientist", "a teacher", "a teaching assistant")>>
			<<if $seeDicks > 0>>
				<<set $activeSlave.dick = random(3,5), $activeSlave.balls = random(3,6), $activeSlave.scrotum = $activeSlave.balls, $activeSlave.prostate = either(1,1,1,2,2,3)>>
			<</if>>
			<<set $activeSlave.actualAge = random(36,$retirementAge-3)>>
			<<set $activeSlave.vagina = random(3,4)>>
			<<set $activeSlave.physicalAge = $activeSlave.actualAge, $activeSlave.visualAge = $activeSlave.actualAge, $activeSlave.ovaryAge = $activeSlave.actualAge>>
		<<case "Nurse">>
			<<set $activeSlave.fetish = "dom", $activeSlave.fetishStrength = 100, $activeSlave.muscles = random(6,50), $activeSlave.face = random(41,90), $activeSlave.sexualQuirk = "caring", $activeSlave.career = either("a doctor", "a medic", "a medical student", "a nurse", "a paramedic"), $activeSlave.intelligence = random(40,90)>>
		<<case "Motherly Attendant">>
			<<set $activeSlave.devotion = 90, $activeSlave.trust = 90, $activeSlave.fetish = "submissive", $activeSlave.fetishStrength = 100, $activeSlave.face = random(60,90)>>
			<<set $activeSlave.career = either("a counselor", "a dispatch officer", "a lifeguard", "a masseuse", "a psychologist", "a therapist"), $activeSlave.counter.birthsTotal = random(1,3), $activeSlave.pregKnown = 1, $activeSlave.preg = random(20,35), $activeSlave.pregWeek = $activeSlave.preg, $activeSlave.pregType = 1>>
			<<run SetBellySize($activeSlave)>>
			<<set $activeSlave.actualAge = random(36,$retirementAge-3)>>
			<<set $activeSlave.vagina = random(3,4)>>
			<<set $activeSlave.physicalAge = $activeSlave.actualAge, $activeSlave.visualAge = $activeSlave.actualAge, $activeSlave.ovaryAge = $activeSlave.actualAge>>
		<<case "Attendant">>
			<<set $activeSlave.devotion = 90, $activeSlave.trust = 90, $activeSlave.fetish = "submissive", $activeSlave.fetishStrength = 100, $activeSlave.eyes = either(-2, 1, 1), $activeSlave.preg = 0, $activeSlave.face = random(60,90), $activeSlave.career = either("a counselor", "a masseuse", "a therapist")>>
			<<set $activeSlave.actualAge = random(26,$retirementAge-3)>>
			<<set $activeSlave.physicalAge = $activeSlave.actualAge, $activeSlave.visualAge = $activeSlave.actualAge, $activeSlave.ovaryAge = $activeSlave.actualAge>>
		<<case "Matron">>
			<<set $activeSlave.devotion = 90, $activeSlave.trust = 90, $activeSlave.sexualQuirk = "caring", $activeSlave.eyes = 1, $activeSlave.counter.birthsTotal = random(2,4), $activeSlave.vagina = 3, $activeSlave.face = random(60,90), $activeSlave.career = either( "a nanny", "a practitioner")>>
			<<set $activeSlave.actualAge = random(24,$retirementAge-3)>>
			<<set $activeSlave.physicalAge = $activeSlave.actualAge, $activeSlave.visualAge = $activeSlave.actualAge, $activeSlave.ovaryAge = $activeSlave.actualAge>>
		<<case "Stewardess">>
			<<set $activeSlave.energy = random(70,90), $activeSlave.fetish = "dom", $activeSlave.fetishStrength = 100, $activeSlave.career = either("a barista", "a bartender", "a caregiver", "a charity worker", "a professional bartender", "a secretary", "a wedding planner", "an air hostess", "an estate agent", "an investor", "an office worker")>>
			<<if $AgePenalty == 1>>
				<<set $activeSlave.actualAge = random(36,$retirementAge-5)>>
			<<else>>
				<<set $activeSlave.actualAge = random(20,$retirementAge-5)>>
			<</if>>
			<<set $activeSlave.physicalAge = $activeSlave.actualAge, $activeSlave.visualAge = $activeSlave.actualAge, $activeSlave.ovaryAge = $activeSlave.actualAge>>
		<<case "Milkmaid">>
			<<set $activeSlave.muscles = random(31,60), $activeSlave.skill.oral = random(31,60), $activeSlave.sexualQuirk = "caring", $activeSlave.behavioralQuirk = "funny", $activeSlave.career = either("a cowgirl", "a dairy worker", "a milkmaid", "a farmer's daughter", "a shepherd", "a veterinarian"), $activeSlave.intelligence = random(20,70)>>
			<<if $seeDicks > 0>>
				<<set $activeSlave.dick = random(3,5), $activeSlave.balls = random(4,9), $activeSlave.scrotum = $activeSlave.balls, $activeSlave.prostate = either(1,1,1,2)>>
			<</if>>
		<<case "Farmer">>
			<<set $activeSlave.devotion = 80, $activeSlave.trust = 80, $activeSlave.health = random(80,95), $activeSlave.muscles = random(41,70), $activeSlave.sexualQuirk = "caring", $activeSlave.career = either("a farmer", "a farmer's daughter", "a rancher", "a farmhand", "a zookeeper"), $activeSlave.intelligenceImplant = 30, $activeSlave.intelligence = random(20,70), $activeSlave.height = Math.round(Height.random($activeSlave, {skew: 3, spread: .2, limitMult: [1, 4]})), $activeSlave.weight = random(0,30)>>
			<<if $seeDicks > 0>>
				<<set $activeSlave.dick = random(3,5), $activeSlave.balls = random(4,9), $activeSlave.scrotum = $activeSlave.balls, $activeSlave.prostate = either(1,1,1,2)>>
			<</if>>
			<<if $AgePenalty == 1>>
				<<set $activeSlave.actualAge = random(36,$retirementAge-5)>>
			<<else>>
				<<set $activeSlave.actualAge = random(20,$retirementAge-5)>>
			<</if>>
			<<set $activeSlave.physicalAge = $activeSlave.actualAge, $activeSlave.visualAge = $activeSlave.actualAge, $activeSlave.ovaryAge = $activeSlave.actualAge>>
	/* Closes management */
	/* Opens entertain */
		<<case "DJ">>
			<<set $activeSlave.skill.entertainment = 100, $activeSlave.muscles = random(6,30), $activeSlave.face = random(80,100), $activeSlave.career = either("a classical dancer", "a classical musician", "a dancer", "a house DJ", "a musician", "an aspiring pop star")>>
		<<case "Madam">>
			<<set $activeSlave.skill.whoring = 100, $activeSlave.career = either("a business owner", "a manager", "a pimp", "a procuress", "an innkeeper")>>
			<<if $seeDicks > 0>>
				<<set $activeSlave.dick = random(3,5), $activeSlave.balls = random(3,5), $activeSlave.scrotum = $activeSlave.balls, $activeSlave.prostate = either(1,1,1,2)>>
			<</if>>
			<<if $AgePenalty == 1>>
				<<set $activeSlave.actualAge = random(36,$retirementAge-5)>>
			<<else>>
				<<set $activeSlave.actualAge = random(20,$retirementAge-5)>>
			<</if>>
			<<set $activeSlave.physicalAge = $activeSlave.actualAge, $activeSlave.visualAge = $activeSlave.actualAge, $activeSlave.ovaryAge = $activeSlave.actualAge>>
		<<case "Concubine">>
			<<set $activeSlave.prestige = 3, $activeSlave.energy = random(80,100), $activeSlave.skill.entertainment = 100, $activeSlave.skill.whoring = 100, $activeSlave.skill.anal = 100, $activeSlave.skill.oral = 100, $activeSlave.skill.vaginal = 100, $activeSlave.face = 100, $activeSlave.devotion = random(90,95), $activeSlave.trust = random(90,100)>>
		/* Closes Entertain */
		<</switch>>
<</widget>>

/%
 % Shows controls for buying and advancing the queue for buying slaves from a school
 % Arguments: none
 % Call as <<buyingFromMarketControls>>
 %/
<<widget "buyingFromMarketControls">>

[["Decline to purchase " + $him + " and check out another slave"|passage()][$slavesSeen += 1]]
<<if $cash >= $slaveCost>>

[["Buy " + $him + " and check out other slaves to order"|passage()][cashX(forceNeg($slaveCost), "slaveTransfer", $activeSlave),$newSlaves.push($activeSlave), $introType = "multi", $slavesSeen+=1]]
	<<if $newSlaves.length == 0>>

[["Buy " + $his + " slave contract"|New Slave Intro][cashX(forceNeg($slaveCost), "slaveTransfer", $activeSlave),$nextButton = "Continue",$nextLink = "AS Dump",$returnTo = "Main"]]
	<<else>>

[["Buy " + $him + " and finish your order of slaves"|Bulk Slave Intro][cashX(forceNeg($slaveCost), "slaveTransfer", $activeSlave), $newSlaves.push($activeSlave)]]
	<</if>>
<<else>>

//You lack the necessary funds to buy this slave.//
<</if>>
<<if $newSlaves.length > 0>>

[[Finish your order of slaves|Bulk Slave Intro]]
<</if>>

<<if $slaveMarket != "indentures" && $slaveMarket != "neighbor" && $slaveMarket != "heap" && $slaveMarket != "wetware">>
	<<set $applyLaw = 1>>
<</if>>
<<set $saleDescription = 1>><<include "Long Slave Description">>
<</widget>>

/%
 % Shows controls for buying and advancing the queue for buying slaves from a school
 % Arguments:
 % 0: school
 % 1: name for a single slave ("slave", "cow", etc.)
 % 2: name for a bunch of them ("slaves", "cattle", etc.)
 % Call as <<buyingFromSchoolControls $TCR "cow" "cattle">>
 %/
<<widget "buyingFromSchoolControls">>

[["Decline to purchase " + $him + " and check out another " + $args[1]|passage()][$slavesSeen += 1]]
<<if $cash >= $slaveCost>>
	<<set _schoolToBuyFrom = $args[0]>>

[["Buy " + $him + " and check out other " + $args[2] + " to order"|passage()][cashX(forceNeg($slaveCost), "slaveTransfer", $activeSlave), _schoolToBuyFrom.schoolSale = 0, _schoolToBuyFrom.studentsBought += 1, $newSlaves.push($activeSlave), $introType = "multi", $slavesSeen+=1]]
	<<if $newSlaves.length == 0>>

[["Buy " + $his + " slave contract"|New Slave Intro][cashX(forceNeg($slaveCost), "slaveTransfer", $activeSlave), _schoolToBuyFrom.schoolSale = 0, _schoolToBuyFrom.studentsBought += 1, $nextButton = "Continue", $nextLink = "AS Dump", $returnTo = "Main"]]
	<<else>>

[["Buy " + $him + " and finish your order of " + $args[2]|Bulk Slave Intro][cashX(forceNeg($slaveCost), "slaveTransfer", $activeSlave), _schoolToBuyFrom.schoolSale = 0, _schoolToBuyFrom.studentsBought += 1, $newSlaves.push($activeSlave)]]
	<</if>>
<<else>>

//You lack the necessary funds to buy this $args[1].//
<</if>>
<<if $newSlaves.length > 0>>

[["Finish your order of " + $args[2]|"Bulk Slave Intro"]]
<</if>>

<<set $saleDescription = 1>><<include "Long Slave Description">>
<</widget>>


code:
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Desktop (please complete the following information):**
 - OS: [e.g. iOS]
 - Version [e.g. 22]
 - Commit: [e.g https://github.com/expanded-mod-team/RL-Expanded-Rewrite/commit/53366c33fe79e4e37d587729ba3f971a3d2ede46]

**Smartphone (please complete the following information):**
 - Device: [e.g. iPhone6]
 - OS: [e.g. iOS8.1]
 - Version [e.g. 22]
 - Commit: [e.g https://github.com/expanded-mod-team/RL-Expanded-Rewrite/commit/53366c33fe79e4e37d587729ba3f971a3d2ede46]

**Additional context**
Add any other context about the problem here.

repo_name: Kelfistan/renpy

license: unknown


code:
---
name: Feature request (Developers)
about: Suggest an specific feature for this project
title: "[DEV FRQ]"
labels: enhancement
assignees: ''

---

<!--- Please ensure your request retains "[USR FRQ] Request:" in it's title.  --->

<!--- All developers suggesting a feature must include a diagram of how this system will integrate --->
![Diagram Alt-Text]()

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe what is needed**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.


code:
---
name: Feature request Users
about: Suggest an idea for this project
title: "[USR FRQ] Request: Brief Descriptive Name"
labels: enhancement
assignees: ''

---

<!--- Please ensure your request retains "[USR FRQ] Request:" in it's title.  --->

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.


code:
---
name: ToDo
about: A specific task that needs to be accomplished
title: "[TODO] Task: Brief Descriptive Title"
labels: ''
assignees: ''

---

<!--- Please ensure your request retains "[TODO] Task:" in it's title.  --->

<!--- All developers must include a diagram illustrating where they believe a problem occurs.--->
![Diagram Alt-Text](image.png)

**Is your task related to a problem? Please describe.**
A clear and concise description of what the problem is.

**Describe what is needed**
A clear and concise description of what needs to be added/removed/modified or fixed.

**Describe potential approaches you've considered**
A clear and concise description of any alternative solutions you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.


code:
# Gitignore file | DO NOT REMOVE OR EDIT

# VS Code
.vscode/

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/

# Ren'py Projects
project.json
*.rpa
*.rpyc
*.jpeg
*.png
*.bak
/*.exe
/renpy/
/lib/
/game/cache/
/game/gui/
/game/images/
/game/saves/
/game/tl

# Ren'py Log Files
traceback.txt
log.txt
errors.txt

# UnRen specific ignores
unren
*.bat

# VScode and Testing
samplePytest.py
game/logging.txt
game/renpy_log.txt
/document-guide
renpy-trainer.code-workspace

path: .gitignore


code:
# INIT PRIORITY

Dependencies
    -1000

Common
    -900


code:
""" 01character.rpy
Trainer Character
"""

init -900 python in trainer:

    attr_max = None
    attr_min = None
    max_modifier = None
    attributes = []

    class Attribute(renpy.store.object):
        """
        A class to hold all information about a TRNCharacter attribute while returning a float when accessed.

        """
        # TODO: Determin how modifier works. https://gitgud.io/pervy-rogues/renpy-trainer/-/issues/147
        def __init__(self, value=0, **properties):
            self._value = value
            self._minimum = properties.pop('min', attr_min)
            self._maximum = properties.pop('max', attr_max)
            self._modifier = properties.pop('mod', 1)

        def _bind(self, value, maximum = attr_max, minimum = attr_min):
            if value >= maximum:
                return maximum
            elif value <= minimum:
                return minimum
            else:
                return value

        def __float__(self):
            try:
                if self._value.is_integer:
                    return float(self._value)
                elif self._value.is_float:
                    return self._value
                else:
                    raise ValueError
            except ValueError as e:
                raise e

        def __get__(self, obj, objtype=None):
            return self._value

        def __index__(self):
            return self.__float__()

        def __set__(self, obj, value):
            self._value = _bind(_bind(value), self._maximum, self._minimum)

        def __str__(self):
            return str(self._value)

        def __repr__(self):
            return self._value

        @property
        def minimum(self):
            return self._minimum

        @minimum.setter
        def minimum(self, value):
            self._minimum = _bind(value)
            return

        @property
        def maximum(self):
            return self._maximum

        @maximum.setter
        def maximum(self, value):
            self._maximum = _bind(value)
            return

        @property
        def modifier(self):
            return self._modifier

        @modifier.setter
        def modifier(self, value):
            if value < 0:
                value = 0
            if value > trainer.max_modifier:
                value = trainer.max_modifier
            self._modifier = value
            return

    @renpy.pure
    class TRNCharacter(renpy.store.ADVCharacter):
        """Represents a trainer character, based on ADVCharacter.
        """

        def __init__(self,
                    name=renpy.character.NotSet,
                    kind=None,
                    **properties):
            self.active = False
            self.inventory = properties.pop('inventory', [])
            self._real_name = name
            self.following = None
            self.home = properties.pop('home', None)
            self._last_location = None
            self.location = None
            self.nickname = properties.pop('nickname', None)
            self.party = []
            # NOTE: these 2 variables are not used anymore
            #self.pet_name = properties.pop('pet_name', None)
            #self.pet_names = properties.pop('pet_names', {})
            # NOTE: reletionships field is a list with other character name and a dict which contains relationship status + petname of that person
            self.relationships = properties.pop('relationships', [])
            self.traits = properties.pop('traits', [])
            #self._wardrobe = Wardrobe(self)
            self._flags = properties.pop('flags', [])

            # Specifies default kind as trn. Default values are stored in renpy.store.trn
            if kind is None:
                kind = store.trn

            # Dynamic takes in a condition to determine what name to display.
            if "dynamic" not in properties:
                properties["dynamic"] = False

            # Recieves stat names from kwargs or from a default value. Allows custom stat names for characters.
            if 'attributes' in properties:
                for attr in properties.get('attributes'):
                    a = Attribute(*attr)
                    setattr(self, attr.lower(), a)

            for attr in attributes: # Currently set to trainer_attributes, and NOT trainer.attributes
                if not hasattr(self, attr):
                    a = Attribute()
                    setattr(self, attr.lower(), a)

            if self.traits:
                for trait in self.traits:
                    self._apply_trait(trait)

            renpy.store.ADVCharacter.__init__(
                self,
                who = name,
                kind = kind,
                **properties)

        def _apply_trait(self, trait):
            '''Takes in a trait name (string) and applies that trait to TRNCharacter.'''
            # Only do this if there are attributes in the trait.
            if 'attributes' in trainer.traits[trait]:
                for attr in trainer.traits[trait]['attributes']:
                    # Apply minimum and maximums first

                    # Apply the modifier

                    # Finally, apply the bonus
                    pass
            return

        def add_trait(self, trait):
            ''' Takes in a trait name (string) and adds that trait to TRNCharacter.'''
            if trait in self.traits:
                renpy.log("(%t) is already in traits!" % trait)
                return
            else:
                self.traits.append(trait)
                self._apply_trait(trait)
            return

        def move(self, location):
            self._last_location = self.location
            self.location = location
            self._last_location.remove_person(self)
            self.location.add_person(self)
            return

        def add_flag(self, flag):
            self._flags.append(flag)

        def remove_flag(self, flag):
            self._flags.remove(flag)

        def is_flag_present(self, flag):
            return flag in self._flags

        def add_item(self, item):
            self.inventory.append(item)

        def remove_item(self, item):
            self.inventory.remove(item)

        def has_item(self, item):
            return item in self.inventory

        def get_items(self):
            # ???:Should i return copy of this list?
            return self.inventory

        # def add_relatonship(who, value):
        #     self.relationships[who]['value'] = value

        # def update_relationship(who, what, value):
        #     self.relationships[who][what] = value

        # def add_petname(name):
        #     try:
        #         self.pet_names[name[1]].append(name[0])
        #     except ValueError:
        #         renpy.log("Pet name type not found or not supplied.")

        # def change_petname(name):
        #     self.name = name

        # def reset_name():
        #     self.name = self._real_name

    # Default Trainer Character based on ADVCharacter
    trn = TRNCharacter(
            who_prefix='',
            who_suffix='',
            what_prefix='',
            what_suffix='',

            show_function=renpy.show_display_say,
            predict_function=renpy.predict_show_display_say,

            condition=None,
            dynamic=False,
            image=None,

            interact=True,
            slow=True,
            slow_abortable=True,
            afm=True,
            ctc=None,
            ctc_pause=None,
            ctc_timedpause=None,
            ctc_position="nestled",
            all_at_once=False,
            with_none=None,
            callback=None,
            type='say',
            advance=True,

            who_style='say_label',
            what_style='say_dialogue',
            window_style='say_window',
            screen='say', # say screen that we can change
            mode='say',
            voice_tag=None,

            kind=renpy.store.adv)

    renpy.store.Attribute = Attribute
    renpy.store.TRNCharacter = TRNCharacter
    renpy.store.trn = trn


code:
"""
    01events.rpy

    Houses the Event class and EventHandler class -- used for all forms of actions including dailies, repeatables, interactable events
    EventHandler has one instance and should keep track of ALL events regardless of where they are
"""

init -1000 python in trainer:
    import json
    import re

    # TODO: Rewrite all execeptions into a seperate file #189
    class EventInvalidKeyError(Exception):
        """
        Key is not an instance of string
        """
        pass

    class EmptyConditionsExceptions(Exception):
        """ There are no conditions in this event to meed requirements!"""
        pass

    class SameEventName(Exception):
        """ Event names/lables must be different one another! """
        pass

    class Event(renpy.store.object):

        def __init__(self, label, conditions, trigger, **kwargs):
            '''
            Event object that stores all the possible variables needed for all types of events and the required specifications
            '''
            self._label = label
            self._conditions = conditions
            self._cleared_conditions = [True] if (len(conditions) <= 0) else [False for i in range(len(conditions))]
            self._trigger = trigger
            self._id = None

            # Optional
            self._static = kwargs.get("static", False)
            self._repeatable = kwargs.get("repeatable", False)
            self._random = kwargs.get("random", False)
            self._weight = int(kwargs.get("weight", 0))
            self._weight_mod = 0
            self._special = kwargs.get("special", False)
            self._active = kwargs.get("active", False)
            self._complete = False
            self._interactable = kwargs.get("interactable", False)
            self._button_text = kwargs.get("button_text", None)
            self._incr_time = int(kwargs.get("incr_time", 0))
            if self._button_text is None:
                self._button_text = re.sub("_"," ", self._label).capitalize()
            self._tags = kwargs.get("event_tags", ['all'])

        def __str__(self):
            return f"Event object {self._label}, event_tags: {self.tags}, conditions: {self.conditions}, trigger: {self.trigger}"

        @property
        def label(self):
            return self._label

        @property
        def button_text(self):
            return self._button_text

        @property
        def weight(self):
            return self._weight + self._weight_mod

        @property
        def weight_mod(self):
            return self._weight_mod

        @property
        def incr_time(self):
            return self._incr_time

        @weight_mod.setter
        def weight_mod(self, mod):
            self._weight_mod = mod

        @property
        def id(self):
            return self._id

        @id.setter
        def id(self, id):
            self._id = id

        @property
        def tags(self):
            return self._tags

        @tags.setter
        def tags(self, tags):
            self._tags = tags

        def is_static(self):
            return self._static

        def is_interactable(self):
            return self._interactable

        def is_repeatable(self):
            return self._repeatable

        def is_random(self):
            return self._random

        def is_special(self):
            return self._special

        def is_active(self):
            return self._active

        def set_active(self, active):
            self._active = active

        def is_complete(self):
            return self._complete

        def set_complete(self, com):
            self._complete = com

        def update(self):
            """
            Iterates through all event conditions
            Checks if condition was already cleared, if yes, move on
            Uses *check_condition to see if condition has been cleared
                marks the index in self._cleared_conditions as True if it has been cleared
            """
            for i, condition in enumerate(self._conditions):
                if self._cleared_conditions[i]: continue
                if check_condition(condition): self._cleared_conditions[i] = True

        def is_triggered(self):
            """
            Returns boolean
            checks if the list of cleared_conditions are all true
            checks if self._trigger is true
            """
            return all(self._conditions) and check_condition(self._trigger)

    def check_condition(condition):
        try:
            return eval(condition)
        except SyntaxError as synErr:
            renpy_log.warning("You made a improper expression, look at the operators and variables to see if you structured properly")
            renpy_log.warning(str(synErr) + " in " + str(condition))
            return False
        except Exception as err:
            renpy_log.warning("Something went wrong updating event when checking condition")
            renpy_log.warning(str(err) + " in " + str(condition))
            return False

    class EventHandler(renpy.store.object):

        DEFAULT_WEIGHT = 25

        def __init__(self):
            self.__events = {}
            self.__active_events = {}
            self.__event_names = {}
            self.__queue_events = []

        def get_interact_events(self,tag):
            interact_events = []

            for evnt in self.__events[tag]:
                if evnt.is_interactable():
                    if evnt.is_triggered():
                        interact_events.append((evnt.button_text, (evnt, "event")))
            return interact_events

        def calculate_weighted_events(self, random_events):
            """
            Algorithem used to pick event based on event weights
            """
            if len(random_events) <= 0: return None
            tiers = {DEFAULT_WEIGHT: None}
            for evnt in random_events:
                if evnt.weight in tiers.keys():
                    tiers[int(evnt.weight)].append(evnt)
                else:
                    tiers[int(evnt.weight)] = [evnt]
            total_weight = 0
            for weight in tiers.keys():
                total_weight = total_weight + weight
            roll = renpy.random.randint(0, total_weight - 1)
            running_total = 0
            tier_keys = list(tiers.keys())
            tier_keys.sort()
            for i in range(len(tier_keys)):
                running_total = running_total + tier_keys[i]
                if roll < running_total:
                    rdm_evnt = renpy.random.choice(tiers[tier_keys[i]])
                    return (rdm_evnt)

        def update_events(self, *tags):
            """ updates certain events based on a tag"""
            # renpy_log.info(tags)
            # renpy_log.info( self.__events.keys())
            for event_tag in tags:
                if event_tag in self.__event_names():
                    self.__event_names[event_tag].update()
                    continue
                if event_tag not in self.__events.keys():
                    continue
                for evnt in self.__event[event_tag]:
                    evnt.update()
                    renpy_log.update
                    if evnt.is_triggered():
                        self.__queue_events.append(evnt)

        def play_triggered_events(self):
            events_to_play = []
            random_events = []
            for evnt in self.__queue_events:
                if evnt.is_random():
                    random_events.append(evnt)

            rdm_evnt = self.calculate_weighted_events(random_events)

            if rdm_evnt is not None:
                random_events.remove(rdm_evnt)
                for evnt in random_events:
                    evnt.weight_mod = (evnt.weight_mod + 5)
                rdm_evnt.weight_mod = 0
                play_event(rdm_evnt)

            self.__queue_events.clear()

        def add_event(self,event):
            #TODO look out for events with duplicate names
            self.__event_names[event.label] = event
            for event_tag in event.tags:
                if event_tag in self.__events.keys():
                    self.__events[event_tag].append(event)
                else:
                    self.__events[event_tag] = [event]

    def play_event(evnt):
        if renpy.has_label(evnt.label):
            game_clock.advance_time(actions = evnt.incr_time)
            # MUST BE LAST IN THE CODE LINE! Terminates any othe code line because control will be given to next statement
            renpy.call(evnt.label)
        else:
            renpy.call("no_event_label", evnt.label)
            renpy_log.info("Please change you ALSO created a label with dialouge with the same name as the event!")

    #### INITIALIZE EVENT_HANDLER
    event_handler = EventHandler()

    renpy.store.TEvent = Event
    renpy.store.TEventHandler = EventHandler
    renpy.store.play_tevent = play_event

init python early:
    import re

    def set_bool_param(l, param_dict, var_name):
        if l.keyword(var_name):
            param_dict[var_name] = True

    def set_string_param(l, param_dict, var_name):

        if l.keyword(var_name):
            param_dict[var_name] = l.string()

    def set_int_param(l, param_dict, var_name):

        if l.keyword(var_name):
            param_dict[var_name] = l.integer()

    def raiseStatParams(lex):
        stat_params = {}
        stat_params["name"] = lex.word()
        lex.skip_whitespace()
        init_param = lex.word()
        init_value = lex.integer()
        stat_params[init_param] = init_value
        while (not lex.eol()):
            param = lex.word()
            value = lex.integer()
            stat_params[param] = value
        return (stat_params)

    def parseRaiseStat(lex):
        lex.init_offset = 0
        return raiseStatParams(lex)

    def executeRaiseStat(stat_params):
        # Works! Except that the actor code needs to be handled with better care
        raiseStat(stat_params["name"], stat_params)

    def linRaiseStat(stat_params):
        # TODO: add better error check
        pass

    renpy.register_statement("raise stat", parse = parseRaiseStat, execute = executeRaiseStat, lint = linRaiseStat, block = False)

    """ Current form of renpy C.C.S - designed for ease of use for content and asset creators"""
    def check_event_params(l, event_params):
        event_params["conditions"] = []
        event_params["trigger"] = "True"
        while l.advance():

            for param in ("interactable", "static", "active", "repeatable", "random"):
                set_bool_param(l, event_params,param)

            for param in ("button_text","trigger"):
                set_string_param(l, event_params,param)

            for param in ("weight", "incr_time"):
                set_int_param(l, event_params, param)

            if l.keyword("event_tags"):
                tags = l.rest()
                tag_list = re.split(" ", tags)
                event_params["event_tags"] = tag_list

            if l.keyword('conditions'):
                ll = l.subblock_lexer()
                # Not really satisfied with nested while loop; will try to think of an alternative
                while(ll.advance()):
                    # description
                    # if ll.keyword("description"):

                    event_params['conditions'].append(ll.string())

        return event_params

    def parse_event(l):
        name = l.require(l.name)
        l.require(":")
        l.expect_eol()
        event_params = {}
        _label = re.sub('[ ]','_',re.sub('[()[\]{}+!@#$%^&*-]','',name)).lower()
        event_params["label"] = _label
        l.expect_block(f"Event block {_label} requires properties")
        return check_event_params(l.subblock_lexer(), event_params)

    def execute_event(event_params):
        try:
            new_event = Event(**event_params)
            global event_handler
            event_handler.add_event(new_event)
        except Exception as err:
            renpy_log.warning("********************************* ERROR EXCEPTION HANDLING 'execute_update_event *********************************")
            renpy_log.warning(err)
            renpy_log.warning(f"event_parameters -- {event_params}")
            renpy_log.warning("********************************* ERROR EXCEPTION HANDLING 'execute_update_event *********************************")

    # TODO: Improve error checking on event addition
    def lint_event(event_params):
        try:
            # event_params["label"]
            if len(event_params["conditions"]) <= 0:
                raise EmptyConditionsExceptions
            # checks for conditions
            for condition in event_params["conditions"]:
                renpy.try_eval("Creating An Event", conditions)
                eval(condition)
            # checks for trigger
            eval(event_params["trigger"])

        except EmptyConditionsExceptions:
            renpy.error("Please add conditions to the event!")
            renpy_log.warning("Please add conditions to the event!")
            event_params["conditions"].append(True)
        except Exception as err:
            renpy.error("Please fix the conditions -- non-empty string or proper expressions")
            renpy_log.warning("Please fix the conditions -- non-empty string or proper expressions")
            renpy_log.warning(err)

    renpy.register_statement("add event", parse = parse_event, lint = lint_event, execute = execute_event, block = True, )

    def parse_condition(l):
        sl = l.subblock_lexer()
        py_expressions = []
        while sl.advance():
            py_expressions.append(sl.simple_expression())
            # py_expressions.append(sl.string())

        return py_expressions

    def execute_condition(o):
        renpy_log.info(f"Renpy conditions: {o}")
        string_manipe = []
        for exp in o:
            # new_exp = re.sub("\W+| in | or | not | is | is not | not in | and | == | != | < | > | <= | >= ",',',exp)
            new_exp = re.sub("( and )|( in )|( not )|( or )|( is )|\W+",' ',exp)
            renpy_log.info(f"Object type: {exp}")
            renpy_log.info(f"FIXED Object type: {new_exp}")
            string_manipe.append(new_exp.split())

        renpy_log.info(f"String Manip: {string_manipe}")
    def l_cond(o):
        pass

    renpy.register_statement("py_cond", parse = parse_condition, lint = l_cond, execute = execute_condition, block = True)

    # EVENT UPDATE CCS (specific)

    def parse_event_update(l):
        event_tags = re.split(" ", l.rest())
        return event_tags

    def execute_update_event(tags):
        global event_handler
        event_handler.update_events(tags)

    def lint_update_event(tags):
        pass

    renpy.register_statement("update events", parse = parse_event_update, execute = execute_update_event, lint = lint_update_event)

    # LOCATION STATEMENT

        # def parse_location(l):
        #     location_name = l.delimited_python(":")
        #     return location_name

        # def execute_location(o):
        #     renpy.store
        #     pass

        # renpy.register_statement("new location", parse = , parse_location, execute = parse_location)


code:
"""
    01helpers.rpy

    This file contains globally accessible helper functions.
"""

init -2 python in trainer:

    ######################################################
    # Inventory functions:
    ######################################################

    def add_items(entity, items):
        if not isinstance(items, list):
            items = [items]

        for item in items:
            entity.add_item(item)

    def remove_items(entity, items):
        if not isinstance(items, list):
            items = [items]

        for item in items:
            try:
                entity.remove_item(item)
            except:
                # Should it throw exception?
                pass

    def has_items(entity, items):
        if not isinstance(items, list):
            items = [items]

        # Is this logic correct or should it return status of each item separated?
        for item in items:
            if not entity.has_item(item):
                return False

        return True

    def get_items(entity):
        return entity.get_items()

    def move_items(entity_from, entity_to, items):
        if has_items(entity_from, items):
            add_items(entity_to, items)
            remove_items(entity_from, items)
        else:
            # Would do something later (probably?).
            pass

    ######################################################
    # Flags functions:
    ######################################################

    def add_flag(entities, flag):
        if not isinstance(entities, list):
            entities = [entities]

        for entity in entities:
            if not is_flag_present(entity, flag):
                entity.add_flag(flag)

    def remove_flag(entities, flag):
        if not isinstance(entities, list):
            entities = [entities]

        for entity in entities:
            if is_flag_present(entity, flag):
                entity.remove_flag(flag)

    def is_flag_present(entities, flag):
        if not isinstance(entities, list):
            entities = [entities]

        for entity in entities:
            if not entity.is_flag_present(flag):
                return False

        return True

    def is_flag_present(entities, flag):
        if not isinstance(entities, list):
            entities = [entities]

        for entity in entities:
            if not entity.is_flag_present(flag):
                return False

        return True

    ######################################################
    # Character functions:
    ######################################################

    def trait_comparison(who, trait_1, trait_2):
        if getattr(who, trait_1) >= trait_2:
            return True
        else:
            return False

    def petname_check(who, petname):
        petname_info = store.self_petnames[petname]
        if trait_comparison(who, petname_info[0], petname_info[1]):
            return True
        else:
            return False

    def relationship_check(who, relationship):
        relationship_info = store.relationship_types[relationship]
        if trait_comparison(who, relationship_info[0], relationship_info[1]):
            return True
        else:
            return False

    def party_check(who, following, trait, requirement):
        """
        Function stub to check if character actually wants to follow someone else
        other characters may form their parties without any trait requirements (because they simply dont exist between other characters)
        """
        if trait == "no trait provided":
            # check in case if party is being created between other characters
            #TODO: change "mc" to actual main character
            #TODO: maybe add relationship requirement for this case
            if following is not mc:
                return True
            else:
                return False
        else:
            if trait_comparison(who, trait, requirement):
                return True
            else:
                return False

    ######################################################
    # Menu functions:
    ######################################################

    menu_set = list(set(menu_list))

    def fetch_entry(dynamic_entry, entry_list = menu_set):
        """ This function finds a dynamic_entry and returns it """

        de = dynamic_entry
        try:
            if not isinstance(de, DynamicEntry):
                de = [entry for entry in menu_list if entry.text == dynamic_entry]
            return de
        except ValueError:
            return False

    def build_menu(dynamic_entry):
        """ Builds a menu from the supplied Dynamic Entry node.

        Args:
            dynamic_entry: An object of DynamicEntry.

        Returns:
            list: A list of Dynamic_Entry objects.
        """
        menu_list = []

        for child in dynamic_entry.children:
            # Checks to condition to show menu entry.
            if child.condition is None or (child.condition is not None and renpy.python.py_eval(child.condition)):
                menu_list.append(child)

        return menu_list

    ######################################################
    # Party / Follower functions:
    ######################################################

    def follow(who, following, trait="no trait provided", requirement=-1):
        """ Causes a given character to follow another.

            Returns:
                bool: True/False on success
        """

        if party_check(who, following, trait, requirement) and (who.follow is not following):
            who.follow = following
            following.party.append(who)
            return True
        else:
            return False

    def is_following(who, follower):
        """ Checks if a given character is following another character.

            Returns:
                bool: is following
        """
        if who in following.party:
            return True
        else:
            return False

    def stop_following(who):
        """ Causes a given character to stop following another. """
        #TODO: Resolve if this will work.
        who.following.party.remove(who)
        who.following = None
        return

    def move_party_to_location(party, location):
        """ Moves a given list of characters to a specified location. """
        for who in party:
            if who.location is not location:
                who.move(location)
        return

    def remove_location_check(who, relationship):
        """ Checks if the given character will accept a command to move to a different location.

            Returns:
                bool: if relationship is high enough
        """
        if relationship_check(who, relationship):
            return True
        else:
            return False

    def remove_from_location(who, destination):
        """ Removes a character from a location if a relationship check is passed.

            Returns:
                bool: if character is removed
        """
        if remove_location_check(who):
            stop_following(who)
            who.move(who, destination)
            return True
        else:
            return False

    ######################################################
    # Test functions to treat nested lists like dicts
    ######################################################

    def give_contains(list, searchable):
        for x in list:
            if x[0] == searchable:
                return x[1]

    def give_index(list, searchable):
        for idx, x in enumerate(list):
            if x[0] == searchable:
                return idx


code:
"""
    01locations.rpy

    Location Class allows for quick creation of new locations.
"""
init -900 python in trainer:
    import re

    class Location(renpy.store.object):
        def __init__(self, name, adjacent, **kwargs):
            self._name = name # Full capitalization and spacing allowed; used for menus, text, and dialogue
            self.trimmed = re.sub('[ ]','_',re.sub("[']",'',self.name)).lower() # Used for variable name, code reference

            self.people = []
            self.day_cycle = kwargs.get('day_cycle', False)
            self.variants = kwargs.get('variants', [])
            self.locked = kwargs.get('locked', False)
            self.path = kwargs.get('path', "/images/backgrounds/")
            self.public = kwargs.get('public', 100)
            self.inventory = kwargs.get('inventory', [])

            # Replaces any spaces with underscores and forces lowercase on the string
            # for use as a jump to label. This will be used as the format for location labels.
            self.jump_to = [re.sub('[ ]','_',re.sub("[']",'',loc)).lower() for loc in adjacent]
            # Iterate through adjacent, create a tuple, and append to self.adjacent
            self.adjacents = [(adjacent[i], (self.jump_to[i], "location")) for i in range(0, len(adjacent))]
            # Add a leave line at the end.
            self.adjacents.append(("Don't go anywhere",(self.trimmed, "location")))

            # Defines renpy images for location background based on if the location has
            # time variants or not
            if self.day_cycle:
                renpy.image("bg {}_{}".format(self.trimmed,"day") ,"{}{}_{}.png".format(self.path,self.trimmed,"day"))
                renpy.image("bg {}_{}".format(self.trimmed,"evening") ,"{}{}_{}.png".format(self.path,self.trimmed,"evening"))
                renpy.image("bg {}_{}".format(self.trimmed,"night") ,"{}{}_{}.png".format(self.path,self.trimmed,"night"))

            else:
                renpy.image("bg {}".format(self.trimmed) ,"{}{}.png".format(self.path,self.trimmed))
            # used for special variations for events
            if len(self.variants) > 0:
                for variant in self.variants:
                    renpy.image("bg {}_{}".format(self.trimmed, variant), "{}{}_{}.png".format(self.path,self.trimmed,variant))
        @property
        def name(self):
            return self._name

        @property
        def label(self):
            return self.trimmed

        # @property
        # def background(self):
        #     """ Returns background image based on time of day.
        #     Returns:
        #         string: Proper renpy image name.
        #     """
        #     if self.day_cycle:
        #         return "bg {}_{}".format(self.trimmed,current_time.lower())
        #     else:
        #         return "bg {}".format(self.trimmed)
        # @property
        # def bg(self):
        #     self.background

        # @property
        # def locked(self):
        #     return self.locked

        # @locked.setter
        # def locked(self, locked):
        #     try:
        #         self._locked = bool(locked)
        #     except TypeError:
        #         devlog.warning("Not boolean at setter (locked)")
        #     else:
        #         self._locked = False

        def get_adjacents(self):
            return self.adjacents

        def clear_location(self):
            self.people.clear()

        def remove_person(self, person):
            self.people.remove(person)

        def add_person(self, person):
            self.people.append(person)

        def get_people(self):
            return self.people

        def has_person(self, person):
            return (person in self.people)

        def add_item(self, item):
            self.inventory.append(item)

        def remove_item(self, item):
            self.inventory.remove(item)

        def has_item(self, item):
            return item in self.inventory

        def get_items(self):
            # ???:Should i return copy of this list?
            return self.inventory

    '''
    Gives all possible menu options relating to location including:
        static location events,
        chat with people,
        adjacent locations,
        miscalleaneos: WAIT, LEAVE(GOTO MAIN HUB --> I.E UNIVERSITY SQUARE)
    '''
    def location_menu(location):
        loc_menu = []
        for person in location.get_people():
            loc_menu.append(("Talk to " + person.name, (person, "talk_to")))
        if travel_mode:
            loc_menu.extend(travel_menu)
        else:
            loc_menu.extend(location.get_adjacents())
        return loc_menu

    renpy.store.Location = Location


code:
"""
    01menu.rpy
    Adds a dynamic menu system to Ren'Py.
"""

init -1000 python in trainer:

    menu_list = []

    class DynamicEntry(renpy.store.object):
        """
            DynamicEntry is a node for the dynamic menu system. When spawned, the DynamicEntry is added to it's designated parent and tag lists.
        """
        def __init__(self, name=None, caption=None, condition=None, actions=[], kind='entry', **properties):
            self.name = name
            self.caption = caption
            self.actions = actions
            self.condition = condition
            self.kind = kind
            self.children = properties.get("children", [])
            self.text = properties.get("text", None)
            self.label = properties.get("label", None)
            self._menu_list = properties.get("menu_list", None)

            if self.name is not None and self.caption is None:
                self.caption = self.name

            if self.name is not None and self.text is None:
                self.text = self.name

            if properties.get("parents",[]):
                for parent in properties["parents"]:
                    if isinstance(parent, DynamicEntry):
                        parent.children.append(self)
                    else:
                        self._menu_list[parent].append(self)

        def execute(self):
            pass

        @property
        def say(self):
            if self.kind == "menu":
                return self._caption
            else:
                return None

        # TODO: Add method to sort children

        # def __call__(self):
        #     """ Causes the object to return a value like a function. """
        #     pass

    renpy.store.menu_list = menu_list
    renpy.store.DynamicEntry = DynamicEntry

init 1 python in trainer:
    '''Removes any duplicated items a creator may have missed.'''
    menu_set = list(set(menu_list))

label game_menu(dynamic_entry=None, style='trainer', entry_list=trainer.menu_set):
    # Displays the screen game_menu unless supplied a DynamicMenu.

    $ de = trainer.fetch_entry(dynamic_entry, entry_list)

    if (de is not None and isinstance(de, DynamicEntry)):
        jump expression dynamic_menu(de)

    call screen game_menu(de)
    jump expression game_menu(de)

label dynamic_menu(dynamic_entry=None, entry_list=trainer.menu_set):
    #   Calls proper screen based on entry.

    #   Args:
    #       dynamic_entry: An object of DynamicEntry or list containing DynamicEntry objects.
    #       style: An override for the style of the screen called by this function.

    $ de = fetch_entry(dynamic_entry, entry_list)

    if (de is None or not isinstance(de, DynamicEntry)):
        jump expression game_menu(de)

    if de.kind is "menu":
        call screen dynamic_choice(de, entry_list)
    elif de.kind is "interaction":
        call screen dynamic_interaction(de, entry_list)
    elif de.kind is "location":
        call screen dynamic_location(de, entry_list)
    elif de.kind is "sex":
        call screen dynamic_sex(de, entry_list)
    else:
        call screen dynamic_choice(de, entry_list)

    jump game_menu


code:
"""
    01outfit.rpy

    Clothing
    Outfit
    Wardrobe
"""
init offset = -900

python in trainer:
    import re

    clothing_price = 0

    class Clothing(renpy.store.object):
        """ Clothing is a data object for a paperdoll layer image. """
        def __init__(self, name, layer, **properties):
            self._name = name
            self._layer = layer
            self._kind = properties.get("kind", None)
            self._price = properties.get("price", clothing_price)
            self._shame = properties.get("shame", 0)
            self._hides = properties.get("hides", None)
            self._covers

            # Uses name for the image unless specified
            if "image" in properties:
                self._image = properties["image"]
            else:
                # RegEx to standardize the image string
                self._image = re.sub('[ ]','_',re.sub("[']",'',name)).lower()

        def __unicode__(self):
            what = self._name
            return renpy.substitutions.substitute(what)[0]

        def __str__(self):
            return unicode(self).encode("utf-8")

        def __format__(self, spec):
            return format(unicode(self), spec)

        def __repr__(self):
            return "<Clothing: {!r}>".format(self._name)

    class Outfit(renpy.store.object):
        """ Outfit is a complete paperdoll minus the character image. """
        def __init__(self, name, clothes = {}, kind = None, character = None, **properties):
            self._name = name
            self._clothes = clothes
            self._kind = kind

            # If no clothes are present, the character is 'Nude'
            if not self._clothes:
                self._kind = "nude"
            # If no outfit type is specified, just identify it as an 'Outfit'
            if self._kind is None:
                self._kind = "outfit"

            self._shame = self._calculate_shame()

        # TODO: Must figure out which clothing is shameful #155
        def _calculate_shame(self):
            """ Calculates a shame value based on items in clothes. """
            return 0

        def __unicode__(self):
            what = self._name
            return renpy.substitutions.substitute(what)[0]

        def __str__(self):
            return unicode(self).encode("utf-8")

        def __format__(self, spec):
            return format(unicode(self), spec)

        def __repr__(self):
            return "<Outfit: {!r}>".format(self._name)

        @property
        def kind(self):
            return self._kind

        @property
        def shame(self):
            return self._shame

    named_outfit_types = []
    default_outfit = ("uniform", Outfit("default_outfit"))

    class Wardrobe(renpy.store.object):
        """ Wardrobe holds and manages the Outfits and Clothes of a Character. """
        def __init__(self, character, **properties):
            self._character = character
            self._clothes = []
            self._outfits = []

            for kind in named_outfit_types:
                setattr(self, kind, properties.get(kind, None))

            if default_outfit:
                setattr(self, default_outfit[0], default_outfit[1])

        @property
        def outfits(self):
            return self._outfits


code:
""" 01paperdoll.rpy
    Creates and displays a compiled character image.
"""
init offset = -900

python early in paperdoll:

    # Taken from Ren'Py format_function(), 00layeredimage.rpy
    def format_function(what, name, group, variant, attribute, image, image_format, **kwargs):

        if image is None:

            if name is None:
                raise Exception("Can't find an image name to format {}.".format(what))

            if attribute is None:
                raise Exception("Can't find an attribute name to format {}.".format(what))

            parts = [ name ]

            if group is not None:
                parts.append(group)

            if variant is not None:
                parts.append(variant)

            parts.append(attribute)

            image = "_".join(parts)

        if isinstance(image, basestring) and (image_format is not None):
            image = image_format.format(name=name, image=image)

        return image

    # Taken from Ren'Py Layer, 00layeredimage.rpy
    class Layer(object):

        def __init__(self, at=[ ], layer=None, group_args={}, **properties):

            if not isinstance(at, list):
                at = [ at ]

            self.at = at
            self.group_args = group_args
            self.transform_args = properties

        def check(self, attributes):
            #TODO: Write a check function.
            pass

        def wrap(self, d):
            """
            Wraps a displayable in the at list and transform arguments.
            """

            d = At(d, *self.at)

            if self.group_args or self.transform_args:
                d = Transform(d)

                for k, v in self.group_args.items():
                    setattr(d, k, v)

                for k, v in self.transform_args.items():
                    setattr(d, k, v)

            return d

    class Attribute(Layer):

        def __init__(self, name, layer):

            super(Attribute, self).__init__(group_args=group_args, **properties)

    # Taken from Ren'Py Layered Image, 00layeredimage.rpy
    class Paperdoll(object):

        def __init__(self, attributes, at=[], name=None, **properties):

            self.name = name
            self.offer_screen = properties.pop('offer_screen', None)

            self.attributes = properties.pop(attributes, [])
            self.layers = [ ]
            self.groups = [ ]

            # import collections
            # self.attribute_to_groups = collections.defaultdict(set)
            # self.group_to_attributes = collections.defaultdict(set)

            for i in attributes:
                #TODO: add poses
                pass

            if not isinstance(at, list):
                at = [ at ]

            self.at = at

            properties.setdefault("xfit", True)
            properties.setdefault("yfit", True)

            self.transform_args = {k : properties.pop(k) for k, v in list(properties.items()) if k not in (renpy.sl2.slproperties.position_property_names + renpy.sl2.slproperties.box_property_names)}
            self.fixed_args = properties

        def get_banned(self, attributes):
            """
            Get the set of attributes that are incompatible with those
            in attributes.
            """

            rv = set()

            for i in attributes:
                for g in self.attribute_to_groups[i]:
                    for j in self.group_to_attributes[g]:
                        if j != i:
                            rv.add(j)
            return rv

        def add():
            pass

        def build_group(rv, group, attributes):
            active = [ ]

        def _duplicate(self, args):

            name = " ".join(args.name + tuple(args.args))

            attributes = set(args.args)

            rv = Fixed(**self.fixed_args)

            offer_screen = self.offer_screen
            if offer_screen is None:
                offer_screen = config.layeredimage_offer_screen
            if offer_screen:
                rv._offer_size = (config.screen_width, config.screen_height)

            for g in self.groups:
                self.build_group(rv, g, attributes)

            rv = At(rv, *self.at)

            if self.transform_args:
                rv = Transform(child=rv, **self.transform_args)

            return rv

        def _list_attributes(self, tag, attributes):
            pass

        def _choose_attributes(self, tag, required, optional):
            pass


code:
""" 01phone.rpy
"""

init -900 python in trainer:
    from collections import namedtuple

    Phone_Button = namedtuple('Phone_Button', ['name', 'image'])


code:
init -1 python in trainer:

    import renpy.store as store

    def change_relationship(person_1, person_2, relationship):
        relationship_info = store.relationship_types[relationship]
        if getattr(person_1, relationship_info[0]) >= relationship_info[1]:
            person_1.relationships[give_index(person_1.relationships, person_2)][1]["relationship"] = relationship
            person_2.relationships[give_index(person_2.relationships, person_1)][1]["relationship"] = relationship
            return True
        else:
            return False

    def change_own_petname(person_1, person_2, petname):
        petname_info = store.self_petnames[petname]
        if petname_check(person_1, petname):
            person_2.relationships[give_index(person_2.relationships, person_1)][1]["petname"] = petname
            return True
        else:
            return False

    def change_others_petname(person_1, person_2, petname):
        petname_info = store.others_petnames[petname]
        if petname_check(person_1, petname):
            person_1.relationships[give_index(person_1.relationships, person_2)][1]["petname"] = petname
            return True
        else:
            return False

    def reset_own_petname(person_1, person_2):
        if person_2.relationships[give_index(person_2.relationships, person_1)][1]["petname"] == person_1._real_name:
            return False
        else:
            person_2.relationships[give_index(person_2.relationships, person_1)][1]["petname"] = person_1._real_name
            return True

    def reset_others_petname(person_1, person_2):
        if person_1.relationships[give_index(person_1.relationships, person_2)][1]["petname"] == person_2._real_name:
            return False
        else:
            person_1.relationships[give_index(person_1.relationships, person_2)][1]["petname"] = person_2._real_name
            return True


code:
"""
    01scheduler.rpy

"""

init -900 python in trainer:

    # Puts all locations in dictionary list for reference
    def initialize_locations(*locations):
        for location in locations:
            trainer.locations[location.name] = location

    # Puts all characters in dictionary list for reference
    def initialize_characters(*characters):
        for character in characters:
            trainer.characters[character.name] = character

    def set_player_location(location):
        trainer.player_prev_location = trainer.player_location
        trainer.player_location = location
        if location.name not in trainer.player_visited_lcations:
            trainer.player_visited_lcations.append(location.name)

    def schedule_characters(day, time_of_day):
        """ Main method that puts all characters in a location in a certain time in a certain day with respect to schedules
        day -- the current day
        time_of_day -- current time of the day

        Method should be called with every progres_time() SEE: time-system
        """
        for k, v in trainer.characters:
            put_to_location(v, day, time_of_day)

    # ??? Is this the best way to go about this order?
    def put_to_location(character, day, time_of_day):
        schedule = character.get_schedule()
        location = trainer.locations[schedule[day][time_of_day]]
        location.add_person(character)
        character.current_location(location)

    # TODO possible methods for events to be updated when characters shuffle around in locations
    def location_update():
        pass

    # TODO should update both character and location
    def character_update():
        pass


code:
"""
    01screens.rpy
    This file has the pre-built screen elements to interact with renpy-trainer.
"""

screen get_clothes(who, kind):
    style_prefix trainer.gui_prefix + "wardrobe"

    # viewport mousewheel "change":
        # for clothing in who.clothes[kind]:
            # imagebutton [clothing.image] action Function(who.select_clothing(kind, clothing))

screen clothing_list(who):
    style_prefix trainer.gui_prefix + "wardrobe"

    # viewport "horizontal-change":
    #     for key,value in who.clothing:
    #         use screen get_clothes(who, key)

define image_size = (203, 190*2)

# style vertical_menu_frame:
#     background Solid("#000000")

screen vertical_menu(_type = "image", commands = [], size = image_size, show_scroll = "vertical"):
    style_prefix "vertical_menu"
    frame:
        viewport maximum size:

            draggable True
            mousewheel True
            scrollbars show_scroll
            has vbox

            for command in commands:

                if _type == "image":

                    imagebutton auto "test_button0_%s.png" action Jump("test_start")
                    imagebutton auto "test_button1_%s.png" action Jump("test_start")
                    imagebutton auto "test_button2_%s.png" action Jump("test_start")
                elif _type == "text":
                    frame background Frame("xmen_background.png") xminimum size[0]:
                        textbutton [str(command)] action Jump("test_start")
                else:
                    text "PLEASE SPECIFY VERTICAL MENU '_type'"

screen movable_frame(pos):
    drag:
        pos pos

        frame:
            # background Frame("movable_frame.png", 10, 10)
            top_padding 20

            transclude