diff --git a/Makefile b/Makefile index 28ec6b6baba5eca0eca67bc5c5a564bb1677dcb4..227c2b27fb8a1863a869016e964452bdfb51d0ff 100644 --- a/Makefile +++ b/Makefile @@ -33,8 +33,12 @@ bin/%.html: bin/tmp git checkout -- src/gui/mainMenu/AlphaDisclaimer.tw mv $< $@ -bin/tmp: bin/ src/gui/mainMenu/AlphaDisclaimer.tw - $(TWEEGO) src/ --head devTools/head.html > $@ +bin/fc.js: bin/ + devTools/concatFiles.sh js/ '*.js' $@ + +bin/tmp: bin/fc.js src/gui/mainMenu/AlphaDisclaimer.tw + $(TWEEGO) --module=bin/fc.js --head devTools/head.html src/ > $@ + rm -f bin/fc.js src/gui/mainMenu/AlphaDisclaimer.tw: sed -Ei "s/build .releaseID/\0 commit $(COMMIT)/" $@ @@ -45,7 +49,4 @@ bin/: sanity: ./sanityCheck.sh -jsanity: - ./sanityCheck.sh java - -.PHONY: all sanity jsanity git +.PHONY: all sanity git diff --git a/compile.bat b/compile.bat index ad3570dfc45fe2b8291d3652546ccab784faa625..2a06b08270c083d45c949ee958095a248b32b52d 100644 --- a/compile.bat +++ b/compile.bat @@ -4,12 +4,14 @@ :: 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" --head devTools/head.html "%~dp0src" + 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" --head devTools/head.html "%~dp0src" + 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 diff --git a/compile.sh b/compile.sh index dc9140f965b049e6f595d1f0bca62b50d32f8a47..53265b8640a82828176aedd42bdb078b04e66265 100755 --- a/compile.sh +++ b/compile.sh @@ -11,8 +11,7 @@ Options: -d, --dry Do not compile -g, --git Add hash of HEAD to filename -h, --help Show this help text - -j, --java Run sanityCheck based on java (recommended) - -p, --python Run sanityCheck based on python + -s, --sanity Run sanityCheck -q, --quiet Suppress terminal output HelpText } @@ -76,7 +75,9 @@ function compile { file="bin/FC_pregmod.html" fi - $TWEEGO_EXE -o $file src/ --head devTools/head.html || build_failed="true" + 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." @@ -109,11 +110,8 @@ else displayHelp exit 0 ;; - -j|--java) - java="true" - ;; - -p|--python) - python="true" + -s|--sanity) + sanity="true" ;; -q|--quiet) output=/dev/null @@ -128,8 +126,7 @@ else fi # Run sanity check. -[ -n "$java" ] && ./sanityCheck.sh java -[ -n "$python" ] && ./sanityCheck.sh +[ -n "$sanity" ] && ./sanityCheck.sh if ! [[ -d .git ]]; then echoMessage "No git repository. Git specfific actions disabled." diff --git a/compile_debug+sanityCheck.bat b/compile_debug+sanityCheck.bat index b1e531e72ded2721cc44054c77a64b04e5916d3f..3e95998da4dd6d15710cd9b747f8dc01cb7f79c8 100644 --- a/compile_debug+sanityCheck.bat +++ b/compile_debug+sanityCheck.bat @@ -21,7 +21,7 @@ for %%k in (HKCU HKLM) do ( :FOUND if %GITFOUND% == yes ( set "PATH=%GIT%bin;%PATH%" - bash --login -c "./sanityCheck.sh java" + bash --login -c "./sanityCheck.sh" ) :: Compile the game diff --git a/compile_debug+sanityCheck_legacy.bat b/compile_debug+sanityCheck_legacy.bat deleted file mode 100644 index d5e38d6426a6d4028cbcb3a8a86e7b8ddccbb2b0..0000000000000000000000000000000000000000 --- a/compile_debug+sanityCheck_legacy.bat +++ /dev/null @@ -1,39 +0,0 @@ -@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 diff --git a/devTools/check.py b/devTools/check.py deleted file mode 100755 index 07cee14ca24984aae9b1ae177b7a2253d85d8299..0000000000000000000000000000000000000000 --- a/devTools/check.py +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env python3 -import fileinput -import re -import sys - -WARNING = '\033[93m' -ENDC = '\033[0m' - -def myprint(*args): - print(WARNING, fileinput.filename() + ":", ENDC,*args) - -def yield_line_and_islastline(f): - global filename - global linenumber - try: - prevline = next(f) - filename = fileinput.filename() - linenumber = fileinput.filelineno() - except StopIteration: - return - for line in f: - yield (prevline, f.isfirstline()) - filename = fileinput.filename() - linenumber = fileinput.filelineno() - prevline = line - yield prevline, True - -pattern = re.compile(r'(<<(\/?) *(if|for|else|switch|case|replace|link)[^<>]*)') - - -tagfound = [] -try: - for line, isLastLine in yield_line_and_islastline(fileinput.input()): - for (whole,end,tag) in re.findall(pattern,line): - if tag == "else" or tag == 'case': - if len(tagfound) == 0: - myprint("Found", tag, "but with no opening tag:") - myprint(" ", linenumber,":", whole) - fileinput.nextfile() - lasttag = tagfound[-1] - if (tag == "else" and lasttag["tag"] != "if") or (tag == "case" and lasttag["tag"] != "switch"): - myprint("Mismatched else: Opening tag was:") - myprint(" ",lasttag["linenumber"],":", lasttag["whole"]) - myprint("But this tag was:") - myprint(" ",linenumber,":", whole) - fileinput.nextfile() - break - elif end != '/': - tagfound.append({"whole": whole, "linenumber":linenumber,"tag":tag}) - else: - if len(tagfound) == 0: - myprint("Found closing tag but with no opening tag:") - myprint(" ", linenumber,":", whole) - fileinput.nextfile() - break - lasttag = tagfound.pop() - if lasttag["tag"] != tag: - myprint("Mismatched tag: Opening tag was:") - myprint(" ",lasttag["linenumber"],":", lasttag["whole"]) - myprint("Closing tag was:") - myprint(" ",linenumber,":", whole) - fileinput.nextfile() - break - - - if isLastLine: - if len(tagfound) != 0: - myprint("End of file found but", len(tagfound), ("tag hasn't" if len(tagfound)==1 else "tags haven't"), "been closed:") - for tag in tagfound: - myprint(" ", tag["linenumber"],":", tag["whole"]) - tagfound = [] -except UnicodeDecodeError as e: - myprint(e) - print(" Hint: In Linux, you can get more details about Unicode errors by running:") - print(" isutf8", fileinput.filename()) - print(" :Note it might be caused by ", filename) diff --git a/devTools/concatFiles.bat b/devTools/concatFiles.bat new file mode 100644 index 0000000000000000000000000000000000000000..cce8129af35c054ac8f951eef9818ff8ae4aa08d --- /dev/null +++ b/devTools/concatFiles.bat @@ -0,0 +1,14 @@ +@echo off +:: Concatenates files from dir %1 specified with wildcard %2 and outputs result to %3 + +:: TODO Proper temp file instead of bin\list.txt +SET _LISTFILE="bin\list.txt" +>%_LISTFILE% (FOR /R "%~1" %%F IN (%2) DO echo "%%F") +sort /O %_LISTFILE% %_LISTFILE% +>%3 (FOR /F "usebackq delims=" %%F IN (`type "%_LISTFILE%"`) DO ( + echo /* %%F */ + type %%F + ) +) + +DEL %_LISTFILE% diff --git a/devTools/concatFiles.sh b/devTools/concatFiles.sh new file mode 100755 index 0000000000000000000000000000000000000000..dfdc89af23764817d5b7ab2383b333096038b3e7 --- /dev/null +++ b/devTools/concatFiles.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +# $1: source dir +# $2: name wildcard +# #3: destination file + +rm -f "$3" +files=$(find "$1" -name "$2" -print) +files=$(echo "$files" | sort) +for f in $files; do + printf "\n/* ${f#$1} */\n" >> "$3" + cat "$f" >> "$3" +done diff --git a/devTools/javaSanityCheck/SanityCheck.jar b/devTools/javaSanityCheck/SanityCheck.jar index 34dda845846f00223076ef49d082607ba2bfa63b..182089e8d3121b89627cef4e30de77569b57353e 100644 Binary files a/devTools/javaSanityCheck/SanityCheck.jar and b/devTools/javaSanityCheck/SanityCheck.jar differ diff --git a/devTools/javaSanityCheck/excluded b/devTools/javaSanityCheck/excluded index f4939870ee93b14bd0a0d7b9467e378624f68a52..04716ff61537863acc4a6ccd7e9b7a1004c4820f 100644 --- a/devTools/javaSanityCheck/excluded +++ b/devTools/javaSanityCheck/excluded @@ -1,5 +1,4 @@ -#Add files or folders to be excluded. -#options to exclude certain checks, no options will break the check +#Add files or folders to be excluded for certain checks. #L : logic checks, like <<if>><</if>> #O : OnlyUsedOnce, if variables are used more than once #S : SpellCheck, matches based on dictionaries in devTools/ diff --git a/devTools/javaSanityCheck/sources.zip b/devTools/javaSanityCheck/sources.zip index 01188228f6e66e2b7650678eefd72f43f3aedb21..d88b225b533b114e05537db43b3895f894d91abd 100644 Binary files a/devTools/javaSanityCheck/sources.zip and b/devTools/javaSanityCheck/sources.zip differ diff --git a/devTools/makeTwineCSSPassage.sh b/devTools/makeTwineCSSPassage.sh index d8ccc4726b949c1ba132b15a26a1cf094f2428c4..de6abc320e849659dd2888eeab2b199d3740281f 100755 --- a/devTools/makeTwineCSSPassage.sh +++ b/devTools/makeTwineCSSPassage.sh @@ -10,7 +10,7 @@ collectCSSForTwine() { files=$(echo "$files" | sort) echo "" > "$2" for f in $files; do - echo -e "\n/* ${f} */\n" >> "$2" + printf "\n/* ${f} */\n" >> "$2" cat "$f" >> "$2" done } diff --git a/devTools/makeTwineJSPassage.sh b/devTools/makeTwineJSPassage.sh index af0db0d42124242c89d66c0c4e13b2b7115f8fc0..e68e144503503e746d6bc408085e6b0d40dd3c17 100755 --- a/devTools/makeTwineJSPassage.sh +++ b/devTools/makeTwineJSPassage.sh @@ -10,7 +10,7 @@ collectJSForTwine() { files=$(echo "$files" | sort) echo "" > "$2" for f in $files; do - echo -e "\n/* ${f} */\n" >> "$2" + printf "\n/* ${f} */\n" >> "$2" sed -nf "$1"/devTools/stripComments.sed "$f" >> "$2" done } diff --git a/src/002-config/fc-js-init.js b/js/002-config/fc-js-init.js similarity index 69% rename from src/002-config/fc-js-init.js rename to js/002-config/fc-js-init.js index 3c923124687bca8b341a43c66007c69029106124..f01b00419cd4402a38ff4f7dbbbb7442d47e858e 100644 --- a/src/002-config/fc-js-init.js +++ b/js/002-config/fc-js-init.js @@ -1,13 +1,8 @@ /* eslint-disable no-var */ -/* -* SugarCube executes scripts via eval() inside a closure. Thus to make App global, -* we declare it as a property of the window object. I don't know why 'App = {}' -* does not work. -*/ // @ts-ignore -window.App = { }; -// the same declaration for code parsers that don't like the line above -var App = window.App || {}; /* eslint-disable-line no-var*/ +"use strict"; + +var App = { }; App.Art = {}; App.Data = {}; diff --git a/src/js/utils.js b/js/utils.js similarity index 88% rename from src/js/utils.js rename to js/utils.js index eca740c543cbcfbf5729fa9fbd766671d7152e05..cf39ddc1d09fa1ff3447db4e4f225850370d1e47 100644 --- a/src/js/utils.js +++ b/js/utils.js @@ -1,3 +1,4 @@ +/* eslint-disable no-unused-vars */ /* This file contains only JS functions without dependencies on FC specific variables/conventions and do not rely on * custom functions outside this file */ @@ -7,17 +8,17 @@ * @param {any} x * @returns {boolean} */ -window.jsDef = function(x) { +function jsDef(x) { return (typeof x !== "undefined" && x !== null && x !== undefined); -}; +} /** * @param {number} n * @returns {boolean} */ -window.isFloat = function(n) { +function isFloat(n) { return Number.isFinite(n) && Math.floor(n) !== n; -}; +} /** * Determines if a is between low and high @@ -26,17 +27,17 @@ window.isFloat = function(n) { * @param {number} high * @returns {boolean} */ -window.between = function(a, low, high) { +function between(a, low, high) { if (low === null) { low = -Infinity; } if (high === null) { high = Infinity; } return (a > low && a < high); -}; +} /** * @param {number[]} obj * @returns {number} */ -window.hashChoice = function hashChoice(obj) { +function hashChoice(obj) { let randint = Math.floor(Math.random() * hashSum(obj)); let ret; Object.keys(obj).some((key) => { @@ -49,37 +50,37 @@ window.hashChoice = function hashChoice(obj) { } }); return ret; -}; +} /** * @param {number[]} obj * @returns {number} */ -window.hashSum = function hashSum(obj) { +function hashSum(obj) { let sum = 0; Object.keys(obj).forEach((key) => { sum += obj[key]; }); return sum; -}; +} /** * @param {Array} arr * @returns {Object} */ -window.arr2obj = function arr2obj(arr) { +function arr2obj(arr) { const obj = {}; arr.forEach((item) => { obj[item] = 1; }); return obj; -}; +} /** * @param {{}} object * @param rest */ -window.hashPush = function hashPush(object, ...rest) { +function hashPush(object, ...rest) { rest.forEach((item) => { if (object[item] === undefined) { object[item] = 1; @@ -87,13 +88,13 @@ window.hashPush = function hashPush(object, ...rest) { object[item] += 1; } }); -}; +} /** * @param {[]} array * @return {{}} */ -window.weightedArray2HashMap = function weightedArray2HashMap(array) { +function weightedArray2HashMap(array) { const obj = {}; array.forEach((item) => { if (obj[item] === undefined) { @@ -103,14 +104,14 @@ window.weightedArray2HashMap = function weightedArray2HashMap(array) { } }); return obj; -}; +} /** * generate a random, almost unique ID that is compliant (possibly) with RFC 4122 * * @return {string} */ -window.generateNewID = function generateNewID() { +function generateNewID() { let date = Date.now(); // high-precision timer let uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) { let r = (date + Math.random() * 16) % 16 | 0; @@ -118,44 +119,44 @@ window.generateNewID = function generateNewID() { return (c === "x" ? r : (r & 0x3 | 0x8)).toString(16); }); return uuid; -}; +} /** * @param {Array} array * @param {number} indexA * @param {number} indexB */ -window.arraySwap = function arraySwap(array, indexA, indexB) { +function arraySwap(array, indexA, indexB) { const tmp = array[indexA]; array[indexA] = array[indexB]; array[indexB] = tmp; -}; +} /** * @param {string} string * @returns {string} */ -window.capFirstChar = function capFirstChar(string) { +function capFirstChar(string) { return string.charAt(0).toUpperCase() + string.substr(1); -}; +} /** * @param {string} word * @returns {string} */ -window.addA = function(word) { +function addA(word) { let vocal = ['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U']; if (vocal.includes(word.charAt(0))) { return `an ${word}`; } return `a ${word}`; -}; +} /** * @param {number} i * @returns {string} */ -window.ordinalSuffix = function ordinalSuffix(i) { +function ordinalSuffix(i) { let j = i % 10; let k = i % 100; if (j === 1 && k !== 11) { @@ -168,27 +169,27 @@ window.ordinalSuffix = function ordinalSuffix(i) { return `${i}rd`; } return `${i}th`; -}; +} /** * @param {number} i * @returns {string} */ -window.ordinalSuffixWords = function(i) { +function ordinalSuffixWords(i) { const text = ["zeroth", "first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth", "tenth", "eleventh", "twelfth", "thirteenth", "fourteenth", "fifteenth", "sixteenth", "seventeenth", "eighteenth", "nineteenth"]; if (i < text.length) { return text[i]; } return ordinalSuffix(i); -}; +} /** * @param {Iterable<any>} array * @returns {any[]} */ -window.removeDuplicates = function removeDuplicates(array) { +function removeDuplicates(array) { return [...new Set(array)]; -}; +} /** * Maps an index from one list onto a matching index on the other. @@ -230,13 +231,13 @@ App.Utils.escapeHtml = function(text) { * @param {Iterable} list * @return {{}} */ -window.mapIdList = function(list) { +function mapIdList(list) { let mappedList = {}; for (const item of list) { mappedList[item.id] = item; } return mappedList; -}; +} /** * Topological sorting algorithm diff --git a/sanityCheck.sh b/sanityCheck.sh index 3e1b11ffbd90631e4d637827f9ce8537ff183255..268742e99c464ab95209493f05fdab1a6a419056 100755 --- a/sanityCheck.sh +++ b/sanityCheck.sh @@ -14,22 +14,8 @@ myprint() { done } -#check if java version should be run -if [[ "$1" == "java" ]]; then - java="true" -fi - -#for everyone that wants to add new checks; just add them outside the java checks. - GREP="git grep -n --color" -if [[ ! "$java" ]]; then - # Check for missing right angle bracket: <</if> - $GREP "<</[^>]*>[^>]" -- 'src/*' | myprint "MissingClosingAngleBracket" - $GREP "<<[^>()]*>[^()<>"$'\r]*\r'"\?$" -- 'src/*' | myprint "MissingClosingAngleBracket" - # Check for missing left angle bracket: </if>> - $GREP "\([^<]\|^\)</\?\(if\|else\|case\|set\|print\|elseif\)" -- 'src/*' | myprint "MissingOpeningAngleBracket2" -fi # Check for accidental assignment. e.g.: <<if $foo = "hello">> $GREP "<<[ ]*if[^>=]*[^><\!=]=[^=][^>]*>>" -- 'src/*' | myprint "AccidentalAssignmentInIf" # Check for accidental assignment. e.g.: <<elseif $foo = "hello">> @@ -51,29 +37,14 @@ $GREP -e "<<[ a-zA-Z]\+[^()<>]*([^()]*)[^()]*)[^()<>]*>>" -- "src/*" | myprint # Check for one closing bracket but two opening brackets. e.g.: <<if ((foo)>> $GREP -e "<<[ a-zA-Z]\+[^()<>]*([^()]*([^()]*)[^()<>]*>>" -- "src/*" | myprint "MissingClosingBracket2" $GREP -e "<<.*[(][^<>)]*[(][^<>)]*)\?[^<>)]*>>" -- "src/*" | myprint "MissingClosingBracket3" -if [[ ! "$java" ]]; then - # Check for missing >>. e.g.: <<if $foo - $GREP "<<[^<>]*[^,\"\[{"$'\r]\r'"\?$" -- 'src/*' | myprint "MissingClosingAngleBrackets" - # Check for too many <<<. e.g.: <<</if>> - $GREP "<<<[^<>]*[<>]\?[^<>]*>>" -- "src/*.tw" | myprint "TooManyAngleBrackets" -fi # Check for too many >>>. e.g.: <</if>>> $GREP "<<[^<>]*[<>]\?[^<>]*>>>" -- "src/*.tw" | myprint "TooManyAngleBrackets" # Check for wrong capitalization on 'activeslave' and other common typos $GREP -e "\$act" --and --not -e "\$\(activeSlave\|activeChild\|activeArcology\|activeStandard\|activeOrgan\|activeLimbs\|activeUnits\|activeCanine\|activeHooved\|activeFeline\|activeLurcher\)" -- "src/*" | myprint "WrongCapitilization" -if [[ ! "$java" ]]; then - $GREP "\(csae\|[a-z] She \|attepmts\|youreslf\|advnaces\|canAcheive\|setBellySize\|SetbellySize\|setbellySize\|bellypreg\|pregBelly\|bellyimplant\|bellyfluid\|pronounCaps\|carress\|hormonebalance\|fetishknown\)" -- 'src/*' | myprint "SpellCheck" - $GREP "\(recieve\|recieves\)" -- 'src/*' | myprint "PregmodderCannotSpellReceive" - $GREP "\$slave\[" -- 'src/*' | myprint "ShouldBeSlaves" -fi # Check for strange spaces e.g. $slaves[$i]. lips $GREP "\$slaves\[\$i\]\. " -- 'src/*' | myprint "MissingPropertyAfterSlaves" # Check using refreshmentType instead of refreshment $GREP "\$PC.refreshmentType[^ =]" -- 'src/*' | grep -v src/events/intro/introSummary.tw | myprint "ShouldBeRefreshment" -if [[ ! "$java" ]]; then - # Check, e.g., <<//if>> - $GREP "<</[a-zA-Z]*[^a-zA-Z<>]\+[a-zA-Z]*>>" -- 'src/*' | myprint "DoubleSlash" -fi # Check, e.g. <<else $foo==4 $GREP "<<else >\?[^>]" -- 'src/*' | myprint "ShouldBeElseIf" # Check, e.g., =to @@ -140,22 +111,9 @@ $GREP -i "non.lethal" -- 'src/*' | myprint "ShouldBeNonlethal" ( cd src/ - -if [[ ! "$java" ]]; then - # Check that we do not have any variables that we use only once. e.g. $onlyUsedOnce - # Ignore *Nationalities - cat $(find . -name "*.tw" ) | tr -c '$a-zA-Z' '\n' | sed -n '/^[$]/p' | grep -v "Nationalities" | sort | uniq -u | sed 's/^[$]/-e[$]/' | sed 's/$/\\\\W/' | xargs -r git grep -n --color | myprint "OnlyUsedOnce" - cat $(find . -name "*.tw" ) | tr -c '.$a-zA-Z[]_' '\n' | sed 's/SugarCube\.State\.variables\./$/g' | sed -n -e 's/^[$]\(PC\|activeSlave\|\(slaves\|tanks\)\[[^]]*\]*\)[.]\([a-zA-Z]\+\).*$/[.]\3/p' | sort | uniq -u |sed 's/^\(.*\)$/-e\1\\\\\b/' | xargs -r git grep -n --color | myprint "SlaveAttributeUsedOnce" -fi - -$GREP "\$\(PC\|activeSlave\|slaves\|tanks\)[.][^a-zA-Z]" | myprint "UnexpectedCharAfterDot" - + $GREP "\$\(PC\|activeSlave\|slaves\|tanks\)[.][^a-zA-Z]" | myprint "UnexpectedCharAfterDot" ) -# Check that all the tags are properly opened and closed -if [[ "$java" ]]; then - java -jar devTools/javaSanityCheck/SanityCheck.jar # and all the excluded stuff -else - git ls-files "src/*.tw" | xargs -d '\n' ./devTools/check.py -fi +# Check that all the tags are properly opened and closed & a lot of other stuff +java -jar devTools/javaSanityCheck/SanityCheck.jar diff --git a/src/cheats/mod_EditSlaveCheatDatatypeCleanupNew.tw b/src/cheats/mod_EditSlaveCheatDatatypeCleanupNew.tw index 6102f86738903d894802b7a813ede997d629e09e..fb9854ded3321576c73bddf4236380c4c9fc3e76 100644 --- a/src/cheats/mod_EditSlaveCheatDatatypeCleanupNew.tw +++ b/src/cheats/mod_EditSlaveCheatDatatypeCleanupNew.tw @@ -216,6 +216,9 @@ <<set $tempSlave.lactationDuration = 0>> <</if>> <<run SetBellySize($tempSlave)>> +<<if $tempSlave.geneticQuirks.albinism === 2 && $activeSlave.albinismOverride === null>> + <<run induceAlbinism($tempSlave, 2)>> +<</if>> <br> You perform the dark rituals, pray to the dark gods, and sell your soul for the power to change and mold slaves to your will. diff --git a/src/endWeek/saStayConfined.js b/src/endWeek/saStayConfined.js index 7b60f4536c80a36f1132a3557171399e87405e69..4a1453a591b9686a6f583f12c26a14d328b23632 100644 --- a/src/endWeek/saStayConfined.js +++ b/src/endWeek/saStayConfined.js @@ -99,14 +99,33 @@ window.saStayConfined = function saStayConfined(slave) { } else { t += ` ${He} is now willing to <span class="devotion accept">do as ${he}'s told,</span>`; } - t += ` so <span class="noteworthy">${his} assignment has defaulted to rest.</span>`; + + t += ` <span class="noteworthy">`; if (slave.assignment === "be confined in the cellblock") { State.temporary.brokenSlaves++; State.temporary.DL--; State.temporary.dI--; } - removeJob(slave, slave.assignment); - } + if (V.assignmentRecords[slave.ID]) { + let oldJob = V.assignmentRecords[slave.ID]; + assignJobSafely(slave, oldJob); + if (slave.choosesOwnAssignment === 1) { + t += ` and ${he} is resting before choosing another task.`; + } else if (slave.assignment === "rest") { + if (oldJob !== "rest") { + t += ` and since ${he} was unable to return to ${his} old task to ${oldJob}, ${his} assignment has defaulted to rest.`; + } else { + t += ` so ${he} has returned to rest.`; + } + } else { + t += ` so ${he} goes back to ${oldJob}.`; + } + } else { + t += ` so ${his} assignment has defaulted to rest.`; + removeJob(slave, slave.assignment); + } + t += `</span>`; + } return t; }; diff --git a/src/endWeek/saTakeClasses.js b/src/endWeek/saTakeClasses.js index 08ee9f45019a39fabfe92ce95ef0f3d89c317afc..e18ffc65c03be80af31eb7d3ec9b7348df266495 100644 --- a/src/endWeek/saTakeClasses.js +++ b/src/endWeek/saTakeClasses.js @@ -412,8 +412,26 @@ window.saTakeClasses = (function saServeThePublic() { if ((slave.skill.entertainment > 30) || (V.schoolroomUpgradeSkills === 0 && slave.skill.entertainment > 10)) { if ((slave.skill.anal > 30) || (V.schoolroomUpgradeSkills === 0 && slave.skill.anal > 10)) { if ((slave.skill.vaginal > 30) || (V.schoolroomUpgradeSkills === 0 && slave.skill.vaginal > 10) || (slave.vagina < 0)) { - r += ` ${He} can learn little from further classes, so <span class="noteworthy">${his} assignment has defaulted to rest.</span>`; - removeJob(slave, "take classes"); + r += ` <span class="noteworthy">`; + if (V.assignmentRecords[slave.ID]) { + let oldJob = V.assignmentRecords[slave.ID]; + assignJobSafely(slave, oldJob); + if (slave.choosesOwnAssignment === 1) { + t += ` and ${he} is resting before choosing another task.`; + } else if (slave.assignment === "rest") { + if (oldJob !== "rest") { + r += ` and since ${he} was unable to return to ${his} old task to ${oldJob}, ${his} assignment has defaulted to rest.`; + } else { + r += ` so ${he} has returned to rest.`; + } + } else { + r += ` so ${he} goes back to ${oldJob}.`; + } + } else { + r += ` so ${his} assignment has defaulted to rest.`; + removeJob(slave, slave.assignment); + } + r += `</span>`; } } } diff --git a/src/facilities/farmyard/food/pFoodCrisis.tw b/src/facilities/farmyard/food/pFoodCrisis.tw index 6e6014fc62e6944231319f570b536ed956caf7ec..9029cf231167d157dbe795b9ddd8cec32d503e88 100644 --- a/src/facilities/farmyard/food/pFoodCrisis.tw +++ b/src/facilities/farmyard/food/pFoodCrisis.tw @@ -30,16 +30,18 @@ <<run repX(5000, "event")>> <<set cashX(forceNeg(_price*2), "farmyard")>> <<set $rations = 2>> - <</replace>> <<if ($PC.skill.trading >= 50) || ($PC.career == "capitalist")>>//This will cost <<print cashFormat(_price*2)>> and some upkeep, @@.springgreen;reduced by your knowledge of trading@@//<<else>>//This will cost <<print cashFormat(_price*2)>> and incur significant upkeep costs//<</if>> + <</replace>> <</link>> + <<if ($PC.skill.trading >= 50) || ($PC.career == "capitalist")>>//This will cost <<print cashFormat(_price*2)>> and some upkeep, @@.springgreen;reduced by your knowledge of trading@@//<<else>>//This will cost <<print cashFormat(_price*2)>> and incur significant upkeep costs//<</if>> <br><<link "Give them enough to survive on">> <<replace "#result">> You have your own problems to deal with, but that doesn't mean you don't look out for your own. You have a number of rationing stations set up throughout $arcologies[0].name and announce that each citizen is entitled to two full meals a day, just enough for your citizens not to starve. Your citizens are @@.green;happy@@ to hear that their leader is looking out for them. <<run repX(2500, "event")>> <<set cashX(forceNeg(_price), "farmyard")>> <<set $rations = 1>> - <</replace>> <<if ($PC.skill.trading >= 50) || ($PC.career == "capitalist")>>//This will cost <<print cashFormat(_price)>> and some upkeep, @@.springgreen;reduced by your knowledge of trading@@//<<else>>//This will cost <<print cashFormat(_price)>> and incur significant upkeep costs//<</if>> + <</replace>> <</link>> + <<if ($PC.skill.trading >= 50) || ($PC.career == "capitalist")>>//This will cost <<print cashFormat(_price)>> and some upkeep, @@.springgreen;reduced by your knowledge of trading@@//<<else>>//This will cost <<print cashFormat(_price)>> and incur significant upkeep costs//<</if>> <br><<link "They can figure their problem out on their own">> <<replace "#result">> You have your own problems to deal with, and you simply can't afford to drop everything and solve theirs at the moment. That you can't take care of your arcology's citizen @@.red;reflects poorly on you.@@ @@ -62,7 +64,8 @@ <<set cashX(forceNeg(_price*2), "farmyard")>> <<set $rations = 4>> <</replace>> - <</link>> <<if ($PC.skill.trading >= 50) || ($PC.career == "capitalist")>>//This will cost <<print cashFormat(_price*2)>> and some upkeep, @@.springgreen;reduced by your knowledge of trading@@//<<else>>//This will cost <<print cashFormat(_price*2)>> and incur significant upkeep costs//<</if>> + <</link>> + <<if ($PC.skill.trading >= 50) || ($PC.career == "capitalist")>>//This will cost <<print cashFormat(_price*2)>> and some upkeep, @@.springgreen;reduced by your knowledge of trading@@//<<else>>//This will cost <<print cashFormat(_price*2)>> and incur significant upkeep costs//<</if>> <br><<link "Provide them with enough sustenance to survive on too">> <<replace "#result">> As much as you'd like to provide them with all of the food in the world, it simply is not feasible in your current situation. Therefore, you announce to the leaders that you will provide them only enough rations to live off of. The leaders understand, and are @@.green;pleased@@ to hear that you would provide for them at all. @@ -70,7 +73,8 @@ <<set cashX(forceNeg(_price), "farmyard")>> <<set $rations = 3>> <</replace>> - <</link>> <<if ($PC.skill.trading >= 50) || ($PC.career == "capitalist")>>//This will cost <<print cashFormat(_price)>> and some upkeep, @@.springgreen;reduced by your knowledge of trading@@//<<else>>//This will cost <<print cashFormat(_price)>> and incur significant upkeep costs//<</if>> + <</link>> + <<if ($PC.skill.trading >= 50) || ($PC.career == "capitalist")>>//This will cost <<print cashFormat(_price)>> and some upkeep, @@.springgreen;reduced by your knowledge of trading@@//<<else>>//This will cost <<print cashFormat(_price)>> and incur significant upkeep costs//<</if>> <br><<link "Change your mind about giving out any rations at all">> <<replace "#result">> Having given the people rations at all was a mistake, you think to yourself. You have a great number of your own problems to deal with, and providing rations to everyone that can't afford food is putting an unnecessary strain on your own situation. With this is mind, you tell the leaders that you simply can't help them at this time, and have decided that you can't help anyone with food at all. The citizens are understandably @@.red;angry@@ that you would go back on your word. @@ -97,7 +101,8 @@ <<set $foodMarket = 1>> <<unset $rations>> <</replace>> - <</link>> <<if ($PC.skill.trading >= 50) || ($PC.career == "capitalist")>>//This will cost an initial investment of <<print cashFormat(_price*5)>>, @@.springgreen;reduced by your knowledge of trading@@//<<else>>//This will cost an initial investment of <<print cashFormat(_price*5)>>//<</if>> + <</link>> + <<if ($PC.skill.trading >= 50) || ($PC.career == "capitalist")>>//This will cost an initial investment of <<print cashFormat(_price*5)>>, @@.springgreen;reduced by your knowledge of trading@@//<<else>>//This will cost an initial investment of <<print cashFormat(_price*5)>>//<</if>> <br><<link "Politely decline their offer, but continue giving them rations">> <<replace "#result">> Things have been going fairly well for you, but not //that// well — setting up an entirely new place to buy, sell, and store food would no doubt be an expensive undertaking. You tell the citizens that while you can't spare the resources to create a new market at the moment, you will honor your past agreement and continue giving them free rations. The people initially seem a bit disappointed that you don't seem to want to expand $arcologies[0].name, but are ultimately @@.green;glad@@ to hear that you'll continue taking care of them. @@ -105,7 +110,8 @@ <<set cashX(forceNeg(_price), "farmyard")>> <<set $rations = 5>> <</replace>> - <</link>> <<if ($PC.skill.trading >= 50) || ($PC.career == "capitalist")>>//This will cost <<print cashFormat(_price)>> and some upkeep, @@.springgreen;reduced by your knowledge of trading@@//<<else>>//This will cost <<print cashFormat(_price)>> and incur significant upkeep costs//<</if>> + <</link>> + <<if ($PC.skill.trading >= 50) || ($PC.career == "capitalist")>>//This will cost <<print cashFormat(_price)>> and some upkeep, @@.springgreen;reduced by your knowledge of trading@@//<<else>>//This will cost <<print cashFormat(_price)>> and incur significant upkeep costs//<</if>> <br><<link "Turn down their offer and end rationing completely">> <<replace "#result">> While a new place to buy, sell, and store food in $arcologies[0].name would most likely come in quite handy in the future, you ultimately decide that you simply cannot spare the resources required. In fact, giving rations at all was a costly venture, and after not having seen any sort of return-on-investment, you decide that you are unable to continue giving out rations anymore. Your citizens are @@.red;angry@@ at the fact that you seem not to care about them at all, but that's their problem. diff --git a/src/gui/css/mainStyleSheet.css b/src/gui/css/mainStyleSheet.css index 2c20405dee171c3676da7590fceb662832d89f77..77595075c001e7ebf299ffd23d0ff0040780e246 100644 --- a/src/gui/css/mainStyleSheet.css +++ b/src/gui/css/mainStyleSheet.css @@ -326,3 +326,10 @@ div.double-indent { .story-label { text-decoration: underline; } + +/* Note: Do not do a linebreak after span in HTML, because it will underline the automatic space it inserts: "Matilda_is a cow" */ +.slave-name { + color: pink; + font-weight: bold; + text-decoration: underline; +} \ No newline at end of file diff --git a/src/init/storyInit.tw b/src/init/storyInit.tw index 83742f4b21185a1a002253a4f347e230f19be5b1..a57b06613734f65bdc1a1302948a5d288a066277 100644 --- a/src/init/storyInit.tw +++ b/src/init/storyInit.tw @@ -336,12 +336,15 @@ You should have received a copy of the GNU General Public License along with thi <<set $useSlaveSummaryOverviewTab = 0>> <<set $useSlaveListInPageJSNavigation = 0>> <<set $killChoice = -1>> + <<set $assignmentRecords = {}>> /* master suite reporting and alternate descriptions */ <<set $verboseDescriptions = 0>> /* Accordion 000-250-006 */ <<set $useAccordion = 0>> - + + <<set $debugMode = 0>> + <<set $showNeighborDetails = 1>> <<set $useTabs = 0>> <<set $tabChoice = {Main: "all"}>> <<set $formatNumbers = 1>> @@ -353,6 +356,8 @@ You should have received a copy of the GNU General Public License along with thi <<set $showEconomicDetails = 0>> /* Pregmod specific */ + <<set $allowMaleSlaveNames = false>> + <<set $profiler = 0>> <<set $economy = 100>> <<set $baseDifficulty = 3>> <<set $difficultySwitch = 0>> diff --git a/src/js/assignJS.js b/src/js/assignJS.js index 0002a19f9885bee7d085d8320d7770d3079f6fad..7caead6c7c1343aef7236df1ff8ccf54a49b5304 100644 --- a/src/js/assignJS.js +++ b/src/js/assignJS.js @@ -2,6 +2,7 @@ window.assignJob = function assignJob(slave, job) { "use strict"; let r = ""; + let oldJob = slave.assignment; if (job === "Pit" || job === "Coursing Association") { return r; } @@ -16,6 +17,24 @@ window.assignJob = function assignJob(slave, job) { V[propName] = slave; }; + /* Tracking for the following cases: */ + if (V.assignmentRecords[slave.ID] !== "choose her own job") { // if choosesOwnAssignment was set before removeJob (which wipes it out), it's saved in assignmentRecords. We don't want to overwrite that here, as we want to be able to get it back. + switch (job.toLowerCase()) { + case "be confined in the cellblock": + case "cellblock": + case "get treatment in the clinic": + case "clinic": + case "learn in the schoolroom": + case "schoolroom": + case "rest in the spa": + case "spa": + if (oldJob !== "rest") { + V.assignmentRecords[slave.ID] = oldJob; // these jobs are temporary, so we save what the slave will return to if it is meaningful. + } + break; + } + } + /* use .toLowerCase() to get rid of a few dupe conditions. */ switch (job.toLowerCase()) { case "be confined in the arcade": @@ -385,6 +404,17 @@ window.assignJob = function assignJob(slave, job) { return r; }; +window.assignJobSafely = function assignJobSafely(slave, assignmentStr){ + if (V.assignmentRecords[slave.ID] === "choose her own job") { + assignJob(slave, "rest"); + slave.choosesOwnAssignment = 1; + } else if (!App.Utils.jobForAssignment(assignmentStr).canEmploy(slave).length) { // If nothing complains about job requirements not being met + assignJob(slave, assignmentStr); + } else { + assignJob(slave, "rest"); + } +}; + window.removeJob = function removeJob(slave, assignment) { "use strict"; let r = ""; @@ -396,6 +426,10 @@ window.removeJob = function removeJob(slave, assignment) { return r; } + if (V.assignmentRecords[slave.ID]) { + delete V.assignmentRecords[slave.ID]; + } + const idx = V.slaveIndices[slave.ID]; if (assignment === "Pit") { @@ -583,6 +617,10 @@ window.removeJob = function removeJob(slave, assignment) { slave.rules.living = "normal"; } + if (slave.choosesOwnAssignment > 0) { + V.assignmentRecords[slave.ID] = "choose her own job"; + } + slave.choosesOwnAssignment = 0; slave.sentence = 0; } @@ -808,7 +846,7 @@ App.UI.SlaveInteract = { const slave = State.variables.activeSlave; const {his} = getPronouns(slave); if ((slave.assignment === "please you") || (slave.assignment === "serve in the master suite") || (slave.assignment === "be your Concubine")) { - res += `<span class="story-label">Fucktoy use preference</span>: <strong><span id = "hole">${slave.toyHole}</span></strong>.`; + res += `<span class="story-label">Fucktoy use preference:</span> <strong><span id = "hole">${slave.toyHole}</span></strong>.`; /** @type {string[]} */ let links = []; links.push('<<link "Mouth">><<set $activeSlave.toyHole = "mouth">><<replace "#hole">>$activeSlave.toyHole<</replace>><</link>>'); @@ -900,8 +938,11 @@ App.Utils.jobForAssignment = function() { if (map.size === 0) { fillMap(); } - return map.get(assignment); + const res = map.get(assignment); + if (!res) { + throw Error(`Can't find job object for assignment '${assignment}'`); + } + return res; } - return getJob; }(); diff --git a/src/js/economyJS.js b/src/js/economyJS.js index 65ffa9c4653a7c55fe2d7c6d9ba8d048b4ef2a86..dc6376c4614b2a772baa9c3554beaa583f850db3 100644 --- a/src/js/economyJS.js +++ b/src/js/economyJS.js @@ -2131,3 +2131,33 @@ window.agentBonus = function(arcology) { } return bonus; }; + +/** + * Charge for subsidies and supply barriers and report the results + * @param {string} NPCclass One of "lower", "middle", "upper", or "top" + * @returns {string} + */ +window.chargeSupplyPolicies = function(NPCclass) { + let r = ``; + const varName = `${NPCclass}Class`; + + // charge supply barriers (unreported, since it's a flat amount that you were told when you enacted the policy) + const supplyCosts = [0, 1000, 5000, 20000, 60000]; + cashX(forceNeg(supplyCosts[V.sexSupplyBarriers[varName]])); + + // report subsidy cost since it is variable + if (V.sexSubsidies[varName] > 0) { + const severity = ["none", "minor", "moderate", "substantial", "gratuitous"]; + const subsidyCost = forceNeg(Math.trunc(V.NPCSexSupply[varName] * Math.pow(V.sexSubsidies[varName], 2) * 0.25)); + r += `Your ${severity[V.sexSubsidies[varName]]} subsidies of ${NPCclass} class sex supply cost you ${cashFormatColor(subsidyCost)} this week. `; + cashX(subsidyCost, "policies"); + + // warn about conflicting policies + if (V.sexSupplyBarriers[varName > 0]) { + r += `The supply barriers you are imposing on ${NPCclass} class sex supply <span class="red">reduce the effectiveness</span> of your subsidies and <span class="red">increase your costs.</span>`; + } + r += `<br>`; + } + + return r; +}; diff --git a/src/js/physicalDevelopment.js b/src/js/physicalDevelopment.js index 3920db892290ad90ca176bfcf38ff284cfb5241a..e29d8a82ea2ee56d9750e0c78a7aa296a3a113b5 100644 --- a/src/js/physicalDevelopment.js +++ b/src/js/physicalDevelopment.js @@ -32,7 +32,7 @@ window.physicalDevelopment = (function physicalDevelopment() { if (slave.balls > 0 && slave.balls < 3) { increaseBalls(slave); } - if (slave.vagina > 0 && slave.ovaries > 0 && pubertyXX > 0) { + if (slave.vagina > 0 && slave.ovaries > 0 && slave.physicalAge > slave.pubertyAgeXX) { increaseWetness(slave); } if (slave.waist < 10) { @@ -63,7 +63,7 @@ window.physicalDevelopment = (function physicalDevelopment() { if (slave.clit > 0) { increaseClit(slave); } - if (slave.vagina > 0 && slave.ovaries > 0 && pubertyXX > 0) { + if (slave.vagina > 0 && slave.ovaries > 0 && slave.physicalAge > slave.pubertyAgeXX) { increaseWetness(slave); } increaseWaistXX(slave); diff --git a/src/js/removeActiveSlave.js b/src/js/removeActiveSlave.js index e5ce66906de23fbd59c4ede720ea20765618796d..1d34fc8386a3e90b0a268d4a4afa3212ee80fa94 100644 --- a/src/js/removeActiveSlave.js +++ b/src/js/removeActiveSlave.js @@ -229,6 +229,10 @@ window.removeActiveSlave = function removeActiveSlave() { V.missingParentID--; } + if (V.assignmentRecords[AS_ID]) { + delete V.assignmentRecords[AS_ID]; + } + removeSlave(INDEX); LENGTH--; V.activeSlave = 0; diff --git a/src/js/surgery.js b/src/js/surgery.js index 053f9d45f17a45ded60dc9504261f5cd64504e50..e80b8a802d2854d905e46044cac440d272bc3234 100644 --- a/src/js/surgery.js +++ b/src/js/surgery.js @@ -716,6 +716,44 @@ window.resetEyeColor = function(slave, side = "both") { slave.eye[side].iris = getGeneticEyeColor(slave, side); }; +/** + * @param {App.Entity.SlaveState} slave + * @param {number} level + */ +window.induceAlbinism = function(slave, level) { + slave.geneticQuirks.albinism = level; + if (level < 2) { + slave.albinismOverride = null; + return; + } + slave.albinismOverride = { + skin: 0, + eyeColor: "red", + hColor: "white" + }; + switch (slave.race) { + case "black": + case "indo-aryan": + case "malay": + case "pacific islander": + case "amerindian": + slave.albinismOverride.skin = "very fair"; + break; + case "latina": + slave.albinismOverride.skin = "extremely fair"; + break; + case "asian": + case "middle eastern": + case "semitic": + case "southern european": + case "white": + slave.albinismOverride.skin = "pure white"; + break; + default: + slave.albinismOverride.skin = "pure white"; + } +}; + /** * Allowed values for limb: * left arm, right arm, left leg, right leg, all diff --git a/src/npc/descriptions/fAnus.tw b/src/npc/descriptions/fAnus.tw index 30a70c7cf8766a0f29647b8e507f323b7902a959..80c864bd5bd3c306d26c632b7c91000be477875f 100644 --- a/src/npc/descriptions/fAnus.tw +++ b/src/npc/descriptions/fAnus.tw @@ -107,7 +107,7 @@ You call $him over so you can $His flaccid dick is ground into the back of the couch as you rape $him. <</if>> <<elseif ($activeSlave.devotion <= 20) && ($activeSlave.vagina < 0)>> - <<if !isAmputee(slave)>> + <<if !isAmputee($activeSlave)>> You instruct $him to present $his anus<<if ($PC.dick == 0)>> as you don a strap-on<</if>>. $He knows a sissy slave takes it up the butt, and lies on the couch next to your desk with $his <<if !hasAnyLegs($activeSlave)>>hips<<else>>leg<<if hasBothLegs($activeSlave)>>s<</if>><</if>> in the air, spreading $his buttocks <<if !hasAnyArms($activeSlave)>>as best $he can<<else>>with $his hand<<if hasBothArms($activeSlave)>>s<</if>><</if>>. <<else>> You tell $him it's time for an assfuck. $He's hesitant, but as an amputee can do nothing about it. diff --git a/src/npc/descriptions/fBoobs.tw b/src/npc/descriptions/fBoobs.tw index d0e0f457672d62d3ae46e658f1e0713480040f0a..9564757046c3c20c61729a78f2a794cc2337dbd8 100644 --- a/src/npc/descriptions/fBoobs.tw +++ b/src/npc/descriptions/fBoobs.tw @@ -182,7 +182,7 @@ tits. <<if (random(1,100) > (100+$activeSlave.devotion))>> <<if ($activeSlave.fetish !== "boobs") && ($activeSlave.energy <= 95) && ($activeSlave.behavioralFlaw == "none")>> - <<if $PC.vagina >= 0>> + <<if $PC.vagina >= 0 && $PC.dick == 0>> Being manhandled and used by you has given $him a @@.flaw.gain;hatred of women.@@ <<set $activeSlave.behavioralFlaw = "hates women">> <<else>> @@ -191,10 +191,7 @@ tits. <</if>> <</if>> <<elseif (random(1,100) > (110-$activeSlave.devotion))>> - <<if ($activeSlave.fetish == "none") - && !(($activeSlave.behavioralFlaw === "hates men") && ($PC.dick > 0) && ($PC.vagina < 0)) - && !(($activeSlave.behavioralFlaw === "hates women") && ($PC.vagina >= 0)) - >> + <<if ($activeSlave.fetish == "none") && ($activeSlave.behavioralFlaw != "hates men" || $PC.dick == 0) && ($activeSlave.behavioralFlaw != "hates women" || $PC.dick > 0)>> Having attention and love lavished on $his boobs by $his <<= WrittenMaster($activeSlave)>> has $him thinking of $his @@.fetish.gain;breasts as sexual organs.@@ <<set $activeSlave.fetish = "boobs", $activeSlave.fetishKnown = 1>> <</if>> diff --git a/src/npc/surgery/reproductiveOrgans.js b/src/npc/surgery/reproductiveOrgans.js index 321bb7c5ed5dc05f2fabbfba2138c8fbbb1e0cc7..54affb5554a1857f0632b7d58b67c68df9052bfb 100644 --- a/src/npc/surgery/reproductiveOrgans.js +++ b/src/npc/surgery/reproductiveOrgans.js @@ -187,7 +187,7 @@ App.Medicine.OrganFarm.Ovaries = class extends App.Medicine.OrganFarm.Organ { tooltip: "you can replace the existing ovaries with a new pair", animal: animal, autoImplant: false, - canImplant: s => (s.vagina >= 0 && s.mpreg === 0 && s.bellyImplant === -1 && s.eggType !== this.eggType), + canImplant: s => (s.vagina >= 0 && s.mpreg === 0 && s.bellyImplant === -1 && (s.eggType !== this.eggType || s.preg === -3)), implantError: s => (s.eggType === this.eggType) ? `This slave already has ${s.eggType} ovaries.` : "", implant: s => { s.eggType = this.eggType; diff --git a/src/uncategorized/BackwardsCompatibility.tw b/src/uncategorized/BackwardsCompatibility.tw index bb4142d9c589b891551ca7ddba053cbebe93ccbb..9491ea05451cb9454e056bdf09babd02678f5634 100644 --- a/src/uncategorized/BackwardsCompatibility.tw +++ b/src/uncategorized/BackwardsCompatibility.tw @@ -3150,7 +3150,9 @@ Setting missing slave variables: <<run App.Entity.Utils.SlaveDataSchemeCleanup($traitor)>> <<run SlaveDatatypeCleanup($traitor)>> <</if>> - +<<if ndef $assignmentRecords>> + <<set $assignmentRecords = {}>> +<</if>> Done<br> diff --git a/src/uncategorized/arcmgmt.tw b/src/uncategorized/arcmgmt.tw index 99a9c2c32150ae3b460a263cf198014a93c98328..ecf5094653c623ae72050c0b6f944341f9849c58 100644 --- a/src/uncategorized/arcmgmt.tw +++ b/src/uncategorized/arcmgmt.tw @@ -53,18 +53,7 @@ <</if>> Lower class satisfaction is at <<print $sexDemandResult.lowerClass/10>>%<<if _overSupply.lowerClass > 0>> and the arcology provides <<print _overSupply.lowerClass/10>>% more sexual services than required which @@.red;drives prices down@@<</if>>, <<print $NPCMarketShare.lowerClass/10>>% of the market is serviced by other suppliers operating inside your arcology.<br> -<<if $sexSupplyBarriers.lowerClass == 1>> - <<run cashX(1000, "policies")>> -<<elseif $sexSupplyBarriers.lowerClass == 2>> - <<run cashX(5000, "policies")>> -<<elseif $sexSupplyBarriers.lowerClass == 3>> - <<run cashX(20000, "policies")>> -<<elseif $sexSupplyBarriers.lowerClass == 4>> - <<run cashX(60000, "policies")>> -<</if>> -<<if $sexSubsidiesLC > 0>> - <<run cashX($NPCSlaves.lowerClass * Math.pow($sexSubsidies.lowerClass, 2) * 0.25, "policies")>> -<</if>> +<<= chargeSupplyPolicies("lower") >> <<if $sexDemandResult.middleClass < 350>> Your middle class citizens have @@.red;far too few options for sexual relief@@ inside your arcology. @@ -100,18 +89,7 @@ Lower class satisfaction is at <<print $sexDemandResult.lowerClass/10>>%<<if _ov <</if>> Middle class satisfaction is at <<print $sexDemandResult.middleClass/10>>%<<if _overSupply.middleClass > 0>> and the arcology provides <<print _overSupply.middleClass/10>>% more sexual services than required which @@.red;drives prices down@@<</if>>, <<print $NPCMarketShare.middleClass/10>>% of the market is serviced by other suppliers operating inside your arcology.<br> -<<if $sexSupplyBarriers.middleClass == 1>> - <<run cashX(1000, "policies")>> -<<elseif $sexSupplyBarriers.middleClass == 2>> - <<run cashX(5000, "policies")>> -<<elseif $sexSupplyBarriers.middleClass == 3>> - <<run cashX(20000, "policies")>> -<<elseif $sexSupplyBarriers.middleClass == 4>> - <<run cashX(60000, "policies")>> -<</if>> -<<if $sexSubsidiesLC > 0>> - <<run cashX($NPCSlaves.middleClass * Math.pow($sexSubsidies.middleClass, 2) * 0.25, "policies")>> -<</if>> +<<= chargeSupplyPolicies("middle") >> <<if $sexDemandResult.upperClass < 350>> Your upper class citizens have @@.red;far too few options for sexual relief@@ inside your arcology. @@ -147,18 +125,7 @@ Middle class satisfaction is at <<print $sexDemandResult.middleClass/10>>%<<if _ <</if>> Upper class satisfaction is at <<print $sexDemandResult.upperClass/10>>%<<if _overSupply.upperClass > 0>> and the arcology provides <<print _overSupply.upperClass/10>>% more sexual services than required which @@.red;drives prices down@@<</if>>, <<print $NPCMarketShare.upperClass/10>>% of the market is serviced by other suppliers operating inside your arcology.<br> -<<if $sexSupplyBarriers.upperClass == 1>> - <<run cashX(1000, "policies")>> -<<elseif $sexSupplyBarriers.upperClass == 2>> - <<run cashX(5000, "policies")>> -<<elseif $sexSupplyBarriers.upperClass == 3>> - <<run cashX(20000, "policies")>> -<<elseif $sexSupplyBarriers.upperClass == 4>> - <<run cashX(60000, "policies")>> -<</if>> -<<if $sexSubsidiesLC > 0>> - <<run cashX($NPCSlaves.upperClass * Math.pow($sexSubsidies.upperClass, 2) * 0.25, "policies")>> -<</if>> +<<= chargeSupplyPolicies("upper") >> <<if $sexDemandResult.topClass < 350>> Your arcology's millionaires have @@.red;far too few options for sexual relief@@ inside your arcology. @@ -194,18 +161,7 @@ Upper class satisfaction is at <<print $sexDemandResult.upperClass/10>>%<<if _ov <</if>> Millionaire satisfaction is at <<print $sexDemandResult.topClass/10>>%<<if _overSupply.topClass > 0>> and the arcology provides <<print _overSupply.topClass/10>>% more sexual services than required which @@.red;drives prices down@@<</if>>, <<print $NPCMarketShare.topClass/10>>% of the market is serviced by other suppliers operating inside your arcology.<br> -<<if $sexSupplyBarriers.topClass == 1>> - <<run cashX(1000, "policies")>> -<<elseif $sexSupplyBarriers.topClass == 2>> - <<run cashX(5000, "policies")>> -<<elseif $sexSupplyBarriers.topClass == 3>> - <<run cashX(20000, "policies")>> -<<elseif $sexSupplyBarriers.topClass == 4>> - <<run cashX(60000, "policies")>> -<</if>> -<<if $sexSubsidiesLC > 0>> - <<run cashX($NPCSlaves.topClass * Math.pow($sexSubsidies.topClass, 2) * 0.25, "policies")>> -<</if>> +<<= chargeSupplyPolicies("top") >> <br> diff --git a/src/uncategorized/clinicReport.tw b/src/uncategorized/clinicReport.tw index f316c5e8adb6488644eab64d8d8263e7eecf5f16..8615a3004ff28046bd8273debd985e4500344cc7 100644 --- a/src/uncategorized/clinicReport.tw +++ b/src/uncategorized/clinicReport.tw @@ -292,6 +292,7 @@ <</if>> <</if>> <<if ($slaves[$i].health.illness > 0)>> + <<elseif ($slaves[$i].health.shortDamage >= 10)>> <<elseif ($slaves[$i].health.condition <= 40)>> <<elseif ($slaves[$i].health.shortDamage >= 40)>> <<elseif ($Nurse != 0) && ($slaves[$i].chem > 15) && ($clinicUpgradeFilters == 1)>> @@ -299,8 +300,29 @@ <<elseif ($Nurse != 0) && ($slaves[$i].pregAdaptation*1000 < $slaves[$i].bellyPreg || $slaves[$i].preg > $slaves[$i].pregData.normalBirth/1.33)>> <<elseif ($Nurse != 0) && ($clinicInflateBelly > 0) && ($slaves[$i].bellyImplant >= 0) && ($slaves[$i].bellyImplant <= ($arcologies[0].FSTransformationFetishistResearch ? 800000 : 130000))>> <<else>> - <br><br>''__@@.pink;$slaves[$i].slaveName@@__'' has been cured<<if ($Nurse != 0) && ($clinicUpgradeFilters == 1)>> and purified<</if>>, so @@.yellow;$his assignment has defaulted to rest.@@ - <<= removeJob($slaves[$i], "get treatment in the clinic")>> + <p> + <span class="slave-name">$slaves[$i].slaveName</span> has been cured<<if ($Nurse != 0) && ($clinicUpgradeFilters == 1)>> and purified<</if>>, + <span class="noteworthy"> + <<if $assignmentRecords[$slaves[$i].ID]>> + <<set _oldJob = $assignmentRecords[$slaves[$i].ID]>> + <<= assignJobSafely($slaves[$i], _oldJob)>> + <<if $slaves[$i].choosesOwnAssignment === 1>> + and $he is resting before choosing another task. + <<elseif $slaves[$i].assignment === "rest">> + <<if _oldJob != "rest">> + and since $he was unable to return to $his old task to <<print _oldJob>>, $his assignment has defaulted to rest. + <<else>> + so $he has returned to rest. + <</if>> + <<else>> + so $he goes back to <<print $slaves[$i].assignment>>. + <</if>> + <<else>> + so $his assignment has defaulted to rest. + <<= removeJob($slaves[$i], "get treatment in the clinic")>> + <</if>> + </span> + </p> <<set _restedSlaves++, _dI--, _DL-->> <<continue>> <</if>> diff --git a/src/uncategorized/options.tw b/src/uncategorized/options.tw index a47ee015bc66bf7ec8acb98938b0a384d6642ec6..f60f4a15781f8409b2620ba4d081d3935bfd944b 100644 --- a/src/uncategorized/options.tw +++ b/src/uncategorized/options.tw @@ -136,8 +136,8 @@ This save was created using FC version $ver build $releaseID. <<options $showNeighborDetails>> Economic report neighbor details such as trade impacts on culture are - <<option true "Enabled">> - <<option false "Disabled">> + <<option 1 "Enabled">> + <<option 0 "Disabled">> <</options>> <<options $formatNumbers>> @@ -600,8 +600,8 @@ This save was created using FC version $ver build $releaseID. <<options $showDistantRelatives>> Distant relatives such as aunts, nieces and cousins are - <<option true "Enabled">> - <<option false "Disabled">> + <<option 1 "Enabled">> + <<option 0 "Disabled">> <</options>> <</if>> </div> diff --git a/src/uncategorized/persBusiness.tw b/src/uncategorized/persBusiness.tw index 5b130b952a51976988e761f63dc08b12f7f1d9cf..fe6e161bf3c2c6ca6404927c564c629850803903 100644 --- a/src/uncategorized/persBusiness.tw +++ b/src/uncategorized/persBusiness.tw @@ -628,7 +628,7 @@ <</if>> <</if>> - <<case "technical accidents">> /* needs work */ + <<case "technical accidents">> <<set _windfall = Math.trunc((150*$PC.skill.hacking)+random(100,2500)), _X = 0>> <<if $PC.skill.hacking == -100>> <<set _Catchtchance = 10>> diff --git a/src/uncategorized/remoteSurgery.tw b/src/uncategorized/remoteSurgery.tw index feb0de231447a89c7b4ec12ce9ce4c901657d00e..adcb4657963529e967bec58c1c6ca483d2ca9a71 100644 --- a/src/uncategorized/remoteSurgery.tw +++ b/src/uncategorized/remoteSurgery.tw @@ -1759,12 +1759,12 @@ <div class="indent"> <<if $activeSlave.geneticQuirks.albinism == 2>> - [[Albinism prevention treatment|Surgery Degradation][$activeSlave.geneticQuirks.albinism = 0,cashX(forceNeg($surgeryCost*4), "slaveSurgery", $activeSlave), surgeryDamage($activeSlave,40), $activeSlave.chem += 100,$surgeryType = "gene treatment"]] + [[Albinism prevention treatment|Surgery Degradation][induceAlbinism($activeSlave, 0), cashX(forceNeg($surgeryCost * 4), "slaveSurgery", $activeSlave), surgeryDamage($activeSlave, 40), $activeSlave.chem += 100, $surgeryType = "gene treatment"]] <<elseif $activeSlave.geneticQuirks.albinism == 1 && $geneticMappingUpgrade >= 2>> - [[Albinism activation treatment|Surgery Degradation][$activeSlave.geneticQuirks.albinism = 2,cashX(forceNeg($surgeryCost*4), "slaveSurgery", $activeSlave), surgeryDamage($activeSlave,40), $activeSlave.chem += 100,$surgeryType = "gene treatment"]] //Will not have an active effect// - | [[Albinism carrier corrective treatment|Surgery Degradation][$activeSlave.geneticQuirks.albinism = 0,cashX(forceNeg($surgeryCost*4), "slaveSurgery", $activeSlave), surgeryDamage($activeSlave,40), $activeSlave.chem += 100,$surgeryType = "gene treatment"]] + [[Albinism activation treatment|Surgery Degradation][induceAlbinism($activeSlave, 2), cashX(forceNeg($surgeryCost * 4), "slaveSurgery", $activeSlave), surgeryDamage($activeSlave, 40), $activeSlave.chem += 100, $surgeryType = "gene treatment"]] //Will not have an active effect// + | [[Albinism carrier corrective treatment|Surgery Degradation][induceAlbinism($activeSlave, 0), cashX(forceNeg($surgeryCost * 4), "slaveSurgery", $activeSlave), surgeryDamage($activeSlave,40), $activeSlave.chem += 100,$surgeryType = "gene treatment"]] <<elseif $geneticFlawLibrary == 1>> - [[Induced albinism treatment|Surgery Degradation][$activeSlave.geneticQuirks.albinism = 2,cashX(forceNeg($surgeryCost*10), "slaveSurgery", $activeSlave), surgeryDamage($activeSlave,40), $activeSlave.chem += 40,$surgeryType = "gene treatment"]] //This will induce @@.orange;albinism@@ in $his genetic code// + [[Induced albinism treatment|Surgery Degradation][induceAlbinism($activeSlave, 2), cashX(forceNeg($surgeryCost * 10), "slaveSurgery", $activeSlave), surgeryDamage($activeSlave, 40), $activeSlave.chem += 40,$surgeryType = "gene treatment"]] //This will induce @@.orange;albinism@@ in $his genetic code// <</if>> </div> diff --git a/src/uncategorized/saChoosesOwnJob.tw b/src/uncategorized/saChoosesOwnJob.tw index f69d8ea9cf35d4aa69a19df2ea11f3c24fac4784..849db7560e048932466aca30a3e96dff243501a9 100644 --- a/src/uncategorized/saChoosesOwnJob.tw +++ b/src/uncategorized/saChoosesOwnJob.tw @@ -2,6 +2,8 @@ <<set _clinicL = $CliniciIDs.length, _schoolL = $SchlRiIDs.length, _servQL = $ServQiIDs.length, _nurseryL = $NurseryiIDs.length, _brothelL = $BrothiIDs.length, _clubL = $ClubiIDs.length, _masterSL = $MastSiIDs.length, _spaL = $SpaiIDs.length, _dairyL = $DairyiIDs.length>> +<<setLocalPronouns $slaves[$i]>> + <<if ($slaves[$i].choosesOwnAssignment == 0) || ($slaves[$i].fuckdoll > 0) || ($slaves[$i].fetish == "mindbroken")>> /* nothing to do */ diff --git a/src/uncategorized/schoolroomReport.tw b/src/uncategorized/schoolroomReport.tw index b939302ffebde08527c2dc09a1394c83e7e6a1f9..252b5d1c427087443b638988a6bda9304da3519e 100644 --- a/src/uncategorized/schoolroomReport.tw +++ b/src/uncategorized/schoolroomReport.tw @@ -162,7 +162,11 @@ <</if>> /% Education done? Has to be here before we run the SA's or there will be double entries for slave %/ <<if $slaves[$i].fetish == "mindbroken">> - <<= removeJob($slaves[$i], "learn in the schoolroom")>> + <<if $assignmentRecords[$slaves[$i].ID]>> + <<= assignJobSafely($slaves[$i], $assignmentRecords[$slaves[$i].ID])>> + <<else>> + <<= removeJob($slaves[$i], "learn in the schoolroom")>> + <</if>> <<set _restedSlaves++, _dI--, _DL-->> <<continue>> <<else>> @@ -173,8 +177,29 @@ <<if ($slaves[$i].skill.entertainment > 30) || (($schoolroomUpgradeSkills == 0) && ($slaves[$i].skill.entertainment > 10))>> <<if ($slaves[$i].skill.anal > 30) || (($schoolroomUpgradeSkills == 0) && ($slaves[$i].skill.anal > 10))>> <<if ($slaves[$i].skill.vaginal > 30) || (($schoolroomUpgradeSkills == 0) && ($slaves[$i].skill.vaginal > 10)) || ($slaves[$i].vagina < 0)>> - <br><br>''__@@.pink;$slaves[$i].slaveName@@__'' can learn little from further classes, so @@.yellow;_his2 assignment has defaulted to rest.@@ - <<= removeJob($slaves[$i], "learn in the schoolroom")>> + <p> + <span class="slave-name">$slaves[$i].slaveName</span> can learn little from further classes, + <span class="noteworthy"> + <<if $assignmentRecords[$slaves[$i].ID]>> + <<set _oldJob = $assignmentRecords[$slaves[$i].ID]>> + <<= assignJobSafely($slaves[$i], _oldJob)>> + <<if $slaves[$i].choosesOwnAssignment === 1>> + and $he is resting before choosing another task. + <<elseif $slaves[$i].assignment === "rest">> + <<if _oldJob != "rest">> + and since $he was unable to return to $his old task to <<print _oldJob>>, $his assignment has defaulted to rest. + <<else>> + so $he has returned to rest. + <</if>> + <<else>> + so $he goes back to <<print $slaves[$i].assignment>>. + <</if>> + <<else>> + so _his2 assignment has defaulted to rest. + <<= removeJob($slaves[$i], "learn in the schoolroom")>> + <</if>> + </span> + </p> <<set _restedSlaves++, _dI--, _DL-->> <<continue>> <</if>> diff --git a/src/uncategorized/slaveInteract.tw b/src/uncategorized/slaveInteract.tw index 076fc739f09927e53467dac6c3d95a51bb77f2a9..46253cc557bc1b8db6fbdbeab9ffc4da6a207e79 100644 --- a/src/uncategorized/slaveInteract.tw +++ b/src/uncategorized/slaveInteract.tw @@ -506,7 +506,17 @@ /* CAN BE REASSIGNED */ - Assignment: <strong><span id="assign">$activeSlave.assignment<<if $activeSlave.sentence>> ($activeSlave.sentence weeks)<</if>></span>.</strong> + Assignment: + <span id="assign" font-weight="bold"> + <<if $activeSlave.sentence>> + $activeSlave.assignment ($activeSlave.sentence weeks). + <<else>> + $activeSlave.assignment. + <</if>> + </span> + <<if $assignmentRecords[$activeSlave.ID] && $assignmentRecords[$activeSlave.ID] != $activeSlave.assignment>> + Previously: <<print $assignmentRecords[$activeSlave.ID]>> + <</if>> <span id="assignmentLinks"><<= App.UI.SlaveInteract.assignmentBlock("assignmentLinks")>></span> <<set _numFacilities = $brothel+$club+$dairy+$farmyard+$servantsQuarters+$masterSuite+$spa+$nursery+$clinic+$schoolroom+$cellblock+$arcade+$HGSuite>> diff --git a/src/uncategorized/spaReport.tw b/src/uncategorized/spaReport.tw index 28d77963b349707c5dd73595fbd817e9e96133cf..40326adbf1d99702c29b91fa16b674eb377f3e2c 100644 --- a/src/uncategorized/spaReport.tw +++ b/src/uncategorized/spaReport.tw @@ -288,8 +288,29 @@ <<set $slaves[$i].rules.living = "luxurious">> <</switch>> <<if ($slaves[$i].health.condition >= 50) && ($slaves[$i].health.tired < 20) && ($slaves[$i].trust > 60) && ($slaves[$i].devotion > 60) && ($slaves[$i].fetish != "mindbroken") && ($slaves[$i].sexualFlaw == "none") && ($slaves[$i].behavioralFlaw == "none")>> - <br><br>''__@@.pink;$slaves[$i].slaveName@@__'' is feeling well enough to leave $spaName, so @@.yellow;$his assignment has defaulted to rest.@@ - <<= removeJob($slaves[$i], "rest in the spa")>> + <p> + <span class="slave-name">$slaves[$i].slaveName</span> is feeling well enough to leave $spaName, + <span class="noteworthy"> + <<if $assignmentRecords[$slaves[$i].ID]>> + <<set _oldJob = $assignmentRecords[$slaves[$i].ID]>> + <<= assignJobSafely($slaves[$i], _oldJob)>> + <<if $slaves[$i].choosesOwnAssignment === 1>> + and $he is resting before choosing another task. + <<elseif $slaves[$i].assignment === "rest">> + <<if _oldJob != "rest">> + and since $he was unable to return to $his old task to <<print _oldJob>>, $his assignment has defaulted to rest. + <<else>> + so $he has returned to rest. + <</if>> + <<else>> + so $he goes back to <<print $slaves[$i].assignment>>. + <</if>> + <<else>> + so $his assignment has defaulted to rest. + <<= removeJob($slaves[$i], "rest in the spa")>> + <</if>> + </span> + </p> <<set _restedSlaves++, _DL--, _dI-->> <<continue>> <</if>> diff --git a/src/utility/descriptionWidgetsFlesh.tw b/src/utility/descriptionWidgetsFlesh.tw index abc4fab49926c3f8da89f0b44ddab0f18c14c8ca..c65f1b74cd99be872c6b56125f5cbdeb976cab74 100644 --- a/src/utility/descriptionWidgetsFlesh.tw +++ b/src/utility/descriptionWidgetsFlesh.tw @@ -81,7 +81,7 @@ $He has <</if>> <</if>> <<elseif $activeSlave.waist > 10>> - an @@.red;unattractive waist@@ that conceals $his <<if $activeSlave.visualAge > 25>>girlish<<else>>womanly<</if>> figure<<if $activeSlave.weight > 30>> and accentuates how fat $he is<<elseif $activeSlave.weight < -30>> despite how thin $he is<</if>>. + an @@.red;unattractive waist@@ that conceals $his <<if $activeSlave.physicalAge <= 25>>girlish<<else>>womanly<</if>> figure<<if $activeSlave.weight > 30>> and accentuates how fat $he is<<elseif $activeSlave.weight < -30>> despite how thin $he is<</if>>. <<if $activeSlave.belly >= 1500>> <<if $activeSlave.belly >= 750000>> $His _belly belly grotesquely bulges around $his waist. @@ -121,7 +121,7 @@ $He has <</if>> <</if>> <<elseif $activeSlave.waist >= -10>> - an average waist for a <<if $activeSlave.visualAge > 25>>$girl<<else>>$woman<</if>><<if $activeSlave.weight > 30>>, though it looks broader since $he's fat<<elseif $activeSlave.weight < -30>>, though it looks narrower since $he's thin<</if>>. + an average waist for a <<if $activeSlave.physicalAge <= 25>>$girl<<else>>$woman<</if>><<if $activeSlave.weight > 30>>, though it looks broader since $he's fat<<elseif $activeSlave.weight < -30>>, though it looks narrower since $he's thin<</if>>. <<if $activeSlave.belly >= 1500>> <<if $activeSlave.belly >= 750000>> $His _belly belly grotesquely bulges around $his waist. @@ -161,7 +161,7 @@ $He has <</if>> <</if>> <<elseif $activeSlave.waist >= -40>> - a nice @@.pink;feminine waist@@ that gives $him a <<if $activeSlave.visualAge > 25>>girlish<<else>>womanly<</if>> figure<<if $activeSlave.weight > 30>> despite $his extra weight<<elseif $activeSlave.weight < -30>> and accentuates how thin $he is<</if>>. + a nice @@.pink;feminine waist@@ that gives $him a <<if $activeSlave.physicalAge <= 25>>girlish<<else>>womanly<</if>> figure<<if $activeSlave.weight > 30>> despite $his extra weight<<elseif $activeSlave.weight < -30>> and accentuates how thin $he is<</if>>. <<if $activeSlave.belly >= 1500>> <<if $activeSlave.belly >= 750000>> $His _belly belly grotesquely bulges around $his waist.