code:
# Useful Functions

## Assay Functions

```js
isSlim(slave) // Returns if slave is considered slim or not by arcology standards.

isStacked(slave) // Returns if slave is considered stacked (big T&A) or not.

isModded(slave) // Tallies a slave's tats and piercings and returns if slave is considered heavily modded or not.

isUnmodded(slave) // Returns if slave is (relatively) unmodded. Some leeway.

isXY(slave) // Returns if a slave has a dick. (This needs review, it's far outdated for what it is used for.)

isPreg(slave) // Returns if a slave looks pregnant.

isNotPreg(slave) // Returns if slave has no sizable belly.

isPure(slave) // Returns if slave has not been surgically enhanced (to a noticeable degree).

isSurgicallyImproved(slave) // Returns if slave has been surgically enhanced with boob, butt and lip implants and also has a small waist.

PiercingScore(slave) // Returns int representing degree of piercings. Higher means more piercings.

TatScore(slave) // Returns int representing degree of tattooing. Higher means more tattoos.

canImproveIntelligence(slave) // Returns if slave intelligence can be improved with Psychostimulants

canImproveHeight(slave) // Returns if slave height can be improved with growth stimulants

sameAssignmentP(slave, slave) // Returns if slaves are on the same assignment.

haveRelationshipP(slave1, slave2) // Returns if slave1 is in a relationship with slave2.

isRivalP(slave1, slave2) // Returns if slave1 is in a rivalry with slave2.

supremeRaceP(slave) // Returns if slave is of the superior race. (Should only be used in conjunction with racial supremacy.)

inferiorRaceP(slave) // Returns if slave is of the inferior race. (Should only be used in conjunction with racial subjugation.)

isLeaderP(slave) // Returns if slave is in a leadership assignment.

isMotherP(slave1, slave2) // Returns if slave2 is slave1's mother.

isFatherP(slave1, slave2) // Returns if slave2 is slave1's father.

isParentP(slave1, slave2) // Returns if slave2 is either of slave1's parents.

sameDad(slave1, slave2) // Returns if slave1 and slave2 have the same father.

sameMom(slave1, slave2) // Returns if slave1 and slave2 have the same mother.

areTwins(slave1, slave2) // Returns if slave1 and slave2 are twins.

areSisters(slave1, slave2) // Returns sister status of slave1 and slave2 (1 // twins, 2 // sisters, 3 // half-sisters)

areRelated(slave1, slave2) // Returns if slave1 and slave2 are related.

totalRelatives(slave) // Returns the number of relatives slave has.

mutualChildren(slave1, slave2) // Returns if slave1 and slave2 have children together.

isSlaveAvailable(slave) // Returns if slave is available and not confined someplace.

assignmentVisible(slave) // Returns whether a slave's current assignment is shown in Main. Often used as a proxy for "penthouse slave".

randomRelatedSlave(slave) // Returns a random relative of slave if possible.

randomRelatedAvailableSlave(slave) // Returns a random available relative of slave if possible.

randomSister(slave) // Returns a random sister of slave if possible.

randomTwinSister(slave) // Returns a random available twin of slave if possible.

randomAvailableSister(slave) // Returns a random available sister of slave if possible.

randomDaughter(slave) // Returns a random child of slave if possible.

randomDaughter(slave) // Returns a random available child of slave if possible.

randomParent(slave) // Returns a random parent of slave if possible.

randomAvailableParent(slave) // Returns a random available parent of slave if possible.

totalPlayerRelatives(PC) // Returns the number of relatives the player has.

isSexuallyPure(slave) // Returns if the slave has (possibly) never had sex.

canGetPregnant(slave) // If the slave is fucked right now, could she get pregnant?

canBreed(slave1, slave2) // Returns if slave1 and slave2 are capable of breeding with each other.

canImpreg(slave1, slave2) // Returns if slave2 can impregnate slave1. PC works as an argument as well.

canFemImpreg(slave1, slave2) // Returns if slave2 can squirt cum and impregnate slave1. Assumes a slave does not have a dick. PC works as an argument as well.

isFertile(slave) // Returns if the actor is capable of having children.

canAchieveErection(slave) // Returns if the slave can get an erection. (Not blocked by chastity.)

canPenetrate(slave) // Returns if the slave can penetrate successfully.

canSee(slave) // Returns if the slave can see.

canHear(slave) // Returns if the slave can hear.

canSmell(slave) // Returns if the slave can smell.

canTaste(slave) // Returns if the slave can taste.

canHold(slave) // Returns if the slave can use both arms.

canWalk(slave) // Returns if the slave can walk unassisted.

canStand(slave) // Returns if the slave can stand unassisted.

canMove(slave) // Returns if the slave is capable of moving themselves.

isHindered(actor) // Returns if the actor's movement is impeded for any reason.

canTalk(slave) // Returns if the slave can talk.

canDoAnal(slave) // Returns if the slave can currently have anal sex.

canDoVaginal(slave) // Returns if the slave can currently have vaginal sex.

tooFatSlave(slave) // Returns if the slave is too fat to move.

tooBigBreasts(slave) // Returns if the slave's breasts are too big for her to move.

tooBigBelly(slave) // Returns if the slave's belly is too big for her to move.

tooBigBalls(slave) // Returns if the slave's balls are too big for her to move.

tooBigDick(slave) // Returns if the slave's dick is too big for her to move.

tooBigButt(slave) // Returns if the slave's butt is too big for her to move.

milkAmount(slave) // Returns the slave's expected milk output in liters.

App.Facilities.Farmyard.foodAmount(slave) // Returns the slave's expected food output in kilograms.

cumAmount(slave) // Returns the slave's expected cum output in deciliters.

isVegetable(slave) // Returns if the slave is mindbroken.

overpowerCheck(slave, PC) // Returns an integer that represents the chance of a slave overpowering the player.

canLift(actor1, actor2) // Returns if actor2 is capable of picking up and carrying actor1.

heelLength(slave) // Returns the length of a slave's heels should she be wearing any
```

## Player Functions

```js
onBedRest(actor) // Returns if the actor is on mandatory bedrest or just incapable of leaving their bed. (Mostly for player use.)
```

## Display Functions

```js
properTitle() // Returns the player's proper title. (customTitle, Sir, Ma'am)

properMaster() // Returns the slave's title for Master when WrittenMaster() is inappropriate. (customTitle, Master, Mistress)

WrittenMaster(slave) // Returns a slave's title for the player and sets lisping. Returns $activeSlave if not given an argument.

Spoken(slave, speech) // Returns speech with lisp if slave lisps. Replaces `<<say>>s` with Spoken(slave, "says").

SlaveFullName(slave) // Returns the slave's full name.

PlayerName() // Returns the player's full name.

PCTitle() // Returns the player's full title.

PoliteRudeTitle(slave) // Returns the slave's title for the player they hate.

SlaveTitle(slave) // Returns the slave's descriptive title.

relativeTerm(slave1, slave2) // Returns the term for slave2's relation to slave1. (daughter, mother, etc.)

vaginaDesc(slave) // Returns the description of the slave's vagina.

dickDesc(slave) // Returns the description of the slave's penis.

ballsDesc(slave) // Returns the description of the slave's testicles.

clitDesc(slave) // Returns the description of the slave's clitoris.

anusDesc(slave) // Returns the description of the slave's anus.

boobsDesc(slave) // Returns the size descriptor of the slave's breasts.

boobsDescLong(slave) // Returns the full description of the slave's breasts.

buttDesc(slave) // Returns the description of the slave's bottom.

lipsDesc(slave) // Returns the description of the slave's lips.

bellyDesc(slave, withNoun, pregReference) // Returns the description of the slave's belly.

penetrationTool(slave, includeClit) // Returns the description of the part of body that a slave/PC uses to penetrate, if he can, or a description for his dildo.

relationshipChecks [script] All work as expected with <<if X.rivalryTarget == $slaves[$i].ID>> preceding them.
 rivalryTerm(id) // Returns the rivalry term for the input. e.g. lines 99-100 of brothelReport.
  //<<if $Madam.rivalryTarget == $slaves[$i].ID>>
   //$He forces $his <<print rivalryTerm($Madam)>>, to service all the men in the brothel.
  //Would print 'She forces her growing rival, to service all the men in the brothel.'

 relationshipTerm(id) Returns the long form relationship term for the input. e.g. lines 147-148 of saRules.
  //<<if $slaves[$i].relationship > 0>>
   //$He often asks to save these breaks so $he can spend them with $his <<print relationshipTerm($slaves[$i])>>.
  //Would print '$He often asks to save these breaks so $he can spend them with $his friend.'

 relationshipTermShort(id) Prints the short form of the above. e.g. line 321 of slaveInteract.
  //`"Fuck $him with $his <<print relationshipTermShort($activeSlave)>> <<= SlaveFullName($slaves[_si])>>"`
  //Would print 'Fuck $him with $his BFF <<= SlaveFullName($slaves[_si])>>'

 PCrelationshipTerm(id) Prints the relationship term for the input (relative to the PC) if the relationship is < -1.
  //<<if $slaves[$i].relationship < -1>>
   //$He loves being your <<print PCrelationshipTerm($slaves[$i])>>.
  //Would print '$He loves being your wife.'

 contextualIntro(context, actor, insertComma=false) // Introduces an actor by using any meaningful relationship(s) with an already on-screen actor, and their name.
  //Returns strings like: "your husband John", "his growing rival and mother Alice", or "her best friend and twin sister Carla".
  //If there is no known relationship between them, returns the name alone. If insertComma is true, it will generate "her father, Dave" instead of "her father Dave".
  //Use this function instead of just printing the slave's name when you'd like to let the player to know if two actors are related, even though it's not going to have any mechanical impact on the scene.

bellyAdjective(slave) // Returns a string describing her belly size.

lispReplace(string) // Returns the string with a lisp.

nippleColor(slave) // Returns the slave's nipple color.

UtilJS [script]
 num() // Returns the value thousand separated with ',' if $formatNumbers > 0 else provides the raw value. Returns an integer if $showNumbers == 0, numbers up to a preset max as words if $showNumbers == 1, or only words if $showNumbers == 2.
  //line 138 of src/SpecialForce/Report.tw, '...focused their <<print num($SFUnit.Troops)>> troops'
  //if $formatNumbers > 0 'focused their 1,589 troops' else 'focused their 1589 troops'
  //if $showNumbers == 0 'focused their 1,589 troops', if $showNumbers == 1 'focused their 1,589 troops' (unless the max is set to more than 1,589), else 'focused their one thousand five hundred eighty-nine troops'

 cashFormat() // uses the above function to return the value thousand separated with ',' if $formatNumbers > 0 else provides the raw value. either way prepends ¤ (the fc domination) symbol.
  //line 157 of the previously listed file, '...totaling @@.yellowgreen;<<print cashFormat(_SFIncome)>>@@'
  //if $formatNumbers > 0 'totaling @@.yellowgreen;¤1,500,000@@' else 'totaling @@.yellowgreen;¤1500000@@'

 isFloat() // Checks if value is float.

 isInt() // Checks if value is an integer.

 numberWithCommas() // Currently unused.

 jsRandom() // JS equivalent of SugarCube's random().

 jsRandomMany() // JS equivalent of SugarCube's randomMany().

 jsEither() // This function wants an array // which explains why it works like array.random(). Give it one or you'll face a NaN. JS equivalent of SugarCube's either() and array.random().

 deepCopy() // This function is alternative to clone // usage needed if nested objects present. Slower but result is separate object tree, not with reference to source object.

 hashChoice() // hashes provided input.

 hashSum() // totals provided input and then hashes.

 arr2obj() // Converts an array to an object. e.g. line 250 of :: init Nationalities [silently]
  <<set $nationalities = arr2obj(setup.baseNationalities)>>

 hashPush() //Note really sure where input is being pushed to.

 weightedArray2HashMap()

 def() // Returns whether the input is defined, similar to SugarCube's def.
```

## Core Slave Functions

```js
newSlave(slave) // Adds slave object to main slave array. Do not use without care!

getSlave(ID) // Returns the slave object with the matching ID.

getPronouns(slave) // Returns an object containing a slave's pronouns.

generatePronouns(slave) // Sets slave's pronouns.

fetishChangeChance(slave) // Returns an int between 0,100 as the chance of a slave's fetish shifting to a new one.

SlaveSort(slaveArray) // Sorts the slaveArray array and sets indices.

slaveSortMinor(slaveArray) // Alphabetically sorts the slaveArray array and returns it.

faceIncrease(slave, amount) // Increases slave's .face by amount and returns a comment if it passes a threshold.

assignJob(slave, assignment) // Assigns slave to assignment. Mandatory for assigning to facilities.

removeJob(slave, assignment) // Removes slave from assignment to "rest". Mandatory for removing from facilities.

GenerateNewSlave(sex) // Generates a new slave of sex. Replaces <<include "Generate __ Slave">>

setPregType(actor) // Returns a random ovum count based off actor values and other factors to be set as .pregType.

removeActiveSlave() // Removes $activeSlave from $slaves. Do not use without care!

SetBellySize(slave) // Sets slave's belly size.(pregnancy+inflation+implant)

SoftenBehavioralFlaw(slave) // Replaces the slave's behavioral flaw with the corresponding quirk.

SoftenSexualFlaw(slave) // Replaces the slave's sexual flaw with the corresponding quirk.

//Increases the slave's skill by value or 1. Returns a string if the skill is boosted over a threshold.
SkillIncrease.Oral(slave, value)
SkillIncrease.Vaginal(slave, value)
SkillIncrease.Anal(slave, value)
SkillIncrease.Whore(slave, value)
SkillIncrease.Entertain(slave, value)

surgeryAmp(slave, part) // Clean up variables connected to a specific body part that was amputated. For limbs see below.

// limb can be: "left arm", "right arm", "left leg", "right leg", "all"
removeLimbs(slave, limb) // Remove limb(s) and clean up connected variables.
attachLimbs(slave, limb, id) // Attach limb(s). Expects amputated limbs, will overwrite existing.

//UtilJS [script]
 Height.mean(nationality, race, genes, age) // returns the mean height for the given combination and age in years (>=2).
 Height.mean(nationality, race, genes) // returns the mean adult height for the given combination.
 Height.mean(slave) // returns the mean (expected) height for the given slave.

 Height.random(nationality, race, genes, age) // returns a random height using the skew-normal distribution around the mean height for the given arguments.
 Height.random(nationality, race, genes) // returns a random height for the given combination of an adult, as above.
 Height.random(slave[, options]) // returns a random height for the given slave, as above.

 Height.forAge(height, age, genes) // returns the height adapted to the age and genes.
 Height.forAge(height, slave) // returns the height adapted to the slave's age and genes.

 heightToEitherUnit() // takes an int in centimeters e.g. $activeSlave.height, returns a string in the format of either `200cm (6'7")`, `6'7"`, or `200cm`

 Height.config(configuration) // configures the random height generator globally and returns the current configuration.

 Intelligence.random(options) // returns a random intelligence. If no options are passed, the generated number will be on a normal distribution with mean 0 and standard deviation 45.

 getSlaveDevotionClass(slave) // returns the trust of the target as text. e.g. if ('mindbroken' == slave.fetish) return 'mindbroken';

 getSlaveTrustClass(slave) // returns the trust of the target as text. e.g. if (slave.trust < -95) return 'extremely-terrified';
```

## Health Functions

```js
setHealth(slave, condition, shortDamage, longDamage, illness, tired) // Sets the health (primarily) of new slaves, it helps ensure the desired values do not immediately kill the slave and corrects them if needed

improveCondition(slave, value) // Basic way to improve the health of a slave, this updates the slave's 'condition' value and their overall 'health' value.

healthDamage(slave, value) // Basic way to reduce the health of a slave, this updates the slave's 'shortDamage' value and their overall 'health' value.

healthPenalty(slave) // Checks illness and tired state in order to provide the slave with a productivity penalty.

illness(slave) // A start of the 'end week loop' function to see if a slave has gotten ill this week, or perhaps recovered, got worse, etc.

endWeekHealthDamage // An end of the 'end week loop' function to move shortDamage to the appropriate longer term variables and such.
```

## Sex Functions

```js
knockMeUp(actor, chance, hole, fatherID, displayOverride) // Attempts to impregnate actor.

VCheck.Anal(count) // Increments $activeSlave's anal count by count and attempts to take virginity. Defaults to 1.

VCheck.Vaginal(count) // Increments $activeSlave's vaginal count by count and attempts to take virginity. Defaults to 1.

VCheck.Both(countAnal, countBoth) // Attempts to increment $activeSlave's anal count by countAnal and attempts to increment vaginal by countBoth. Defaults to 1. Attempts to take virginities.

VCheck.Simple(count) // Calls either VaginalVCheck or VCheck.Anal() count times.

VCheck.Partner(countAnal, countBoth) // Attempts to increment $partner's anal count by countAnal and attempts to increment vaginal by countBoth. Defaults to 1. Attempts to take virginities.

SimpleSexAct.Player(slave, count) // Runs a player on slave sex act count times. (randomly chooses hole based off availability.)

SimpleSexAct.Slave(slave, count) // Runs a slave on slave sex act count times. (randomly chooses hole based off availability.)

SimpleSexAct.Slaves(slave1, slave2, count) // Runs a slave2 on slave1 sex act count times. (randomly chooses hole based off availability.)

//UtilJS [script]

 dickToInchString() // takes a dick value e.g. $activeSlave.dick, returns a string in the format 6 inches

 dickToCM() // takes a dick value e.g. $activeSlave.dick, returns an int of the dick length in cm

 ballsToInchString() // takes a ball value e.g. $activeSlave.balls, returns a string in the format 3 inches

 ballsToCM() // takes a ball value e.g. $activeSlave.balls, returns an int of the ball size in cm

 dickToEitherUnit() // takes a dick value e.g. $activeSlave.dick, returns a string in the format of either `20cm (8 inches)`, `8 inches`, or `20cm`

 ballsToEitherUnit() // takes a ball value e.g. $activeSlave.balls, returns a string in the format of either `20cm (8 inches)`, `8 inches`, or `20cm`
```

## Pregnancy Functions

```js
WombInit($slave) // before first pregnancy, at slave creation, of as backward compatibility update.

WombImpregnate($slave, $fetus_count, $fatherID, $initial_age) // should be added after normal impregnation code, with already calculated fetus count. ID of father // can be used in future for processing children from different fathers in one pregnancy. Initial age normally 1 (as .preg normally set to 1), but can be raised if needed. Also should be called at time as broodmother implant add another fetus(es), or if new fetuses added from other sources in future (transplanting maybe?)

WombProgress($slave, $time_to_add_to_fetuses) // after code that update $slave.preg, time to add should be the same.

$isReady = WombBirthReady($slave, $birth_ready_age) // how many children ready to be birthed if their time to be ready is $birth_ready_age (40 is for normal length pregnancy). Return int // count of ready to birth children, or 0 if no ready exists.

$children = WombBirth($slave, $birth_ready_age) // for actual birth. Return array with fetuses objects that birthed (can be used in future) and remove them from womb array of $slave. Should be called at actual birth code in SugarCube. fetuses that not ready remained in womb (array).

WombFlush($slave) // clean womb (array). Can be used at broodmother birthstorm or abortion situations in game. But birthstorm logically should use WombBirth($slave, 35) or so before // some children in this event is live capable, others is not.

TerminatePregnancy($slave) // end a pregnancy early, clean the womb, update the belly size, and automatically set an appropriate postpartum length.

$slave.bellyPreg = WombGetVolume($slave) // return double, with current womb volume in CC // for updating $slave.bellyPreg, or if need to update individual fetuses sizes.

findFather(ID) // searches for the ID given and returns an object or undefined
```

## Release Functions

```js
sexAllowed // returns true if both slaves are allowed to have sex with each other. All non-assignment sex should check here first; use disobedience() to determine if the slave or slaves involved will ignore the rules.

hasPartnerSex // returns true if the slave has a romantic partner, the relationship is sexual, and they are allowed to sex. Unless you are specifically checking the theoretical rule, check this instead of rules.release.partner.

hasFamilySex // returns true if the slave has a close family member, they are allowed to have sex, and the player is OK with seeing the result. Unless you are specifically checking the theoretical rule, check this instead of rules.release.family.

hasNonassignmentSex // returns true if the slave is having some kind of sex while off-duty with a partner other than the PC. This function provides the answer to "can I mention this slave having an off-duty sexual encounter of some kind."

releaseRestricted // returns true if the slave has some kind of rule limiting the off-duty sex they have. If it returns false, the slave is completely free to fuck whomever they want.
```

## Other Functions

```js
//UtilJS [script]
 cmToInchString() // takes an integer e.g. $activeSlave.hLength, returns a string in the format 10 inches

 cmToFootInchString() // takes an integer e.g. $activeSlave.height, returns a string in the format 6'5"

 lengthToEitherUnit() // takes an int in centimeters e.g. $activeSlave.hLength, returns a string in the format of either `30cm (12 inches)`, `12 inches`, or `30cm`

 ValidateFacilityDecoration() // checks the value of the associated variable and it if it infinite i.e. NA the text description is reset back to standard.
  /* decoration should be passed as "facilityDecoration" in quotes. For example, ValidateFacilityDecoration("brothelDecoration"). The quotes are important, do not pass it as a story variable. */

 stretchedAnusSize() // Calculates the minimum anus size to accommodate a particular dick size

 FSChangePorn() // // Currently unused, widget version routes directly through FSChange()

 HackingSkillMultiplier() // outputs a value based off of the PC's hacking skill.

 upgradeMultiplierArcology() // outputs a value based off of the PC's engineering skill.

 upgradeMultiplierMedicine() // outputs a value based off of the PC's medicine skill.

 upgradeMultiplierTrade() // outputs a value based off of the PC's trading skill.

 passageLink() // Creates a HTML element with custom SugarCube attributes which works as a passage link

 SkillIncrease() // Depreciates the SugarCube functions.

 disobedience() // Returns a 0-100 value indicating likelihood of a slave ignoring the rules.

 penetrativeSocialUse() // Returns the percentage (0-100) of the social acceptance of the slaves penetrating citizens.
```

repo_name: Nithhogg/fc

license: mit


code:
#!/bin/sh

# setup:
# add this to crontab:
# */15 * * * * cd ~/FC/fc-pregmod && git pull --ff-only origin pregmod-master > ~/FC/git_pull.log 2>&1
# and do "ln -s ~/FC/fc-pregmod/devTools/BuildAndIPFSify.sh .git/hooks/post-merge"
# NOTE: you may need to define XDG_RUNTIME_DIR in your crontab

# TODO: add logic to figure out if we should use ipfs-cluster instead of using the local instance directly.
#			if we use ipfs-cluster we probably don't need to warm ipfs.io's cache.

rm bin/*.html

# if this script is used as the post-merge hook then
# a) git pull has pulled something
# b) $PWD is fc-pregmod
if [ "$(basename "$0")" != "post-merge" ]; then
	# cd to fc-pregmod based on where this script is
	cd "$(readlink -f "$(dirname "$0")")/.." || exit 1
	git pull
	# if there are new html files then git probably pulled something and ran this script as a post-merge hook
	if ls bin/*.html; then
		exit 0
	fi
fi

# If we've done this before then unpin the previous hash so IPFS can GC it if it needs to
if [ -r ../IPFS_hash.txt ]; then
	ipfs pin rm --recursive=true "$(cut -d : -f 2 ../IPFS_hash.txt | tr -d ' ')"
fi

./compile || exit 1

# Keep the build time from changing the hash of the file
sed -Ei -e '/^  \* Built on .+$/d' bin/*.html

# add the date of the last commit to the file, but don't use colons because Windows (still?) doesn't like them
mv bin/*.html "bin/FC pregmod $(git log -1 --format='%cd' --date='format:%F %H-%M').html"

# include the unembedded vector art
ipfs_hash="$(ipfs add -w -Q -r bin/*.html resources)"
echo "IPFS Folder Hash: ${ipfs_hash}" > ../IPFS_hash.txt
ipfs name publish "$ipfs_hash"

# when it's done it will print something like "Published to $your_pubkey: /ipfs/$ipfs_hash"
# You can view the folder at http://127.0.0.1:8080/ipns/$your_pubkey

# make ipfs.io cache the files
# $XDG_RUNTIME_DIR SHOULD be defined, but there are cases where it wouldn't be
if [ -z "${XDG_RUNTIME_DIR+x}" ]; then
	echo "\$XDG_RUNTIME_DIR is unset, bailing"
	exit 2
fi

# throw it into a file so we can loop over lines, not "strings delimited by whitespace"
find resources bin -print | grep -ve '.gitignore' | sed -e 's|bin/||' | grep -Ee '.+\.svg' -e '.html' > "${XDG_RUNTIME_DIR}/files.list"

# ipfs PeerID, it's user specific
PeerID="$(ipfs config show | grep -e 'PeerID' | cut -d: -f 2 | tr -d ' "')"
while IFS= read -r item
do
	echo "https://ipfs.io/ipns/${PeerID}/${item}"
done < "${XDG_RUNTIME_DIR}/files.list" | xargs --max-procs=10 --max-args=1 --replace curl --silent --show-error --range 0-499 --output /dev/null '{}'

rm "${XDG_RUNTIME_DIR}/files.list"


code:
#!/bin/bash
branch='pregmod-master'
usr='pregmodfan'

echo "Use temp [0], dump file to current directory [1] or overwrite file in place [2]" && read opt
echo "Use upstream [1] or origin [0]" && read usrSelection
echo "Dry run? 1, 0" && read dryRun

if [[ $usrSelection == 0 ]];then
	usr=$(git remote show origin|grep -e /|head -n 1 | sed s'/Fetch URL: //' | sed s%/fc-pregmod.git%% | sed s%git@ssh.gitgud.io:%% || sed %https://gitgud.io/%%)
	echo "Use master [1] or current branch [0]." && read targetBranch
	if [[ $targetBranch == 0 ]];then branch=$(git rev-parse --abbrev-ref HEAD); fi
fi

if [[ $dryRun == 1 ]];then
 echo "https://gitgud.io/$usr/fc-pregmod/raw/$branch/"
else
	for ((i=1; i<=$#; i++)); do
		if [[ $opt == 0 ]]; then
			wget -q -P /tmp/ https://gitgud.io/$usr/fc-pregmod/raw/$branch/${!i}
		elif [[ $opt == 1 ]]; then
			wget -q https://gitgud.io/$usr/fc-pregmod/raw/$branch/${!i}
		else
			curl -s https://gitgud.io/$usr/fc-pregmod/raw/$branch/${!i} > ${!i}
		fi
	done
fi


code:
# Script to convert SC passages to JS.
# lowercasedonkey, here.  This script was written for the "PythonScript" plugin for notepad++.  https://github.com/bruderstein/PythonScript.  Not a python guy, but if works somewhere else, great!
# At the moment, you can't "rerun it" on JS.  Only run the code on SC, not the output.  It won't update the JS.

# Update slave references
editor.rereplace(r"\$activeSlave", r"slave")
editor.rereplace(r"\$slaves\[\$i\]", r"slave")

# Update all references
editor.rereplace(r"\$", r"V\.")

# Line breaks for embedded code, beautify later
editor.rereplace(r"([a-zA-Z@].*?)<<", r"$1\n<<")
editor.rereplace(r">>([a-zA-Z,\.@ ].*?)", r">>\n\t$1")

# Clean up print
editor.rereplace(r"<<print (.*)>>", r"V.\1")
editor.rereplace(r"<<= (.*?)>>", r"V\.\1")

# Raw text
editor.rereplace(r"	([a-zA-Z@\.,`'; ].*)", r"	r.push\(`\1`\);")

# If / else
editor.rereplace(r"<<if (.*?)>>", r"if \1 {")
editor.rereplace(r"<<elseif (.*?)>>", r"} else if \(\1\) {")
editor.rereplace(r"<<else>>", r"} else {")
editor.rereplace(r"<</if>>", r"}")

#fix paren
editor.rereplace(r"([	\n])if ([^\(].*) {", r"\1if \(\2\) {")
editor.rereplace(r"([	\n])else if ([^\(].*) {", r"\1 else if \(\2\) {")

# run can happen directly
editor.rereplace(r"<<run (.*?)>>", r"\1;")

# Clean up unset
editor.rereplace(r"<<unset (.*)>>", r"delete \1;")

# Set
editor.rereplace(r"<<set (.*?)>>", r"$1;")

editor.rereplace(r"<<(Master)>>", r"${$1}")
editor.rereplace(r"<<(say)>>", r"${$1}")

#Switch
editor.rereplace(r"<<switch (.*?)>>", r"switch \(\1\) {")
editor.rereplace(r"<</switch>>", r"}")
editor.rereplace(r"<<case (.*?)>>", r"case \1:")
editor.rereplace(r"<<default>>", r"default:")

# SC markup
editor.rereplace(r"@@\.(.*?);(.*?)@@", r"\2")
editor.rereplace(r"@@\.(.*?);", r"")
editor.rereplace(r"@@", r"")
#remove incompatible comment style
editor.rereplace(r"/%", r"/*")
editor.rereplace(r"%/", r"*/")

# JS
editor.rereplace(r" == ", r" === ")
editor.rereplace(r" != ", r" !== ")

#fix pronouns
editor.rereplace(r"V\.Hers", r"\${Hers}")
editor.rereplace(r"V\.hers", r"\${hers}")
editor.rereplace(r"V\.He", r"\${He}")
editor.rereplace(r"V\.he", r"\${he}")
editor.rereplace(r"V\.Himself", r"\${Himself}")
editor.rereplace(r"V\.himself", r"\${himself}")
editor.rereplace(r"V\.Him", r"\${Him}")
editor.rereplace(r"V\.him", r"\${him}")
editor.rereplace(r"V\.His", r"\${His}")
editor.rereplace(r"V\.his", r"\${his}")
editor.rereplace(r"V\.Girl", r"\${Girl}")
editor.rereplace(r"V\.girl", r"\${girl}")
editor.rereplace(r"V\.Loli", r"\${Loli}")
editor.rereplace(r"V\.loli", r"\${loli}")
editor.rereplace(r"V\.Woman", r"\${Woman}")
editor.rereplace(r"V\.woman", r"\${woman}")

#fix pronouns
editor.rereplace(r"_He2", r"\${_He2}")
editor.rereplace(r"_he2", r"\${_he2}")
editor.rereplace(r"_Him2", r"\${_Him2}")
editor.rereplace(r"_him2", r"\${_him2}")
editor.rereplace(r"_His2", r"\${_His2}")
editor.rereplace(r"_his2", r"\${_his2}")
editor.rereplace(r"_Hers2", r"\${_Hers2}")
editor.rereplace(r"_hers2", r"\${_hers2}")
editor.rereplace(r"_Himself2", r"\${_Himself2}")
editor.rereplace(r"_himself2", r"\${_himself2}")
editor.rereplace(r"_Girl2", r"\${_Girl2}")
editor.rereplace(r"_girl2", r"\${_girl2}")
editor.rereplace(r"_Loli2", r"\${_Loli2}")
editor.rereplace(r"_loli2", r"\${_loli2}")
editor.rereplace(r"_Woman2", r"\${_Woman2}")
editor.rereplace(r"_woman2", r"\${_woman2}")
editor.rereplace(r"_Hers2", r"\${_Hers2}")
editor.rereplace(r"_hers2", r"\${_hers2}")

#look for variables embedded in literals
editor.rereplace(r"(	r.push[^;]*?)(V\.[^ ,<'`]*)", r"\1${\2}")
editor.rereplace(r"(	r.push[^;]*?)(slave\.[^ ,<'`]*)", r"\1${\2}")
editor.rereplace(r"(	r.push[^;]*?)(_S\.[^ ,<'`]*)", r"\1${\2}")
editor.rereplace(r"(	r.push[^;]*?)( _[^ ,<'`]*)", r"\1${ \2}")

#Delay fixing _S to simplify detection if it's embedded.
editor.rereplace(r"_S\.", r"S.")

#drop spaces
editor.rereplace(r"r.push\(` ", r"r.push\(`")
editor.rereplace(r" `\);", r"`\);")

#Cleanup
editor.rereplace(r"\${He}adGirl", r"V.HeadGirl")
editor.rereplace(r"\.}", r"}.")
editor.rereplace(r"\${slave}", r"slave")
editor.rereplace(r"V.getSlave", r"getSlave")
editor.rereplace(r"V.App", r"App")

# Compress speech macros, like <<s>>
editor.rereplace(r"`\);\n[	]*<<([^\}]*)>>\n[	]*r\.push\(`", r"$1")

path: devTools/Script to convert SC to JS/SC to JS 1.py


code:
#!/bin/sh

tmpJoinedFile=`mktemp --suffix=.js`

files=$(find js src -name '*.js' -print)
files=$(echo "$files" | sort)
for f in $files; do
	printf "\n/* ${f} */\n" >> "$tmpJoinedFile"
	cat "$f" >> "$tmpJoinedFile"
done

node -c "$tmpJoinedFile"

test $? -eq 0 && rm "$tmpJoinedFile"


code:
@echo off
:: Concatenates files from dir %1 specified with wildcard %2 and outputs result to %3

:: temporary codepage change to avoid mojibake
FOR /f "tokens=2 delims=:." %%x IN ('CHCP') DO SET _CP=%%x
CHCP 65001 > NUL

:: TODO Proper temp file instead of bin\list.txt
IF EXIST %3 DEL %3
SET _LISTFILE=bin\list.txt
SET _SORT_CMD=sort

:: If SORT_MEM is defined, use memory option for SORT
IF DEFINED SORT_MEM SET _SORT_CMD=%_SORT_CMD% /m %SORT_MEM%

:: Collect sorted list of files
ECHO "Ignore the first line to skip the BOM" >%_LISTFILE%
(FOR /R "%~1" %%F IN (%2) DO echo "%%F") | %_SORT_CMD% >>%_LISTFILE%

:: If we have powershell available, strip the absolute path information
:: If not, fail silently (which is fine, but will leak path information into the built file)
powershell -command "" 2> NUL
IF %ERRORLEVEL% EQU 0 powershell -command "(get-content -literalPath \"%CD%\%_LISTFILE%\" -encoding utf8) -replace [regex]::escape(\"%CD%\"),'' -replace '\"','' ^| set-content -encoding utf8 -literalPath \"%CD%\%_LISTFILE%\""

:: Append the files
(FOR /F "skip=1 usebackq delims=" %%F IN (`type "%_LISTFILE%"`) DO (
	echo /* %%F */ >> %3
	copy /b %3+"%CD%%%F" %3 1>NUL
	)
)

DEL %_LISTFILE%
CHCP %_CP% > NUL


code:
#!/bin/sh

# $1: source dir
# $2: name wildcard
# #3: destination file

rm -f "$3"
files=$(find "$1" -name "$2" -print)
files=$(echo "$files" | sort)
for f in $files; do
	printf "\n/* ${f#$1} */\n" >> "$3"
	cat "$f" >> "$3"
done


code:
#!/bin/sh

#converts files in the current dir

# collect files with [script] tag
FILES=`grep '\[script\]' -H -R * | cut -f 1 -d ':'`
for f in $FILES; do
	# create new name. Old name can have any of the following suffixes:
	# _JS.tw  JS.tw .tw
	nf="${f%_JS.tw}"
	nf="${nf%JS.tw}"
	nf="${nf%.tw}"
	# we might end up with an empty name, then set dir name as the file name
	[ -z "$(basename $nf)" -o "${nf: -1}" = "/" ] && nf="${nf}$(basename ${nf})"
	# append the new suffix
	nf="${nf}.js"
	echo "renaming ${f} -> ${nf}"
	# rename the file
	git mv "${f}" "${nf}" || echo "renaming ${f} failed"
	# strip Twee header from it
	sed -i 1d "${nf}" || echo "stripping Twee header failed for ${nf}"
	# strip leading empty line '/./,$!d'
	sed -i '/./,$!d' "${nf}" || echo "Stripping leading empty blank lines failed for ${nf}"
done


code:
Afghan
African
Albanian
Algerian
American
Andorran
Angolan
Antiguan
Argentinian
Armenian
Aruban
Australian
Austrian
Azerbaijani
Bahamian
Bahraini
Bangladeshi
Barbadian
Belarusian
Belgian
Belizean
Beninese
Bermudian
Bhutanese
Bissau-Guinean
Bolivian
Bosnian
Brazilian
British
Bruneian
Bulgarian
Burkinabé
Burmese
Burundian
Caledonian
Cambodian
Cameroonian
Canadian
Cape Verdean
Catalan
Chadian
Chilean
Chinese
Colombian
Comorian
Congolese
Costa Rican
Croatian
Cuban
Curaçaoan
Cypriot
Czech
Danish
Djiboutian
Dominican
Dominiquais
Dutch
Ecuadorian
Egyptian
Emirati
Equatoguinean
Eritrean
Estonian
Ethiopian
Fijian
Filipina
Finnish
Gabonese
Gambian
Georgian
German
Ghanan
Greek
Greenlandic
Grenadian
Guamanian
Guatemalan
Guianan
Guinean
Guyanese
Haitian
Honduran
Hungarian
I-Kiribati
Icelandic
Indian
Indonesian
Iranian
Iraqi
Irish
Israeli
Italian
Ivorian
Jamaican
Japanese
Jordanian
Kazakh
Kenyan
Kittitian
Korean
Kosovan
Kurdish
Kuwaiti
Kyrgyz
Laotian
Latvian
Lebanese
Liberian
Libyan
Lithuanian
lusitanian
Lusitanic
Luxembourgian
Macedonian
Malagasy
Malawian
Malaysian
Maldivian
Malian
Maltese
Marshallese
Mauritanian
Mauritian
Mexican
Micronesian
Moldovan
Monégasque
Mongolian
Montenegrin
Moroccan
Mosotho
Motswana
Mozambican
Namibian
Nauruan
Nepalese
Ni-Vanuatu
Nicaraguan
Nigerian
Nigerien
Niuean
Norwegian
Omani
Pakistani
Palauan
Palestinian
Panamanian
Papua New Guinean
Paraguayan
Peruvian
Polish
Polynesian
Portuguese
Puerto Rican
Qatari
Romanian
Russian
Rwandan
Sahrawi
Saint Lucian
Salvadoran
Sammarinese
Samoan
São Toméan
Saudi
Scottish
Senegalese
Serbian
Seychellois
Sierra Leonean
Singaporean
Slovak
Slovene
Somali
Spanish
Sri Lankan
Sudanese
Surinamese
Swazi
Swedish
Swiss
Syrian
Taiwanese
Tajik
Tanzanian
Thai
Tibetan
Timorese
Togolese
Tongan
Trinidadian
Tunisian
Turkish
Turkmen
Tuvaluan
Ugandan
Ukrainian
Uruguayan
Uzbek
Vatican
Venezuelan
Vietnamese
Vincentian
Yemeni
Zairian
Zambian
Zimbabwean


code:
inu
kit
neko
risu
tanuki
tsundere
uma
usagi
ushi


code:
Abkhaz
Bhojpuri
Verdean
Chewa
Chichewa
Dari
Drehu
Dzongkha
Khmu
Kikongo
Kinyarwanda
Kirundi
Luxembourgish
Makhuwa
Māori
Ndebele
Nengone
São Toméan
Sesotho
Tetum
Toméan
Tsonga


code:
Engineerix
ephebophile
lolifier
lolify
lolifying
ltdrdata
mcmonkeyprojects
orthodontal
reputational
rgthree
sdapi
SDXL
Svornost
swinir
unapprovingly
uncircumcise
unsexy
webui


code:
Adamsdóttir
Alawi
Anika
Auyala
Banaszewski
Bettysdóttir
Bettysson
Bolkiah
Bóndi
Cammy
Chakri
Chloë
Danni
Dlamini
Ervona
Eryma
Fatiah
Feri
Fjola
Gabe
Glücksburg
Hāshim
Ildoe
Izzy
Kennerly
Khalifah
Kissa
Koko
Lillium
Maree
Mayu
Mikayla
Mikey
Milly
Nahyan
Nikole
Picarde
Reine
Riya
Rodan
Rolan
Saxe-Coburg
Sotto
Suzie
Thani
Thérèse
Tupou
Viktoriya
Xendra
Yukiko
Yuuki
Yuzuki
Zuzanna


code:
@echo off
pushd %~dp0
embed_favicon.py
popd
pause


code:
#!/usr/bin/env python3

'''
Script for embedding favicons into a HTML Header.

Script file is expected to reside in devTools directory.

Note: This does not actually check the image file's contents for size detection.

Usage:
python3 embed_favicon.py [FC_pregmod.html]
'''

import sys
import os
import re
import base64

# file extensions eligible for use as favicons and their mimetype
ext2mimetype = {
	'.png': 'image/png',
	'.ico': 'image/x-icon'
}

# reads a file, turns it into a data uri
def data_uri_from_file(filename, mimetype):
	data = open(filename, 'rb').read()
	base64data = base64.b64encode(data).decode('ascii')
	out = 'data:%s;base64,%s' % (mimetype, base64data)
	return out

if __name__ == "__main__":
	# find project root directory path
	# (script file is expected to reside in devTools)
	project_root_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
	html_path = ''
	if (len(sys.argv) > 1):
		html_path = sys.argv[1]
	else:
		# path to bin/FC_pregmod.html
		html_path = os.path.join(
			project_root_path,
			'bin/FC_pregmod.html'
		)
	# path to directory containing all favicons to embed
	favicons_source_path = os.path.join(
		project_root_path,
		'resources/raster/favicon/'
	)
	# walk directory for all files
	favicons_paths = [
		os.path.join(dirpath, filename)
		for dirpath, dirnames, filenames in os.walk(favicons_source_path)
		for filename in filenames
	]
	# ignore files with unknown extensions
	favicons_paths = [f for f in favicons_paths
					  if f[-4:] in ext2mimetype.keys()]

	# prepare embedded data
	size_from_filename = re.compile(r'([0-9]+)\....$')
	favicons_html = []
	for fp in favicons_paths:
		print('Found favicon source file "%s".' % (fp))
		# get mimetype by file extension
		mimetype = ext2mimetype[fp[-4:]]
		if (mimetype == 'image/x-icon'):
			# assume sizes in ico
			sizes = '16x16 32x32 64x64'
		else:
			# guess icon size from file name
			size = size_from_filename.search(fp).group(1)
			sizes = '%sx%s' % (size, size)
		data = data_uri_from_file(fp, mimetype)
		favicons_html.append(
			# prepare html with favicon data embedded
			'<link rel="icon" type="%s" sizes="%s" href="%s">\n' % (
				mimetype, sizes, data
			)
		)

	# modify header file
	with open(html_path, 'r+', encoding='utf-8') as hf:
		print('Rewriting "%s"...' % (html_path))
		lines_in = hf.readlines()  # read whole file
		lines_out = []
		for line in lines_in:
			# embed favicons into head
			if (line.startswith('</head>')):
				lines_out.extend(favicons_html)
			# remove all currently embedded favicons
			if (not (line.startswith('<link') and 'icon' in line)):
				lines_out.append(line)
		hf.seek(0)  # move to beginning of file
		hf.write(''.join(lines_out))  # overwrite with new data
		hf.truncate()  # remove trailing old data

	print('Finished.')


code:
<!-- Added to the <head> of the html file -->
<link rel="shortcut icon" type="image/x-icon" href="resources/raster/favicon/arcologyVector.ico">


code:
Full sources for easy import into an IDE can be found [here](https://gitgud.io/Arkerthan/twine-sanitycheck).

`sources.zip` is a backup in case the repo is inaccessible.


code:
# The same as dictionary_phrases.txt, just case sensitive.
bellypreg#bellyPreg
bellyimplant#bellyImplant
bellyfluid#bellyFluid
earWear#earwear
eyeWear#eyewear
setBellySize#SetBellySize
SetbellySize#SetBellySize
setbellySize#SetBellySize
hormonebalance#hormoneBalance
fetishknown#fetishKnown


code:
# Define phrases that should be searched in src/ on every call of the java based
# sanityCheck here.
# Phrases will be found whenever that exact phrase appears, regardless of
# surroundings or overlapping.
# Not case sensitive.
# Format is: searchPhrase#errorMessage
# Output is: Found searchPhrase; Correct: errorMessage
#cash +=#Should be cashX() ## cash used by corporate code,
#cash -=#Should be cashX() ## too many false positives
#rep +=#Should be repX() ## unused because .rep is used by facility code
#rep -=#Should be repX() ## -> many false positives
cash+=#Should be cashX()
cash-=#Should be cashX()
rep+=#Should be repX()
rep-=#Should be repX()
attepmts#attempts
youreslf#yourself
advnaces#advances
canAcheive#canAchieve
carress#caress
recieves#receives
$slave[#Should be $slaves[
can not #cannot
Coca Cola#Coca-Cola
dosen't#doesn't
aircrafts'#aircraft's
outift#outfit
curiousity#curiosity
intensly#intensely
quicly#quickly
avalibe#available
randomise#randomize
protudes#protrudes
disapearing#disappearing