code:
#!/usr/bin/env python3

'''
Application for procedural content adaption
*THIS IS VERY EXPERIMENTAL*
Contains a very poor man's implementation of spline mesh warping.

This application parses SVG path data of an outfit sample aligned to a body part.
The outfit is then replicated for other shapes of the same body part.

Example data is geared towards generating a strap outfit for boobs and torso
for all sizes of boobs and all shapes of torsos based on a single outfit for
boobs of size 2 and a hourglass torso respectively.

Limitations:
* handles paths only
* only svg.path Line and CubicBezier are tested
* only the aforementioned examples are tested

Usage:
python3 vector_clothing_replicator.py infile clothing bodypart destinationfile

Usage Example:
python3 vector_clothing_replicator.py vector_source.svg Straps Boob vector_destination.svg
python3 vector_clothing_replicator.py vector_source.svg Straps Torso vector_destination.svg
'''

from svg.path import parse_path
import copy
import lxml.etree as etree
import sys

REFERENCE_PATH_SAMPLES = 200
EMBED_REPLICATIONS = True # whether to embed all replications into the input file or output separate files

input_file = sys.argv[1]
clothing = sys.argv[2]
bodypart = sys.argv[3]
output_file_embed = sys.argv[4]

# TODO: make these configurable
output_file_pattern = '%s_%s_%s.svg' #bodypart, target_id, clothing

if ('Torso' == bodypart):
  xpath_shape = './svg:g[@id="Torso_"]/svg:g[@id="Torso_%s"]/svg:path[@class="skin torso"]/@d' # TODO: formulate more general, independent of style
  xpath_outfit_container = '//svg:g[@id="Torso_Outfit_%s_"]'%(clothing)
  xpath_outfit = '//svg:g[@id="Torso_Outfit_%s_%s"]'%(clothing,'%s')
  target_ids = "Unnatural,Hourglass,Normal".split(",")
  reference_id = "Hourglass"
else:
  raise RuntimeError("Please specify a bodypart for clothing to replicate.")

tree = etree.parse(input_file)
ns = {'svg' : 'http://www.w3.org/2000/svg'}

canvas = copy.deepcopy(tree)
for e in canvas.xpath('./svg:g',namespaces=ns)+canvas.xpath('./svg:path',namespaces=ns):
  # TODO: this should be "remove all objects, preserve document properties"
  e.getparent().remove(e)

def get_points(xpath_shape):
  '''
  This function extracts reference paths by the given xpath selector.
  Each path is used to sample a fixed number of points.
  '''
  paths_data = tree.xpath(xpath_shape,namespaces=ns)
  points = []
  path_length = None
  for path_data in paths_data:
	p = parse_path(path_data)
	points += [
	  p.point(1.0/float(REFERENCE_PATH_SAMPLES)*i)
	  for i in range(REFERENCE_PATH_SAMPLES)
	]
  if (not points):
	raise RuntimeError(
	  'No paths for reference points found by selector "%s".'%(xpath_shape)
	)
  return points

def point_movement(point, reference_points, target_points):
  '''
  For a given point, finds the nearest point in the reference path.
  Gives distance vector from the nearest reference point to the
  respective target reference point.
  '''
  distances = [abs(point-reference_point) for reference_point in reference_points]
  min_ref_dist_idx = min(enumerate(distances), key=lambda x:x[1])[0]
  movement = target_points[min_ref_dist_idx] - reference_points[min_ref_dist_idx]
  return movement

reference_points = get_points(xpath_shape%(reference_id))
container = tree.xpath(xpath_outfit_container,namespaces=ns)
if (len(container) != 1):
  raise RuntimeError('Outfit container selector "%s" does not yield exactly one layer.'%(xpath_outfit_container))
container = container[0]
outfit_source = container.xpath(xpath_outfit%(reference_id),namespaces=ns)
if (len(outfit_source) != 1):
  raise RuntimeError('Outfit source selector "%s" does not yield exactly one outfit layer in container selected by "%s".'%(xpath_outfit%(reference_id), xpath_outfit_container))
outfit_source = outfit_source[0]

for target_id in target_ids:
  print(
	'Generating variant "%s" of clothing "%s" for bodypart "%s"...'%
	(target_id, clothing, bodypart)
  )
  outfit = copy.deepcopy(outfit_source)
  paths = outfit.xpath('./svg:path',namespaces=ns)
  if target_id == reference_id:
	print("This is the source variant. Skipping...")
  else:
	layerid = outfit.get('id').replace('_%s'%(reference_id),'_%s'%(target_id))
	outfit.set('id', layerid)
	outfit.set(etree.QName('http://www.inkscape.org/namespaces/inkscape', 'label'), layerid) # for the Inkscape-users
	target_points = get_points(xpath_shape%(target_id))
	if (len(reference_points) != len(target_points)):
	  raise RuntimeError(
		('Different amounts of sampled points in reference "%s" and target "%s" paths. '+
		'Selector "%s" probably matches different number of paths in the two layers.')%
		(reference_id, target_id, xpath_shape)
	  )
	for path in paths:
	  path_data = path.get("d")
	  p = parse_path(path_data)
	  for segment in p:
		original_distance = abs(segment.end-segment.start)
		start_movement = point_movement(segment.start, reference_points, target_points)
		segment.start += start_movement
		end_movement = point_movement(segment.end, reference_points, target_points)
		segment.end += end_movement
		distance = abs(segment.end-segment.start)
		try:
		  # enhance position of CubicBezier control points
		  # amplification is relative to the distance gained by movement
		  segment.control1 += start_movement
		  segment.control1 += (segment.control1-segment.start)*(distance/original_distance-1.0)
		  segment.control2 += end_movement
		  segment.control2 += (segment.control2-segment.end)*(distance/original_distance-1.0)
		except AttributeError as ae:
		  # segment is not a CubicBezier
		  pass
	  path.set("d", p.d())
	if EMBED_REPLICATIONS:
	  container.append(outfit)
  if not EMBED_REPLICATIONS:
	container = copy.deepcopy(canvas).xpath('.',namespaces=ns)[0]
	container.append(outfit)

  if not EMBED_REPLICATIONS:
	svg = etree.tostring(container, pretty_print=True)
	with open((output_file_pattern%(bodypart, target_id, clothing)).lower(), 'wb') as f:
	  f.write('<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n'.encode("utf-8"))
	  f.write(svg)

if EMBED_REPLICATIONS:
  svg = etree.tostring(tree, pretty_print=True)
  with open(output_file_embed, 'wb') as f:
	f.write('<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n'.encode("utf-8"))
	f.write(svg)


code:
#!/usr/bin/env python3

'''
Application for splitting groups from one SVG file into separate files

Usage:
python3 vector_layer_split.py infile format outdir

Usage Example:
python3 vector_layer_split.py vector_source.svg tw ../src/art/vector/layers/
'''

import lxml.etree as etree
import sys
import os
import copy
import re
import normalize_svg
import argparse

parser = argparse.ArgumentParser(
	description='Application for splitting groups from one SVG file into separate files.')
parser.add_argument('-o', '--output', dest='output_dir', required=True,
					help='output directory')
parser.add_argument('-f', '--format', dest='output_format',
					choices=['svg', 'tw'], default='svg', help='output format.')
parser.add_argument('-p', '--prefix', dest='prefix', default='',
					help='Prepend this string to result file names')
parser.add_argument('input_file', metavar='FILENAME', nargs='+',
					help='Input SVG file with layers')

args = parser.parse_args()
output_format = args.output_format
output_directory = args.output_dir

def splitFile(inputFile):
	tree = etree.parse(inputFile)
	normalize_svg.fix(tree)

	# prepare output template
	template = copy.deepcopy(tree)
	root = template.getroot()

	# remove all svg root attributes except document size
	for a in root.attrib:
		if (a != "viewBox"):
			del root.attrib[a]

	# add placeholder for CSS class (needed for workaround for non HTML 5.1 compliant browser)
	# if output_format == 'tw':
		# root.attrib["class"] = "'+_art_display_class+'"
	ns = {
		'svg': 'http://www.w3.org/2000/svg',
		'inkscape': 'http://www.inkscape.org/namespaces/inkscape',
		'sodipodi': "http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd",
	}

	# remove all content, including metadata
	# for twine output, style definitions are removed, too
	defs = None
	for e in root:
		if (e.tag == etree.QName(ns['svg'], 'defs')):
			defs = e
		if (e.tag == etree.QName(ns['svg'], 'g') or
			e.tag == etree.QName(ns['svg'], 'metadata') or
			e.tag == etree.QName(ns['svg'], 'defs') or
			e.tag == etree.QName(ns['sodipodi'], 'namedview') or
			(output_format == 'tw' and e.tag == etree.QName(ns['svg'], 'style'))
			):
			root.remove(e)
	# template preparation finished

	# prepare regex for later use
	regex_xmlns = re.compile(' xmlns[^ ]+')
	regex_space = re.compile(r'[>]\s+[<]')

	# find all groups
	layers = tree.xpath('//svg:g', namespaces=ns)
	for layer in layers:
		i = layer.get('id')
		if (  # disregard non-content groups
			i.endswith("_") or  # manually suppressed with underscore
			i.startswith("XMLID") or  # Illustrator generated group
			i.startswith("g")  # Inkscape generated group
		):
			continue
	# create new canvas
		output = copy.deepcopy(template)
	# copy all shapes into template
		canvas = output.getroot()
		for e in layer:
			canvas.append(e)
		# represent template as SVG (binary string)
		svg = etree.tostring(output, pretty_print=False)
		# poor man's conditional defs insertion
		# TODO: extract only referenced defs (filters, gradients, ...)
		# TODO: detect necessity by traversing the elements. do not stupidly search in the string representation
		if ("filter:" in svg.decode('utf-8')):
			# it seems there is a filter referenced in the generated SVG, re-insert defs from main document
			canvas.insert(0, defs)
			# re-generate output
			svg = etree.tostring(output, pretty_print=False)

		if (output_format == 'tw'):
			# remove unnecessary attributes
			# TODO: never generate unnecessary attributes in the first place
			svg = svg.decode('utf-8')
			svg = regex_xmlns.sub('', svg)
			svg = svg.replace(' inkscape:connector-curvature="0"', '')  # this just saves space
			svg = svg.replace('\n', '').replace('\r', '')  # print cannot be multi-line
			svg = regex_space.sub('><', svg)  # remove indentation
			svg = svg.replace('svg:', '')  # svg namespace was removed
			if ("Boob" in i):  # internal groups are used for scaling
				svg = svg.replace('<g ', '<g data-transform="boob" ')  # boob art uses the boob scaling
			elif ("Belly" in i):
				svg = svg.replace('<g ', '<g data-transform="belly" ')  # belly art uses the belly scaling
			elif ("Balls" in i):
				svg = svg.replace('<g ', '<g data-transform="balls" ')  # balls art uses the balls scaling
			else:
				svg = svg.replace('<g ', '<g data-transform="art" ')  # otherwise use default scaling
		if (not svg.endswith('\n')):
			svg += '\n'
		svg = svg.encode('utf-8')

		# save SVG string to file
		i = layer.get('id')
		output_path = os.path.join(output_directory, "{0}{1}.svg".format(args.prefix, i))
		with open(output_path, 'wb') as f:
			if (output_format == 'svg'):
				# Header for normal SVG (XML)
				f.write('<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n'.encode("utf-8"))
				f.write(svg)
			elif (output_format == 'tw'):
				f.write(svg)

if not os.path.exists(output_directory):
	os.makedirs(output_directory)

for f in args.input_file:
	splitFile(f)

license: mit


code:
#!/usr/bin/env python3

'''
Application for splitting groups from one SVG file into separate files

Usage:
python3 vector_layer_split.py infile format outdir

Usage Example:
python3 vector_layer_split.py vector_source.svg tw ../src/art/vector/layers/
'''

import lxml.etree as etree
from lxml.etree import XMLParser, parse

import sys
import os
import copy
import re
import argparse
import normalize_svg

parser = argparse.ArgumentParser(
	description='Application for splitting groups from one SVG file into separate files.')
parser.add_argument('-o', '--output', dest='output_dir', required=True,
					help='output directory')
parser.add_argument('-f', '--format', dest='output_format',
					choices=['svg', 'tw'], default='svg', help='output format.')
parser.add_argument('-p', '--prefix', dest='prefix', default='',
					help='Prepend this string to result file names')
parser.add_argument('input_file', metavar='FILENAME', nargs=1,
					help='Input SVG file with layers')

args = parser.parse_args()

output_format = args.output_format
output_directory = args.output_dir
input_file = args.input_file[0]

if not os.path.exists(output_directory):
	os.makedirs(output_directory)

ns = {
	'svg': 'http://www.w3.org/2000/svg',
	'inkscape': 'http://www.inkscape.org/namespaces/inkscape',
	'sodipodi': "http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd",
}

p = XMLParser(huge_tree=True)
tree = parse(input_file, parser=p)
#tree = etree.parse(input_file)
normalize_svg.fix(tree)

# prepare output template
template = copy.deepcopy(tree)
root = template.getroot()

# remove all svg root attributes except document size
for a in root.attrib:
	if (a != "viewBox"):
		del root.attrib[a]

# remove all content, including metadata
# for twine output, style definitions are removed, too
defs = None
for e in root:
	if (e.tag == etree.QName(ns['svg'], 'defs')):
		defs = e
	if (e.tag == etree.QName(ns['svg'], 'g') or
			e.tag == etree.QName(ns['svg'], 'metadata') or
			e.tag == etree.QName(ns['svg'], 'defs') or
			e.tag == etree.QName(ns['sodipodi'], 'namedview') or
			(output_format == 'tw' and e.tag == etree.QName(ns['svg'], 'style'))
	):
		root.remove(e)
# template preparation finished

# prepare regex for later use
regex_xmlns = re.compile(' xmlns[^ ]+')
regex_space = re.compile(r'[>]\s+[<]')

# find all groups
layers = tree.xpath('//svg:g', namespaces=ns)
for layer in layers:
	i = layer.get('id')
	if (  # disregard non-content groups
			i.endswith("_") or  # manually suppressed with underscore
			i.startswith("XMLID") or  # Illustrator generated group
			i.startswith("g")  # Inkscape generated group
	):
		continue
	# create new canvas
	output = copy.deepcopy(template)
	# copy all shapes into template
	canvas = output.getroot()
	for e in layer:
		canvas.append(e)
	# represent template as SVG (binary string)
	svg = etree.tostring(output, pretty_print=False)
	# poor man's conditional defs insertion
	# TODO: extract only referenced defs (filters, gradients, ...)
	# TODO: detect necessity by traversing the elements. do not stupidly search in the string representation
	if ("filter:" in svg.decode('utf-8')):
		# it seems there is a filter referenced in the generated SVG, re-insert defs from main document
		canvas.insert(0, defs)
		# re-generate output
		svg = etree.tostring(output, pretty_print=False)
	elif ("clip-path=" in svg.decode('utf-8')):
		# it seems there is a clip path referenced in the generated SVG, re-insert defs from main document
		canvas.insert(0, defs)
		# re-generate output
		svg = etree.tostring(output, pretty_print=False)

	if (output_format == 'tw'):
		# remove unnecessary attributes
		# TODO: never generate unnecessary attributes in the first place
		svg = svg.decode('utf-8')
		svg = regex_xmlns.sub('', svg)
		svg = svg.replace(' inkscape:connector-curvature="0"', '')  # this just saves space
		svg = svg.replace('\n', '').replace('\r', '')  # print cannot be multi-line
		svg = regex_space.sub('><', svg)  # remove indentation
		svg = svg.replace('svg:', '')  # svg namespace was removed

		if (not svg.endswith('\n')):
			svg += '\n'
		svg = svg.encode('utf-8')

	# save SVG string to file
	i = layer.get('id')
	output_path = os.path.join(output_directory, "{0}{1}.svg".format(args.prefix, i))
	with open(output_path, 'wb') as f:
		if (output_format == 'svg'):
			# Header for normal SVG (XML)
			f.write('<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n'.encode("utf-8"))
			f.write(svg)
		elif (output_format == 'tw'):
			f.write(svg)


code:
@echo off
:: Free Cities Basic Compiler - Windows

:: Set working directory
pushd %~dp0
if not exist "bin\resources" mkdir bin\resources
CALL devTools/concatFiles.bat js/ "*.js" bin/fc.js
:: Run the appropriate compiler for the user's CPU architecture.
if %PROCESSOR_ARCHITECTURE% == AMD64 (
	CALL "%~dp0devTools\tweeGo\tweego_win64.exe" -o "%~dp0bin/FC_pregmod.html" --module=bin/fc.js --head devTools/head.html "%~dp0src"
) else (
	CALL "%~dp0devTools\tweeGo\tweego_win86.exe" -o "%~dp0bin/FC_pregmod.html" --module=bin/fc.js --head devTools/head.html "%~dp0src"
)
DEL bin\fc.js

popd
ECHO Done


code:
#!/bin/bash

output=/dev/stdout

# displays help text
function displayHelp {
  cat << HelpText
Usage: compile.sh [OPTION]...

Options:
  -d, --dry      Do not compile
  -g, --git      Add hash of HEAD to filename
  -h, --help     Show this help text
  -s, --sanity   Run sanityCheck
  -q, --quiet    Suppress terminal output
HelpText
}

#display an error message
function echoError {
	echo -e "\033[0;31m$@\033[0m"
}

#display message
function echoMessage {
	echo "$1" > "${output}"
}

#compile the HTML file
function compile {
	mkdir -p bin/resources
	export TWEEGO_PATH=devTools/tweeGo/storyFormats
	TWEEGO_EXE="tweego"

	if hash $TWEEGO_EXE 2>/dev/null; then
		echoMessage "system tweego binary"
	else
		case "$(uname -m)" in
		x86_64|amd64)
			echoMessage "x64 arch"
			if [ "$(uname -s)" = "Darwin" ]; then
				TWEEGO_EXE="./devTools/tweeGo/tweego_osx64"
			elif [ $OSTYPE = "msys" ]; then
				TWEEGO_EXE="./devTools/tweeGo/tweego_win64"
			else
				TWEEGO_EXE="./devTools/tweeGo/tweego_nix64"
			fi
			;;
		x86|i[3-6]86)
			echoMessage "x86 arch"
			if [ "$(uname -s)" = "Darwin" ]; then
				TWEEGO_EXE="./devTools/tweeGo/tweego_osx86"
			elif [ $OSTYPE = "msys" ]; then
				TWEEGO_EXE="./devTools/tweeGo/tweego_win86"
			else
				TWEEGO_EXE="./devTools/tweeGo/tweego_nix86"
			fi
			;;
		*)
			echoError "No system tweego binary found, and no precompiled binary for your platform available."
			echoError "Please compile tweego and put the executable in PATH."
			exit 2
		esac
	fi

	if [[ -d .git ]]; then
		COMMIT=$(git rev-parse --short HEAD) # Find and insert current commit
		if [[ "$usehash" ]]; then
			file="bin/FC_pregmod_${COMMIT}.html"
		else
			sed -Ei "s/build: .releaseID/\0, commit: $COMMIT/" src/gui/mainMenu/AlphaDisclaimer.tw
			file="bin/FC_pregmod.html"
		fi
	else
		file="bin/FC_pregmod.html"
	fi

	devTools/concatFiles.sh js/ '*.js' bin/fc.js
	$TWEEGO_EXE -o $file --module=bin/fc.js --head devTools/head.html src/ || build_failed="true"
	rm -f bin/fc.js
	if [ "$build_failed" = "true" ]
	then
		echoError "Build failed."
		exit 1
	fi

	#Make the output prettier, replacing \t with a tab and \n with a newline
	sed -i -e '/^.*<div id="store-area".*$/s/\\t/\t/g' -e '/^.*<div id="store-area".*$/s/\\n/\n/g' $file
	if [[ -d .git ]]; then
		git checkout -- src/gui/mainMenu/AlphaDisclaimer.tw # Revert AlphaDisclaimer for next compilation
	fi
	echoMessage "Saved to $file."
}

if [[ "$1" == "" ]]; then
	#tip if no option
	echoMessage "For more options see compile.sh -h."
else
	#parse options
	while [[ "$1" ]]
	do
		case $1 in
		-d|--dry)
			dry="true"
		;;
		-g|--git)
			usehash="true"
		;;
		-h|--help)
			displayHelp
			exit 0
		;;
		-s|--sanity)
			sanity="true"
		;;
		-q|--quiet)
			output=/dev/null
		;;
		*)
			echoError "Unknown argument $1."
			displayHelp
			exit 1
		esac
		shift
	done
fi

# Run sanity check.
[ -n "$sanity" ] && ./sanityCheck.sh

if ! [[ -d .git ]]; then
	echoMessage "No git repository. Git specfific actions disabled."
fi

#compile
if [[ "$dry" ]]; then
	echoMessage "Dry run finished."
else
	compile
	echoMessage "Compilation finished."
fi


code:
@echo off
:: Free Cities Basic Compiler - Windows

:: Set working directory
pushd %~dp0

:: See if we can find a git installation
setlocal enabledelayedexpansion

for %%k in (HKCU HKLM) do (
	for %%w in (\ \Wow6432Node\) do (
		for /f "skip=2 delims=: tokens=1*" %%a in ('reg query "%%k\SOFTWARE%%wMicrosoft\Windows\CurrentVersion\Uninstall\Git_is1" /v InstallLocation 2^> nul') do (
			for /f "tokens=3" %%z in ("%%a") do (
				set GIT=%%z:%%b
				set GITFOUND=yes
				goto FOUND
			)
		)
	)
)
:FOUND
if %GITFOUND% == yes (
	set "PATH=%GIT%bin;%PATH%"
	bash --login -c "./sanityCheck.sh"
)

:: Compile the game
call "%~dp0compile.bat"

if %GITFOUND% == yes (
	:: Make the output prettier, replacing \t with a tab and \n with a newline
	bash -c "sed -i -e '/^.*<div id=\"store-area\".*$/s/\\\t/\t/g' -e '/^.*<div id=\"store-area\".*$/s/\\\n/\n/g' bin/FC_pregmod.html"

	:: Revert ./src/init/storyInit.tw for next compilation
	git checkout -- ./src/init/storyInit.tw
)

popd
PAUSE


code:
@echo off
:: Free Cities Basic Compiler - Windows

:: Set working directory
pushd %~dp0

:: Compile the game
call "%~dp0compile.bat"

popd
PAUSE


code:
Anatomy of a FreeCities event

Type
There are several types of events. They all happen during the end-of-week calculation, AFTER the normal changes to the slaves and all the economic effects (including you messing with your corporation) happened.

Scheduled events
Nonrandom events
Random nonindividual events
Random individual events

The differences between them are almost non-existent. If they happen, they happen in this order, so you could say it's a kind of event priority ordering. The last two events pre-select a slave (in $eventSlave), with the "nonindividual" events using all your slaves while the "individual" events use only non-Fuckdolls, typically from your penthouse. When writing your event, you're free to ignore this and choose your own slave or create a new one. By convention, scheduled events tend to go back to the "Scheduled Event" passage so that other such events can run; all the others tend to just skip to the next event category. Nothing in code forces you to do it this way for your events.

Preconditions
Most events have some kind of precondition for when they happen. Scheduled events always happen when their preconditions are true. Nonrandom events happen when their preconditions are true and no other nonrandom events get picked first (so writing a too-often-true precondition is a good way to break the game by blocking any further such events). The two other types of events get put in a pool ($events) if they match the precondition, then at most one event gets pulled from the pool per type.

	NonRandomEvent (26-33)
	<<elseif (_effectiveWeek == 14) && $badC != 1>>
	<<set _valid = $slaves.find(function(s) { return s.curatives > 1 || s.inflationType == "curative"; })>>
	<<if def _valid>>
		<<set $badC = 1, $Event = "bad curatives">>
		<<goto "Generic Plot Events">>
	<<else>>
		<<set $badC = 1>>
		<<goto "Nonrandom Event">>
	<</if>>

If it is week fourteen and the player hasn't ready seen the event, a check is then made for slaves that either are on curatives or have their implants filled by curatives. If it was successful then load the "bad curatives" generic event, if unsuccessful set the flag anyway and read from the Nonrandom Event passage.

Immediate effects

Every event can have immediate effects, which happen when the event gets chosen. For most events, those are what should happen if the player ignores the event (by hitting "Continue" or the space bar on the keyboard). Choice effects (see below) can override or roll back those.

	reRecuit (4-19)
	<<if Array.isArray($recruit)>>
		<<if $cheatMode == 1>>
			<<set $nextButton = "Back", $nextLink = "Nonrandom Event", $returnTo = "Nonrandom Event">> /* if user just clicks spacebar */
			''A random recruit event would have been selected from the following:''

			<<for _i = 0; _i < $recruit.length; _i++>>
				<<print "[[$recruit[_i]|RE recruit][$recruit = $recruit[" + _i + "]]]">>

			<</for>>

[[Go Back to Random Nonindividual Event|Random Nonindividual Event][$eventSlave = 0]]
		<<else>>
			<<set $recruit = $recruit.random()>>
			<<goto "RE recruit">>
		<</if>>
	<<else>>

	If cheat mode is enabled and the user presses the space bar go back to the start.

Main event text
The bulk of the writing will be in the main event text. There are quite a few rules to deal with here.
The PC is referred to in the second person singular ("you"), everyone else in third person.
The PC has no direct speech. All the things "you" say are described, not quoted.
A slave can be linked with the macro <<EventNameLink _Slave>>. This allows the player to click on the slave name and view their description, then go back to the event. WARNING: Going back triggers the event passage again, so if your event has immediate effects (see above), make sure to NOT repeat them by setting corresponding flags (this is harder than it sounds in general).

<<SlaveTitle _Slave>> sets $desc (which ends up being a string like "slavegirl", "MILF", "futanari" and so on, depending on slave).

<<setLocalPronouns _Slave>> allows you to use the variables $pronoun ("she"/"he"/"it"), $pronounCap ("She"/"He"/"It"), $possessive ("her"/"his"/"its"), $possessiveCap ("Her"/"His"/"Its") and $object ("her"/"him"/"it"). There is NO variable for self-possession ("hers"/"his"/"its") and for "herself", you need to use <<= $object>>self.
One more macro initializes several others and is required when you have a slave speak and want to use direct quotes: <<Enunciate _Slave>> allows you to use <<Master>>, <<WrittenMaster>>, <<says>> (which turns into "lisps" when that's the case) and the lisping replacers <<s>>, <<ss>>, <<S>>, <<c>> and <<z>>.

The text should be about large enough to fit on the screen assuming typical monitor sizes. In terms of visible text, about 1000 words are a fine limit to aim for. There's a lot to keep in mind in terms of different appearances and circumstances, so keep your document with slave variables as a reference nearby.

It's fine — and a part of the normal workflow — to first write an event without any variation, then go through it and vary the text here and there.

Choices
You should keep the amount of choices small, but not too small. About three to five is generally a good number. Choices which can't be taken due to the current situation should be displayed as such ("You lack the funds ...") if they are an obvious choice, hidden when they aren't (for example, in event chains you might want to hide choices if the player didn't do something specific or didn't acquire some specific bit of knowledge). Every choice should be a simple sentence of the form "Do something." followed by a short explanation of the obvious effects.

Choices should also be hidden when they run against the game rules, like for example the setting if the player wants to see "extreme" content.

	diary (313-325)
	<<if $dairyFeedersUpgrade == 1>>
		The milking machines can hold feeders in slaves' mouths and inject drugs into their bodies, ensuring ideal nutrition and production.

    The feeders are
		<<if $dairyFeedersSetting == 2>>
			''industrial.'' [[Moderate|Dairy][$dairyFeedersSetting = 1, $dairyFeedersSettingChanged = -1]]
		<<elseif $dairyFeedersSetting == 1>>
			''active.'' [[Inactive|Dairy][$dairyFeedersSetting = 0]]<<if ($seeExtreme != 0) && ($dairyRestraintsSetting == 2)>> | [[Industrial|Dairy][$dairyFeedersSetting = 2, $dairyFeedersSettingChanged = 1]]<</if>>
		<<else>>
			''inactive.'' [[Active|Dairy][$dairyFeedersSetting = 1]]
		<</if>>
	<<else>>
		$dairyNameCaps is equipped to feed and clean slaves normally. [[Upgrade the milking machines with intubators|Dairy][cashX(forceNeg(_Tmult1), "capEx"), $dairyFeedersUpgrade = 1]] //Costs ¤_Tmult1 and will increase upkeep costs. cashX is the proper way to handle cash payments. The forceNeg part just means "make sure what comes next is negative if it isn't already, because I want it to cost the player money." "capEx" is the budget category you want this transaction recorded under. You can search through the game files to find similar transactions. //
	<</if>>

	In order to enable the industrial feeder option both any of the see extreme content options has be enabled and the restraint's have to be already set to industrial.

Remember that "do nothing" is almost always a choice (it's called "Continue" and can be found on the left side of the screen) so your events don't need this as an extra choice.

Choice text
This should be a short text describing the effects of your choice. Generally shorter than the main text, but all the other things mentioned there apply.
Try to keep surprise buttsex to a minimum.

For example this cut up version of "paternalist encounter" from REFS (l:106-139).

		<<link "Alert your drones and keep walking">>
		<</link>>
		<<if $cash >= 2000>>

<<link "Take the poor slave $girl into your custody">>
			<</link>>
		<</if>>

<<link "Publicly confront the citizen">>
		<</link>>

	So here you can either, A) "Alert your drones and keep walking", B) if $cash is above 2000 you can take acquire the slave or C) "Publicly confront the citizen".

Choice effect
A choice doesn't need to have a specific effect. If your event has an immediate effect, remember to take that into account when you decide on the choice's effects.

		<<link "Alert your drones and keep walking">>
			<<replace "#result">>
				You inform $assistantName that you have a slave beater in need of detainment by your security drones, then continue on your way confident in your knowledge that the citizen will soon be in custody.
			<</replace>>
		<</link>>
		<<if $cash >= 2000>>

<<link "Take the poor slave $girl into your custody">>
				<<set $activeSlave.clothes = "no clothing">>
				<<replace "#artFrame">>
					/* 000-250-006 */
					<<if $seeImages == 1>>
						<<if $imageChoice == 1>>

<<= SlaveArt($activeSlave, 2, 0)>>

						<<else>>

<<= SlaveArt($activeSlave, 2, 0)>>

						<</if>>
					<</if>>
					/* 000-250-006 */
				<</replace>>
				<<replace "#result">>
					Confronting the citizen is simplicity in itself; he would not dare defy you under threat of arrest by your security drones and is unlikely to garner any sympathy from the public for his degradationist behaviors. As such, you are able to take civil ownership over the poor slave $girl and take $him into your care with only minimal compensation to the citizen. As you stride away from $his former owner with the $girl in your arms, $he leans over to plant a chaste kiss of thanks on your cheek.
					<<run cashX(-2000, "slaveTransfer", $activeSlave)>>
					<<include "New Slave Intro">>
				<</replace>>
			<</link>> // Taking custody of the $girl will cost <<print cashFormat(2000)>>. //
		<</if>>

<<link "Publicly confront the citizen">>
			<<replace "#result">>
				Your walk up to the citizen is not accompanied by shaking ground or tumultuous fanfare, yet the citizen looks as if death itself has come before him. You don't hurt him physically, instead chastising him publicly in front of his fellow peers who begin to cheer their agreement. You end your tirade of verbal abuse with a reminder that although the man is a citizen of your arcology, that does not give him the impunity to shirk the law. To make it clear his next offense will be his last, a brace of your security drones hover behind you threateningly. The crowd that gathered @@.green;approve of your rebuke of the citizen.@@
				<<run repX(2500, "event")>>
			<</replace>>
		<</link>>

	So here the results of the choices are, A) nothing, B) reduce cash by 2000 but acquire the slave C) chastise the citizen for plus 500 rep.


code:
artist notes
-------------
TO USE: SELECT VECTOR ART BY NOX/DEEPMURK

CREDITS
-------------
Nov_X/NoX (Original Artist, whose work I built off of)
skinAnon (For doing the color hexes on hundreds of skin/nipple tones.)
@prndev (For dynamic belly scaling magic)
@klorpa (For fixing many of my mistakes/spaghetti art code)
@kopareigns (For fixing many of my mistakes/spaghetti art code)
@pregmodder (Fixes and more art)

FOR MANUAL USE
-------------
1. Split source_vector_ndmain.svg and source_vector_ndextras.svg into src/art/vector/layer.
Note#1 source_vector.svg is a legacy version (before the art was changed) and is not used for anything.
Note#2 vector_revamp_source.svg not related and belongs to the other artist.

TO PLAY WITHOUT FACES
-------------
1. Go to pregmod/src/art/vector
2. Open head.tw in notepad/notepad++
3. Delete everything from Line 30 to Line 979... you'll see it says faceShape, eyebrowFullness, etc-- all of those are related to faces and can be deleted. (AKA just delete everything between the lines that says /* FACIAL APPEARANCE */ and /* END FACIAL APPEARANCE */)
4. Compile and play game.

known issues
-------------
	-minor clipping issue leg/ass outfits due to their outfit transparency effects
	-not all outfit art works with amputees
	-minor hair clipping on some outfits
	-heavy lip piercings look wonky on open mouth art
	-heavy/light piercings on face seem to override each other

---------------------------------------------------------------------------------------------------------------------------------------------
pending requests/suggestions
-------------
	-loli/shota bodies

pending outfit requests
-------------
	-opaque stockings with ribbons

planned additions
-------------
	-more hair styles
	-facepaint
	-alternate makeup options
	-rework all AI avatars
	-dick piercings (stalled due to planned code change)
	-more outfits, see current queue ( https://gitgud.io/deepmurk/fc-pregmod/issues/1 )

---------------------------------------------------------------------------------------------------------------------------------------------

v1.7 (12/22/2018)
-------------
	-added muscle definition (heavy)
	-added colorable sclera
	-added colorable eyebrows
	-added purple hair color
	-added dark orchid hair color
	-added sea green hair color
	-added green-yellow hair color
	-added dark blue hair color
	-added missing AI avatars
	-fixed faces & skintones not showing on custom ethnicities
	-added jet black hair color
	-changed black hair color
	-changed auburn hair color
	-alphabetized some options in the salon
	-miscellaneous tweaks to some other colors

v1.6 (11/18/2018)
-------------
	-misc art fixes
	-added muscle definition (low)
	-added muscle definition (medium)
	-shibari rope outfit is now red for better contrast on some skins
	-fixed hair showing when ability to grow hair was surgically removed
	-fixed muscles showing on amputated slave limbs
	-fixed faces showing on Fuckdolls
	-fixed "mixed race" skin tone/face issues
	-fixed some issues related to belly outfits

v1.5 (10/21/2018)
-------------
	-removed penis head piercing light flaccid (art only)
	-removed penis head piercing light erect (art only)
	-removed penis head piercing heavy flaccid (art only)
	-removed penis head piecing heavy erect (art only)
	-corrected ku klux klan robe description grammar
	-added burkini outfit
	-added hijab and blouse outfit
	-changed the code that affects art layer names due to conflicts with new outfits
	-changed art layer name of cutoffs to cutoffsandatshirt
	-changed art layer name of niqab to niqabandabaya
	-changed art layer name of hijab to hijabandabaya
	-changed art layer name of spats to spatsandatanktop
	-changed art layer name of stretchpants to stretchpantsandacroptop
	-changed art layer name of blouse to hijabandblouse
	-changed blouse and hijab outfit string name to hijab and blouse
	-changed shimapan panties outfit string name to striped panties
	-added bra outfit
	-added button-up shirt outfit
	-added button-up shirt and panties outfit
	-added gothic lolita dress outfit
	-added hanbok outfit
		-added nice pony outfit (no art yet)
	-added one-piece swimsuit outfit
	-added police uniform outfit
	-added skimpy loincloth outfit
	-added slutty klan robe outfit
		-added slutty pony outfit (no art yet)
	-added sports bra outfit
	-added striped bra outfit
	-added sweater outfit
	-added sweater and cutoffs outfit
	-added sweater and panties outfit
	-added t-shirt outfit
	-added t-shirt and jeans outfit
	-added t-shirt and panties outfit
	-added t-shirt and thong outfit
	-added tank-top outfit
	-added tank-top and panties outfit
	-added thong outfit
	-added tube top outfit
	-added tube top and thong outfit
	-added oversized t-shirt outfit
	-added oversized t-shirt and boyshorts outfit
	-added boyshorts outfit
	-added cutoffs outfit
	-added jeans outfit
	-added leather pants outfit
	-added leather pants and a tube top outfit
	-added leather pants and pasties outfit
	-added panties outfit
	-added panties and pasties outfit
	-added sport shorts outfit
	-added sport shorts and a sports bra outfit
	-added sport shorts and a t-shirt outfit
	-added striped underwear outfit
	-increased size of armpit hair art
	-changed minidress outfit to black color (per request)
	-misc art fixes
	-added kitty lingerie outfit

v1.4 (09/29/2018)
-------------
	-fixed facial markings showing on restrictive latex
	-fixed error on certain clothes when slave is an amputee
	-added ku klux klan outfit
	-added burqa outfit
	-added hijab and abaya outfit
	-changed niqab and abaya outfit
	-added shimapan panty outfit
	-fixed malay race not having faces
	-added penis head piercing light flaccid (art only)
	-added penis head piercing light erect (art only)
	-added penis head piercing heavy flaccid (art only)
	-added penis head piecing heavy erect (art only)
	-added nose piercing light
	-added nose piercing heavy
	-added lip piercing light
	-added lip piercing heavy
	-added eyebrow piercing light
	-added eyebrow piercing heavy
	-fixed some eyebrow types not coloring correctly when dyeing
	-fixed chastity belt showing incorrectly on some bodies (chubby, fat, obese)
	-fixed hijab head outfit showing incorrectly on faces
	-added cybernetic feet basic
	-added cybernetic leg narrow basic
	-added cybernetic leg normal basic
	-added cybernetic leg wide basic
	-added cybernetic leg thick basic
	-added cybernetic butt 0 basic
	-added cybernetic butt 1 basic
	-added cybernetic butt 2 basic
	-added cybernetic butt 3 basic
	-added cybernetic butt 4 basic
	-added cybernetic butt 5 basic
	-added cybernetic butt 6 basic
	-added cybernetic arm left thumb down basic
	-added cybernetic arm left rebel basic
	-added cybernetic arm left high basic
	-added cybernetic arm left mid basic
	-added cybernetic arm left low basic
	-added cybernetic arm right high basic
	-added cybernetic arm right mid basic
	-added cybernetic arm right low basic
	-added cybernetic feet sexy
	-added cybernetic leg narrow sexy
	-added cybernetic leg normal sexy
	-added cybernetic leg wide sexy
	-added cybernetic leg thick sexy
	-added cybernetic butt 0 sexy
	-added cybernetic butt 1 sexy
	-added cybernetic butt 2 sexy
	-added cybernetic butt 3 sexy
	-added cybernetic butt 4 sexy
	-added cybernetic butt 5 sexy
	-added cybernetic butt 6 sexy
	-added cybernetic arm left thumb down sexy
	-added cybernetic arm left rebel sexy
	-added cybernetic arm left high sexy
	-added cybernetic arm left mid sexy
	-added cybernetic arm left low sexy
	-added cybernetic arm right high sexy
	-added cybernetic arm right mid sexy
	-added cybernetic arm right low sexy
	-added cybernetic feet beauty
	-added cybernetic leg narrow beauty
	-added cybernetic leg normal beauty
	-added cybernetic leg wide beauty
	-added cybernetic leg thick beauty
	-added cybernetic butt 0 beauty
	-added cybernetic butt 1 beauty
	-added cybernetic butt 2 beauty
	-added cybernetic butt 3 beauty
	-added cybernetic butt 4 beauty
	-added cybernetic butt 5 beauty
	-added cybernetic butt 6 beauty
	-added cybernetic arm left thumb down beauty
	-added cybernetic arm left rebel beauty
	-added cybernetic arm left high beauty
	-added cybernetic arm left mid beauty
	-added cybernetic arm left low beauty
	-added cybernetic arm right high beauty
	-added cybernetic arm right mid beauty
	-added cybernetic arm right low beauty
	-added cybernetic feet combat
	-added cybernetic leg narrow combat
	-added cybernetic leg normal combat
	-added cybernetic leg wide combat
	-added cybernetic leg thick combat
	-added cybernetic butt 0 combat
	-added cybernetic butt 1 combat
	-added cybernetic butt 2 combat
	-added cybernetic butt 3 combat
	-added cybernetic butt 4 combat
	-added cybernetic butt 5 combat
	-added cybernetic butt 6 combat
	-added cybernetic arm left thumb down combat
	-added cybernetic arm left rebel combat
	-added cybernetic arm left high combat
	-added cybernetic arm left mid combat
	-added cybernetic arm left low combat
	-added cybernetic arm right high combat
	-added cybernetic arm right mid combat
	-added cybernetic arm right low combat
	-added cybernetic feet swiss
	-added cybernetic leg narrow swiss
	-added cybernetic leg normal swiss
	-added cybernetic leg wide swiss
	-added cybernetic leg thick swiss
	-added cybernetic butt 0 swiss
	-added cybernetic butt 1 swiss
	-added cybernetic butt 2 swiss
	-added cybernetic butt 3 swiss
	-added cybernetic butt 4 swiss
	-added cybernetic butt 5 swiss
	-added cybernetic butt 6 swiss
	-added cybernetic arm left thumb down swiss
	-added cybernetic arm left rebel swiss
	-added cybernetic arm left high swiss
	-added cybernetic arm left mid swiss
	-added cybernetic arm left low swiss
	-added cybernetic arm right high swiss
	-added cybernetic arm right mid swiss
	-added cybernetic arm right low swiss
	-added penis flaccid circumcised 0
	-added penis flaccid circumcised 1
	-added penis flaccid circumcised 2
	-added penis flaccid circumcised 3
	-added penis flaccid circumcised 4
	-added penis flaccid circumcised 5
	-added penis flaccid circumcised 6
	-added penis flaccid circumcised 7
	-added penis flaccid circumcised 8
	-added penis flaccid circumcised 9
	-added penis flaccid circumcised 10
	-added penis erect circumcised 0
	-added penis erect circumcised 1
	-added penis erect circumcised 2
	-added penis erect circumcised 3
	-added penis erect circumcised 4
	-added penis erect circumcised 5
	-added penis erect circumcised 6
	-added penis erect circumcised 7
	-added penis erect circumcised 8
	-added penis erect circumcised 9
	-added penis erect circumcised 10

v1.3 (09/22/2018)
-------------
	-fixed shaved sides hairstyle showing incorrectly
	-fixed faces showing on restrictive latex
	-fixed restrictive latex not showing on bodies (chubby, fat, obese)
	-fixed accent band not showing on kimono belly outfits
	-fixed facial markings showing incorrectly on faces (birthmark,etc)
	-added eye coloring (irises only)
	-fixed lips showing only one color
	-added fox ears and tail
	-added cat ears and tail
	-fixed nipples not showing on attractive lingerie for a pregnant woman outfit
	-fixed black colored nipples showing on latex and bodysuits
	-fixed head accessory alignment to new faces (ball gag, dildo gag, etc)
	-changed art on porcelain mask
	-added eyes type-d
	-added mouth type-d
	-added nose type-d
	-added eyebrows type-d pencilthin
	-added eyebrows type-d thin
	-added eyebrows type-d threaded
	-added eyebrows type-d natural
	-added eyebrows type-d tapered
	-added eyebrows type-d thick
	-added eyebrows type-d bushy
	-added eyes type-e
	-added mouth type-e
	-added nose type-e
	-added eyebrows type-e pencilthin
	-added eyebrows type-e thin
	-added eyebrows type-e threaded
	-added eyebrows type-e natural
	-added eyebrows type-e tapered
	-added eyebrows type-e thick
	-added eyebrows type-e bushy
	-added eyes type-f
	-added mouth type-f
	-added nose type-f
	-added eyebrows type-f pencilthin
	-added eyebrows type-f thin
	-added eyebrows type-f threaded
	-added eyebrows type-f natural
	-added eyebrows type-f tapered
	-added eyebrows type-f thick
	-added eyebrows type-f bushy
	-separated faces by race/head shape (eg: white/exotic is different from asian/exotic)
	-made some eye types smaller
	-fixed stockings not covering thick thighs properly

v1.2 (09/16/2018)
-------------
	-added naked apron outfit (chubby, fat, obese)
	-added attractive lingerie (chubby, fat, obese)
	-added ballgown outfit (chubby, fat, obese)
	-added battlearmor outfit (chubby, fat, obese)
	-added battledress outfit (chubby, fat, obese)
	-added biyelgee costume (chubby, fat, obese)
	-added body oil outfit (chubby, fat, obese)
	-added bunny outfit (chubby, fat, obese)
	-added chains outfit (chubby, fat, obese)
	-added chattel habit outfit (chubby, fat, obese)
	-added cheerleader outfit (chubby, fat, obese)
	-added clubslut outfit (chubby, fat, obese)
	-added comfortable bodysuit outfit (chubby, fat, obese)
	-added conservative outfit (chubby, fat, obese)
	-added cutoffs and tshirt outfit (chubby, fat, obese)
	-added dirndl outfit (chubby, fat, obese)
	-added fallennun habit outfit (chubby, fat, obese)
	-added haltertop dress outfit (chubby, fat, obese)
	-added harem gauze outfit (chubby, fat, obese)
	-added hijab and abaya outfit (chubby, fat, obese)
	-added huipil outfit (chubby, fat, obese)
	-added kimono outfit (chubby, fat, obese)
	-added latex outfit (chubby, fat, obese)
	-added attractive lingerie for pregnant woman outfit (chubby, fat, obese)
	-added leotard outfit (chubby, fat, obese)
	-added lederhosen outfit (chubby, fat, obese)
	-added long qipao outfit (chubby, fat, obese)
	-added maternity dress outfit (chubby, fat, obese)
	-added military uniform outfit (chubby, fat, obese)
	-added minidress outfit (chubby, fat, obese)
	-added monikini outfit (chubby, fat, obese)
	-added mounty outfit (chubby, fat, obese)
	-added nice business attire outfit (chubby, fat, obese)
	-added nice maid outfit (chubby, fat, obese)
	-added nice nurse outfit (chubby, fat, obese)
	-added penitent nuns habit outfit (chubby, fat, obese)
	-added red army uniform outfit (chubby, fat, obese)
	-added scalemail bikini outfit (chubby, fat, obese)
	-added schoolgirl outfit (chubby, fat, obese)
	-added schutzstaffel uniform outfit (chubby, fat, obese)
	-added schutzstaffel uniform slutty outfit (chubby, fat, obese)
	-added shine outfit [Only applies to latex] (chubby, fat, obese)
	-added shibari rope outfit (chubby, fat, obese)
	-added slutty outfit (chubby, fat, obese)
	-reworked slutty outfit (changed to pasties)
	-added slave gown outfit (chubby, fat, obese)
	-added slutty business attire outfit (chubby, fat, obese)
	-added slutty jewelry outfit (chubby, fat, obese)
	-added slutty maid outfit (chubby, fat, obese)
	-added slutty nurse outfit (chubby, fat, obese)
	-updated slutty nurse outfit (now with 100% more hat)
	-added slutty qipao outfit (chubby, fat, obese)
	-added spats outfit (chubby, fat, obese)
	-added stretch pants outfit (chubby, fat, obese)
	-added string bikini outfit (chubby, fat, obese)
	-added succubus outfit (chubby, fat, obese)
	-added toga outfit (chubby, fat, obese)
	-added uncomfortable strap outfit (chubby, fat, obese)
	-added western outfit (chubby, fat, obese)
	-added eyes type-a
	-added mouth type-a
	-added nose type-a
	-added eyebrows type-a pencilthin
	-added eyebrows type-a thin
	-added eyebrows type-a threaded
	-added eyebrows type-a natural
	-added eyebrows type-a tapered
	-added eyebrows type-a thick
	-added eyebrows type-a bushy
	-added eyes type-b
	-added mouth type-b
	-added nose type-b
	-added eyebrows type-b pencilthin
	-added eyebrows type-b thin
	-added eyebrows type-b threaded
	-added eyebrows type-b natural
	-added eyebrows type-b tapered
	-added eyebrows type-b thick
	-added eyebrows type-b bushy
	-added eyes type-c
	-added mouth type-c
	-added nose type-c
	-added eyebrows type-c pencilthin
	-added eyebrows type-c thin
	-added eyebrows type-c threaded
	-added eyebrows type-c natural
	-added eyebrows type-c tapered
	-added eyebrows type-c thick
	-added eyebrows type-c bushy

v1.1 (07-11-2018)
-------------
	-added torso chubby
	-added torso fat
	-added torso obese
	-added butt enormous
	-added butt gigantic
	-added butt massive
	-added legs thick
	-added butt outfits enormous (x56)
	-added butt outfits gigantic (x56)
	-added butt outfits massive (x56)
	-fixed crotch coloring for dicks on dirndl
	-fixed crotch coloring for dicks on lederhosen
	-fixed crotch coloring for dicks on battlearmor
	-fixed crotch coloring for dicks on mounty outfit
	-fixed crotch coloring for dicks on long qipao
	-fixed crotch coloring for dicks on biyelgee costume
	-added leg outfits thick (x56)

v1.0 (07-03-2018)
-------------
	-added long qipao outfit
	-added battlearmor outfit
	-added mounty outfit
	-added dirndl outfit
	-added lederhosen outfit
	-added biyelgee costume outfit
	-added tiny nipple art
	-added cute nipple art
	-added puffy nipple art
	-added inverted nipple art
	-added huge nipple art
	-added fuckable nipple art
	-added partially inverted nipple art

v0.9 (05-05-2018)
-------------
	-added dynamic belly scaling (courtesy of @prndev)
	-added belly button art
	-fixed belly piercings not showing
	-updated belly piercing art
	-added belly outfit apron
	-added belly outfit bodysuit
	-added belly outfit cheerleader
	-added belly outfit clubslut
	-added belly outfit cutoffs (base only)
	-added belly outfit cybersuit
	-added belly outfit fallen nun (base only)
	-added belly outfit haltertop dress
	-added belly outfit hijab and ayaba
	-added belly outfit latex catsuit
	-added belly outfit leotard
	-added belly outfit nice maid
	-added belly outfit slutty maid
	-added belly outfit military (base only)
	-added belly outfit minidress
	-added belly outfit monokini (base only)
	-added belly outfit nice nurse
	-added belly outfit slutty nurse (base only)
	-added belly outfit red army uniform (base only)
	-added belly outfit schoolgirl (base only)
	-added belly outfit schutzstaffel (base only)
	-added belly outfit silken ballgown
	-added belly outfit skimpy battldress (base only)
	-added belly outfit slave gown
	-added belly outfit spats and a tank top (base only)
	-added belly outfit succubus (base only)
	-added belly outfit suit nice (base only)
	-added belly outfit suit slutty (base only)
	-added belly outfit bunny outfit
	-added belly outfit chattel habit (base only)
	-added belly outfit conservative clothing (base only)
	-added belly outfit harem gauze (base only)
	-added belly outfit huipil
	-added belly outfit kimono (base only)
	-added belly outfit maternity dress
	-added belly outfit slutty qipao
	-added belly outfit toga
	-added belly outfit western clothing
	-added belly outfit penitent nun (base only)
	-added belly outfit restrictive latex
	-added freckles as misc facial feature
	-added heavy freckles as misc facial feature
	-added beauty mark as misc facial feature
	-added birthmark as misc facial feature
	-minor outfit polishing on some outfits
	-polished outlines on torso art (normal, narrow, absurd)
	-reworked naked apron outfit
	-updated bangles outfit
	-fixed problems when surgically altering a slave's race
	-reworked clubslut netting outfit
	-updated cheerleader outfit
	-added AI personal assistant art
	-added blue-violet hair color
	-updated deep red hair color
	-added shaved armpit hair
	-added neat armpit hair
	-added bushy armpit hair
	-fixed male genitalia showing over large bellies
	-added porcelain mask accessory
	-added ability to custom color porcelain mask
	-added ability to custom color glasses
	-added slutty schutzstaffel uniform

v0.8 (04-21-2018)
-------------
	-added wispy pubic hair
	-added areola normal art
	-added areola large art
	-added areola wide art
	-added areola huge art
	-added areola star-shaped art
	-added areola heart-shaped art
	-converted stockings to a leg accessory
	-fixed issue that allowed stockings to be shown/selected on amputees
	-added visor hat to military outfit (per request)
	-fixed tilted neat pubic hair
	-fixed bellies/corsets showing at the same time if present/selected
	-major overhaul of skin tones
	-tweaked leg/hipsize/weight art distribution
	-fixed vaginal piercings not showing
	-updated vaginal piercing art
	-created porcelain mask accessory art
	-added cybersuit outfit
	-added skin/nipple tones for every race (courtesy of skinAnon)
	-added naked apron outfit
	-added schutzstaffel uniform
	-added red army uniform
	-darkened stocking art slightly (per request)

v0.7 (04-14-2018)
-------------
	-added sleeves to hijab and abaya outfit
	-added sleeves to cutoffs and a t-shirt outfit
	-added sleeves to skimpy battledress outfit
	-added sleeves to conservative outfit
	-added sleeves to huipil outfit
	-added sleeves to kimono outfit
	-added sleeves to nice maid outfit
	-added sleeves to military uniform outfit
	-added sleeves to nice nurse outfit
	-added sleeves to slutty nurse outfit
	-added sleeves to slutty qipao outfit
	-added sleeves to schoolgirl outfit
	-added sleeves to nice suit outfit
	-added sleeves to slutty suit outfit
	-added sleeves to western clothing outfit
	-removed thigh-highs/stockings on most outfits
	-fixed nipple piercings showing incorrectly
	-fixed boots showing incorrectly on some outfits
	-fixed 'invisible balls' on one of the scrotum sizes (the shadow was showing as skin color, removing the outline)
	-slutty nurse outfit now better matches the description
	-updated thigh boot art
	-updated extreme heel art
	-added bare feet stocking outfits (Long/short)
	-added additional flat shoe outfits (bare/stockings short/stockings long)
	-added additional heel shoe outfits (bare/stockings short/stockings long)
	-added additional pump shoe outfits (bare/stockings short/stockings long)

v0.6 (04-07-2018)
-------------
	-fixed bodysuit outfit color issue on non-default colors
	-fixed restrictive latex color issue on non-default colors
	-added hairstyle 'messy bun' (long/medium/short)
	-added hairstyle 'dreadlocks' (long/medium/short)
	-added hairstyle 'cornrows' (long/medium/short)
	-added hairstyle 'braided' (long/medium/short)
	-added hairstyle 'twintails' (long/medium/short)
	-added hairstyle 'shavedsides' (long/medium/short)
	-added chains outfit
	-added penitent nun outfit
	-reworked male genitalia
	-added bulge outfits for the appropriate outfits
	-removed transparency on clubslut, harem, and slutty torso outfits due to multiple issues
	-overhauled clubslut outfit to fix numerous art issues.
	-changed extreme heels
	-changed thigh high boots
	-overhauled breasts
	-reworked all breast outfits due to breast overhauled
	-changed breast positioning relative to the overall body
	-reworked corset lengths
	-reworked all breast and torso outfits for new breast compatibility

v0.5 (03-31-2018)
-------------
	-added belly scaling w/pregnancy+overfeeding
	-minor polishing on all outfits
	-fixed piercings not showing correctly
	-added nipple light piercings
	-added areola light piercings
	-added nipple heavy piercings
	-added areola heavy piercings
	-added vaginal dildo accessory
	-added vaginal long dildo accessory
	-added vaginal large dildo accessory
	-added vaginal long, large dildo accessory
	-added vaginal huge dildo accessory
	-added vaginal long, huge dildo accessory
	-added anal long plug accessory
	-added anal large plug accessory
	-added anal long, large plug accessory
	-added anal huge plug accessory
	-added anal long, huge accessory
	-added anal tail plug accessory (anal hook/bunny tail)
	-added first trimester pregnancy empathy belly
	-added second trimester pregnancy empathy belly
	-added third trimester pregnancy empathy belly
	-added third trimester twin pregnancy empathy belly
	-added tight corset torso accessory
	-added extreme corset torso accessory
	-cleaned up changelog wording for clarity purposes
	-added uncomfortable leather collar outfit
	-updated dildo gag collar graphic art
	-added massive dildo gag collar outfit
	-added ball gag collar outfit
	-added bit gag collar outfit
	-added silken ribbon collar outfit
	-added bowtie collar outfit
	-added ancient egyptian collar outfit
	-added hairstyle 'neat' (long/medium/short)
	-added hairstyle 'up' (long/medium/short)
	-added hairstyle 'ponytail' (long/medium/short)
	-added hairstyle 'bun' (long/medium/short)
	-added hairstyle 'curled' (long/medium/short)
	-added hairstyle 'messy' (long/medium/short)
	-added hairstyle 'permed' (long/medium/short)
	-added hairstyle 'eary' (long/medium/short)
	-added hairstyle 'luxurious' (long/medium/short)
	-added hairstyle 'afro' (long/medium/short)
	-fixed cowboy hat not showing on western outfit
	-fixed baldness on generic/generated non-selectable hairstyles

v0.4 (03-24-2018)
-------------
	-added nice lingerie outfit
	-fixed immersion breaking art on specific flat-chested outfits (somewhat)
	-added nurse slutty outfit
	-added silken ballgown outfit
	-added skimpy battledress outfit
	-minor polishing on all outfits
	-added slutty outfit
	-added spats and a tank top outfit
	-fixed graphical issues on mini dress
	-added succubus outfit
	-added nice suit outfit
	-added slutty suit outfit
	-added attractive lingerie for a pregnant woman outfit
	-added bunny outfit
	-added chattel habit outfit
	-updated fallen nun outfit (headdress added)
	-added conservative clothing outfit
	-added harem gauze outfit
	-added huipil outfit
	-added kimono outfit
	-added slave gown outfit
	-added stretch pants and a crop top outfit
	-updated schoolgirl outfit (sweater vest added)
	-added slutty qipao outfit
	-added toga outfit
	-added western clothing outfit (no cowboy hat)
	-fixed dick/ball clipping issues on all relevant outfits
	-added natural color nipples to match racial skin tones

v0.3 (03-17-2018)
-------------
	-added schoolgirl outfit
	-added fallennun outfit
	-added nice maid outfit
	-added slutty maid outfit
	-updated minidress outfit (changed color+fixes)
	-minor polishing on some outfits
	-added niqab and abaya outfit (niqab > hijab)
	-changed white colors on outfits to grey for increased contrast on light skin tones.
	-added nice nurse outfit
	-fixed outline issues on boots/extreme heels
	-fixed ultra black hair color issue (vanilla only)
	-added military uniform outfit
	-updated to latest pregmod git

v0.2 (03-10-2018)
-------------

	-added string bikini outfit
	-added scalemail bikini outfit
	-updated male genitalia display position
	-set default shoe colors to neutral (per request)
	-added some natural color nipples to match racial skin tones

v0.1 (03-03-2018)
-------------
	-updated boob graphic art
	-updated nipple graphic art
	-updated arm graphic art
	-updated female genitalia graphic art
	-updated waist graphic art
	-updated butt graphic art
	-added bushy pubic hair
	-added very bushy pubic hair
	-updated vaginal chastity belt
	-updated anal chastity belt
	-added uncomfortable strap outfit
	-added shibari rope outfit
	-updated restrictive latex outfit
	-updated latex catsuit outfit
	-updated extreme heel graphic art
	-updated pump shoes graphic art (not selectable in-game yet)
	-added bodysuit outfit
	-added body oil outfit
	-added haltertop dress outfit
	-added bangles outfit
	-added mini dress outfit
	-added leotard outfit
	-added t-shirt and cutoffs outfit
	-added cheerleader outfit
	-added clubslut netting outfit


code:
This document gives an overview of some of the economic mechanics, especially the ones spread across multiple files and functions.

Determining the prices for whoring;

The general principle behind the pricing is one of supply and demand.
Getting our hands on the appropriate information takes some doing due to how the game operates.
Supply and demand needs to be determined before the slave reports are generated, as such it takes place at the top of 'slaveAssignmentsReport.tw'.
Finding the demand is relatively straightforward, as it depends on the current arcology population of the various classes as well as visitors.
Finding the supply requires more work as all slaves tasked with sexually serving the populace need to be considered.
The function 'slaveJobValues()' takes care of pretty much all of that and can be found in 'economyJS.js'.

'slaveJobValues()' takes into account gloryholes/arcade, public sluts/club sluts and street whores/brothel whores seperately.
Gloryhole prices aren't too involved, since the 'product' is very homogenous and sluts don't get paid for their services.
Whores on the other hand have variable skills and appearance and may appeal to different classes of citizens.

'SJVBrothel()' takes care of general bonuses/penalties that all jobs have to some degree.
Near the end it determines the 'value' of the whore by taking the above bonus, their 'beauty()' and their 'FResult()' score.
Previously 'beauty()' determined the number of sexual acts and 'FResult()' the price for them.
With the distinction between classes and the kind of sexual services they demand it became glaring that the best quality whores were used most heavily.
Shouldn't these talented slaves should be MORE exclusive, not less?

The function whoreScore() will be taking care of this oddity and it uses 'beauty()' * 'FResult()' as well as applicable modifiers to give us an 'income' variable.
This 'income' is the basis for the money the slave will be making, but will still be going through some modifications before the actual figure is produced later.
This is the amount of money they used to make and are still expected to make under standard circumstances but now it will be divided between sexual acts and their value in a different fashion.
whoreScore() also takes care of some slave sorting according to supply and demand.
Whenever the demand of the class a slave is trying to service is already met the function will determine if the slave should perhaps service a lower class instead.
It uses effectiveWhoreClass() to find out the maximum possible class a slave can service (or is allowed to service by the player), and demotes a slave for the week as needed.
After the class of citizens the slave will service is set the function takes care of the specific 'sexAmount' and 'sexQuality' the slave is providing.
The higher the class the more time and attention they demand from their whores. Generally a better slave servicing a higher class will fuck less than a lesser slave servicing a lower class.
The price per service is adjusted to compensate; 'income' is the basis, 'sexAmount' is partially set by the class serviced and 'sexQuality' is 'income' / 'sexAmount'.
There is a maximum for the 'sexAmount' and 'sexQuality' for each class; On the one hand the slave only has so much time in the day and on the other citizens will only pay a particular amount of money.
There is also a minimum for 'sexAmount'; a slave assigned to whore is expected to be working hard for the entire assignment, if needed the price will be adjusted to ensure a full work week for every slave.
The maximum amount of money a citizen is willing to pay depends on the rent they need to pay. Less rent means they have more spending money for other things, including whores.
Additionally servicing a higher class also comes with a little bonus in and of itself.

'slaveJobValues()' aggregates all sexual services done by a player's slaves, thus at the end of this function we know the supply provided by the player.
We must also consider the supply by other providers operating within the arcology, but this is relatively straightforward.
Combine the two and we now have the total supply for that week and we can finally compare supply and demand to provide a final price modifier.
Each class of citizens has their own demand and supply statistics and thus their own price modifier as well.
All of this once again takes place within the top part of 'slaveAssignmentsReport.tw'.
When demand outstrips supply, a whore will recieve a premium for their services, but not proportionally.
Supplying only half of what is demanded does not mean prices are doubled, they'll be increased by less than that.
Likewise when supply outstrips the demand a whore will recieve less for their services, but not proportionally.
Doubling the demand reduces the price by significantly more than 50%.
There is however an absolute minimum of 30% of the standard price.

Finally, as each slave has their report generated they will actually be earning 'sexAmount' * 'sexQuality' * supply/demand modifier.

path: devNotes/Economy notes.txt


code:
Extended family mode (mod)

In short, extended family mode replaces the old .relation + .relationTarget system with a completely new system capable of handling a limitless number of relatives. Or at least until your game crashes from trying to handle it all. Fully incompatible with the old system and fully functional with ng+.

The backbone of the system: .father and .mother

Everything about a slave's family can be gathered by looking into her mother and father. Beyond the obvious mother-daughter relation, you can check two separate slaves' parents to see if they are related to each other, allowing for sisters, half-sisters, and with a .birthWeek check, twins with little effort.
The following values are used with .mother and .father:
Valid slave IDs (in other words, a value > 0) - Serves as both a target for checks and as a check itself to see if effort should be expended to search for the parent.
0 - Slave has no known parent. A slave with a parent value of 0 is capable of having a parent added via reRelativeRecruiter
MissingParentIDs (in other words, a value < -2) - Serves as a placeholder to preserve sibling relations in the case of a parent being sold or lost. Outside of extreme cases, this value will never be restored to its' previous value. $missingParentID starts at -10000 and decrements after application. On NG+, positive values are incremented the same as a normal slave and checked for validity. Should it be invalid, it will be replaced with $missingParentID. Negative values, on the other hand, are decremented by 1200000. Values of -1 and -2 are ignored by the JS, so don't use them. Also -9999 through -9994 are used by hero slaves to preserve their sibling status no matter when they are purchased or obtained during the same game.

The limiters: .sisters and .daughters
Extended family mode is VERY for loop intensive, and as such, has limiters to prevent it from needlessly looping. A value greater than 0 for either of these slave variables signals that slave has a sibling/daughter for various checks. Furthermore, the value of .sisters and .daughters accurately tracks the number of sisters and daughters, particularly for checks that require all of them to be found. You'll learn to hate these, but on the plus side, they can safely be recalculated with no side effects. Nearly entirely handled by <<AddSlave>> and removeActiveSlave, you do not understand how huge of a plus this is.

The recruiting check: .canRecruit

Checked by reRelativeRecruiter to see if a slave is eligible to have relatives added. Hero slaves, special slaves, and often event slaves are ineligible for recruiting. Gets disabled if the slave is called into the recruiting event but fails to qualify for additional relatives due to unaddable slots or too many existing relatives.

A quick list of the JS that gets things done and various useful JS calls:

sameDad(slave1, slave2) - checks if the slaves share the same father and returns true/false.
sameMom(slave1, slave2) - checks if the slaves share the same mother and returns true/false.
sameTParent(slave1, slave2) - an exception catcher that handles such things as "slave1 knocked up slave2 and got impregnated by slave2, their children will be sisters" and returns the sister variable (0 - not related, 1 - twins, 2 - sisters, 3 - half-sisters). (subJS, never call on its own)
areTwins(slave1, slave2) - checks if the slaves are twins and returns true/false.
areSisters(slave1, slave2) - combines all of the above and returns the sister variable (0 - not related, 1 - twins, 2 - sisters, 3 - half-sisters). A widely used check to identify sister relatives. Generally gated by a .sisters check. Recommended to use in a <<switch>> macro instead of calling it for each outcome.

totalRelatives(slave) - returns how many relatives a slave has as an integer. Useful both as a check and for its value. Recommended to use as a check in instances where you want a relative, but don't care what it is.

mutualChildren(slave1, slave2, slaves) - checks the slave array for children shared by the two slave arguments and returns the number of mutual children as an integer. Currently used solely to encourage two slaves into a relationship if they have kids together.

The utility JS, courtesy of FCGudder. This JS should only be called if you know it will find something, use your limiters! These will always return the only relative if only one outcome is possible, so technically they can be used creatively. randomAvailable JS should be followed with random JS as a fallback for circumstances where you must find something, but would prefer it to be sensible if possible.
randomRelatedSlave(slave, filterFunction) - returns a random related slave to the slave passed into it. filterFunction is called in the following JS but not needed if you just want a random relative.
randomRelatedAvailableSlave(slave) - returns a random available related slave.
randomSister(slave) - returns a random sister.
randomAvailableSister(slave) - returns a random available sister.
randomTwinSister(slave) - returns a random twin.
randomAvailableTwinSister(slave) - returns a random available twin.
randomDaughter(slave) - returns a random daughter.
randomAvailableDaughter(slave) - returns a random available daughter.
randomParent(slave) - returns a random parent.
randomAvailableParent(slave) - returns a random available parent.

path: devNotes/Extended Family Mode Explained.txt


code:
Security Expansion

	10/18/17

	1

	3

	10/22/17

	5

	10/24/17

	6
	-balance adjustments
	-fixed improper name assignment
	-added renaming of units
	-reworked casualties logic
	-added statistics to arcology management screen
	-various other fixes

	10/28/17

	7
	-SFanon additions
	-fixes
	-balance

	10/29/17

	7.1
	-fixes
	-couple of balance adjustments.

	11/01/17

	7.5

	7.6
	-fixed reported issue
	-balance adjustments (run backward compatibility to apply them)

	7.7

	11/03/17

	8
	-various fixes
	-balance
	-rebellions

	11/05/17

	8.5
	-fixes
	-rebellions

	11/06/17

	Pregmod v113

	8.6
	-fixes

	8.7
	-fixed reported issue maybe pretty please?

	11/07/17

	Pregmod v114/Pregmod v114.1

	8.8
	-fixes

	9.2
	-small fixes
	-new edicts
	-new units upgrade
	-new barracks upgrade

	Pregmod v115

	9.6
	-fixes
	-loyalty work

	11/09/17

	Pregmod v119

	9.6
	-small fixes

	11/10/17

	10
	-fixes
	-weapons manufacturing
	-balance

	11/11/17

	Pregmod v121

	10.2
	-fixes

	Pregmod v122

	11
	-fixes
	-proclamations
	-balance

	11.1

	11.2
	-fixes
	-extra options

	11/12/17

	Pregmod v124

	11.5
	-fixes
	-balance

	11.6
	-fixed reported issues
	-balance

	Pregmod v125

	12
	-fixes
	-transport hub and trade
	-balance

	11/13/17

	12.3
	-fixes
	-SFanon additions
	-balance

	Pregmod v126

	12.4

	11/14/17

	Pregmod v130

	12.5
	-fixes
	-SFanon stuff
	-balance

	Pregmod v132

	12.6
	-fixes
	-anon's stuff

	12.8
	-fixes
	-balance

	12.9
	-fixes

	11/15/17

	13
	-fixes
	-balance

	11/16/17

	13.1
	-fixes
	-balance

	13.3
	-fixes

	13.4
	-fixed >>142293 (Attack value NaN during major battle)

	11/17/17

	Pregmod v135

	13.4
	-fixes
	-balance
	-difficulty settings

	Pregmod v136

	13.6
	-fixes

	11/18/17

	13.7
	-balance
	-(maybe) fix for battle terrain not showing up.

	13.8
	-(maybe) fixed >>142732

	Pregmod v137

	v13.9
	-fixes (couple of)

	Pregmod v139

	14
	-fixes
	-spell checked attack report. My god was is bad.

	14.1
	-fixes

	11/20/17

	14.2
	-fixes
	-balance
	-very satisfying version number.


code:
# The pronouns system #
All references to scene actors shall be made via the pronouns object, returned by the `getPronouns()` function. The properties of the returned object contains strings to be used for referring to the actor or his actions. The object presents three property groups. The first one refers to pronouns by their grammatical names ('noun', 'object', 'pronoun', etc.). The rest of the groups provide the same values, but referred using gender-dependent names: he/she, his/her, etc. They are meant to be used in passage texts, and you can choose any group you like, the actual strings will be based on the slave object, which was passed as argument in the `getPronouns()` call.

## Usage examples ##

```js
const s = getPronouns(aSlave);
`Use ${s.his} mouth`
`Fuck ${s.him}`
`${s.He} is ready`
```

```
<<set _p = getPronouns(aSlave)>>
<<= _p.Girl>>s' butts are for loving
```

## Extending the pronouns system. ##

Consider a degradationism-based society where a slave is a thing. To extend the pronouns system, we create a successor of the `App.Utils.Pronouns` class:

```js
App.Utils.ThingPronouns = class extends App.Utils.Pronouns {
	get pronoun() { return "it" }
	get possessivePronoun() { return "its"; }
	get possessive() { return "its"; }
	get object() { return "its"; }
	get objectReflexive() { return "itself"; }
	get noun() { return "thing"; }
};
```
Notice, we override only the basic gender-neutral properties, and the rest of them use these values. Then we modify the `getPronouns()` code:

```js
if (/*degradationist society condition*/) {
	return new App.Utils.ThingPronouns(slave);
}
return new App.Utils.Pronouns(slave);
```


code:
QuickList is built from the interaction of six parts.

1] The Quick List option enable/disable control.
2] The list context, basically if there are more than one, and the
	context is correct, the toggle, the table will be available.
3] The Slave Summary Passage contains the Quick List toggle button,
	clicking it either shows or hides the quick list table.
4] The Slave Summary Passage contains the actual quick list table, which
	if shown has a button for each slave name in the list, in columns up
	to 5 wide.
5] The Slave Summary Passage contains invisible <a> links or any other
	html element nearby or tied to each slave's name. These are
	generated with an html attribute id set to "slave-##" where ## is the
	slave's ID.
6] The JS code to tie a scroll animation from the visible name buttons
	in the quick list table down to the invisible links/elements.

The slave summary passage is called in many strange contexts, and for
this reason, there is some serious complexity in getting consistent
results. As it stands now, the passage sometimes calls itself
recursively (for facilities), but it doesn't do that for the Main
penthouse page.

The list context is duplicated, so that we can quickly loop over the
list context to get the slave names in the list, all without disturbing
the principal list context for the slave data.

If the list context has more than one slave, and is either the first
call for the Main/penthouse list, or the recursive call for any other
facility, And we haven't *already* built a quick list table, then we
proceed to build the quick list table.

We use special attributes on the built button to name the invisible
link to which we'll navigate, the speed that we'll animate our
navigation and an offset.


code:
Assay Functions:

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.

haveRelationP(slave1, slave2) - Returns if slave1 is related to second slave2. (NOT extended family mode compliant).

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.

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.

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

Display Functions:

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)

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.)

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])>>'

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

lispReplace(string) - Returns the string lispified.

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()

	between(a, low, high) - outputs the value down the middle of two inputs e.g.
		between($trees, 1, 3) returns $trees = 2

	def() - Returns whether the input is defined, similar to sugarcube's def.

Core Slave Functions:

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.

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

Enunciate(slave) - Syncs lisp widgets with slave.

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)

generatePronouns(slave) - Sets slave's pronouns.

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

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

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

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

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

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:

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:

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:

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 pregancy early, clean the womb, update the belly size, and automatically set an appropriate postpartum length.

$slave.bellyPreg = WombGetWolume($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:

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:

isItemAccessible(itemName) - Returns if the string is available for use. Defaults to true.

UtilJS [script]
	html5passage(passage_function) - circumvents sugarcube, allowing a plain HTML5 UI within it

	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. */

	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 likelyhood of a slave ignoring the rules.

path: devNotes/Useful JS Function Documentation.txt


code:
Passages that require a go over for adding clothing and accessories.

Hair:

	Definite:
		descriptionWidgetsStyle.tw
		salon.tw
		cosmeticRulesAssistant.tw

	Possible:
		generateXXSlave.tw
		generateXYSlave.tw
		artWidgets.tw
		saLiveWithHG.tw

		(mostly shaved/bald hairstyle checks, probably not worth checking)
		fPat.tw
		remoteSurgery.tw
		suregeryDegradation.tw
		saLongTermEffects.tw
		saAgent.tw
		rulesAutosurgery.tw
		autoSurgerySettings.tw
		ptWorkaround.tw
		newSlaveIntro.tw
		newChildIntro.tw
		RESS.tw

Clothes:

	Definite:
		descriptionWidgetsStyle.tw
		descriptionWidgetsFlesh.tw
		descriptionWidgetsPiercing.tw
		boobs.js
		fAbuse.tw
		walkPast.js
		slaveInteract.tw
		wardrobeUse.tw
		slaveSummaryWidgets.js
		rulesAssistantOptions.js
		toyChest.js
		useGuard.js
		birthWidgets.tw
		peConcubineInterview.tw
		PESS.tw
		RESS.tw

	Possible:
		artWidgets.tw
		saClothes.tw
		saChoosesOwnClothes.tw
		eventSelectionJS.js
		saLiveWithHG.tw
		setupVars.tw
		longSlaveDescription.tw

Shoes:

	Definite:
		descriptionWidgetsStyle.tw
		descriptionWidgetsFlesh.tw
		slaveInteract.tw
		walkPast.tw
		wardrobeUse.tw
		slaveSummaryWidgets.js
		rulesAssistant.tw

	Possible:
		saLongTermEffects.tw
		saClothes.tw
		saChoosesOwnClothes.tw
		eventSelectionJS.js
		RESS.tw
		REFI.tw
		saServeThePublic.js
		saWhore.js
		saLiveWithHG.tw
		artWidgets.tw
		reStandardPunishment.tw
		setupVars.tw
		fAnus.tw
		seBirthWidgets.tw
		raWidgets.tw

Collars:

	Definite:
		descriptionWidgetsStyle.tw
		fLips.tw
		walkPast.js
		slaveInteract.tw
		fKiss.tw
		wardrobeUse.tw
		rulesAssistant.tw
		RESS.tw

	Possible:
		saLongTermEffects.tw
		saClothes.tw
		saDevotion.tw
		raWidgets.tw
		artWidgets.tw
		reStandardPunishment.tw
		saChoosesOwnClothes.tw
		eventSelectionJS.tw
		assayWidgets.tw

--------------------------------------------------------------------------------------
OUTFITS BY TYPE — FOR REFERENCE ONLY

SEXUAL/EROTIC
=============
	Kitty Lingerie
	Slutty Jewelry
	Fallen Nun
	Chattel Habit
	Body Oil
	Pregnant Lingerie
	Nice Lingerie
	Latex Catsuit
	Bodysuit
	Skimpy Loincloth
	BDSM Pony outfit

FESTIVE/ENTERTAINMENT/TRADITIONAL/CULTURAL
=================================
	Kimono
	Qipao nice/slutty
	Biyelgee Costume
	Harem Gauze
	Dirndl
	Klan Robes
	Lederhosen
	Western Clothing
	Toga
	Huipil
	Bunny Outfit
	Succubus Costume
	Ballgown
	Slavegown
	Minidress
	Haltertop Dress
	Clubslut Netting
	Santa Dress
	Hanbok
	Gothic Lolita

EXERCISE/ATHLETICS
==================
	Leotard
	Monokini
	Stretch pants + croptop
	Spats and tank-top
	String Bikini
	Scalemail Bikini
	Cheerleader

CASUAL/DAILY
============
	Shimapan panties
	Hijab and Abaya
	Hijab and Blouse
	Niqab and Abaya
	Burqa
	Burkini
	Conservative Clothing
	Maternity Dress
	Schoolgirl
	Cutoffs + T-shirt
	Apron

PROFESSIONAL/OTHER
==================
	Maid Nice/Maid Slutty
	Suit nice/slutty
	Nurse nice/slutty

MILITARY/LAW ENFORCEMENT
========================
	Mounty
	Schutzstaffel Uniform nice/slutty
	Red Army Uniform
	Battledress
	Military Uniform
	Battlearmor
	Cybersuit
	Police outfit [Not in-game yet]

path: devNotes/clothing hair and accessory passages.txt