diff --git a/SanityCheck.jar b/SanityCheck.jar index 478417de473b6dd0de5575eef4d474e2ef3d7073..f19e52f690973f356affb974151449cdce45adcc 100644 Binary files a/SanityCheck.jar and b/SanityCheck.jar differ diff --git a/devNotes/VersionChangeLog-Premod+LoliMod.txt b/devNotes/VersionChangeLog-Premod+LoliMod.txt index dcbfa59a4fe8531ce169f16315e6cd6d2ccb5cc9..50e7a259afe2b71c73c12e2ba7c4abf732b9bcf5 100644 --- a/devNotes/VersionChangeLog-Premod+LoliMod.txt +++ b/devNotes/VersionChangeLog-Premod+LoliMod.txt @@ -1,13 +1,18 @@ Pregmod -0.10.7.1-2.2.x +0.10.7.1-2.3.x + 0 -player can now be impregnated during the futanari sister orgy -added tracking for futanari sister impregnation -player medicine and trading skill now more useful + -easier to passively gain slaving skill + -UI changes -fixes -code cleaning +0.10.7.1-2.2.x + 03/15/2019 5 diff --git a/devNotes/twine CSS b/devNotes/twine CSS index e3da430ae7e5616908919995f033dfb7add7508c..39e646cedfe25ebed9c196a0f0c18c6c75cd2f93 100644 --- a/devNotes/twine CSS +++ b/devNotes/twine CSS @@ -656,7 +656,6 @@ div.tab button.active { border: #555 solid 0.5px; border-top-width: 0; vertical-align: top; - background: linear-gradient(transparent,#222); -moz-user-select: none; min-width: 79px; /* 80px - 1px for border */ display: inline-block; @@ -666,6 +665,7 @@ div.tab button.active { .optionComment { vertical-align: top; color: gray; + padding-left: 10px; } /* But don't add the | after the last one */ @@ -688,11 +688,11 @@ div.tab button.active { } .optionMacroOption:hover { - background: linear-gradient(#2F2F2F,#111); + background: #2F2F2F; } .optionMacroSelected { - background: linear-gradient(#2F2F2F,#111); + background: #2F2F2F; padding: 0 10px; min-width: 80px; cursor: pointer; @@ -705,8 +705,8 @@ div.tab button.active { } .optionValue input { - padding: 3px; - background: linear-gradient(transparent,#222); + padding: 3px 3px 3px 10px; + background: transparent; border: #555 solid 0.5px; border-top-width: 0; min-width: unset; diff --git a/devTools/javaSanityCheck/htmlTags b/devTools/javaSanityCheck/htmlTags index 466a9b301e715f5b896bd84c38941bf61c4ec985..d6797ca12f38ec785c0e45c7f4df696643408c0e 100644 --- a/devTools/javaSanityCheck/htmlTags +++ b/devTools/javaSanityCheck/htmlTags @@ -29,7 +29,7 @@ h4;1 hr;0 html;1 i;1 -img;1 +img;0 input;0 li;1 option;1 diff --git a/devTools/javaSanityCheck/info.txt b/devTools/javaSanityCheck/info.txt new file mode 100644 index 0000000000000000000000000000000000000000..e949bd8d03f785569f824dbae27c9c282bcb8014 --- /dev/null +++ b/devTools/javaSanityCheck/info.txt @@ -0,0 +1,2 @@ +Full sources for easy import into IDE can be found here: +https://gitgud.io/Arkerthan/twine-sanitycheck diff --git a/devTools/javaSanityCheck/src/DisallowedTagException.java b/devTools/javaSanityCheck/src/DisallowedTagException.java index cd479fbdf5f9c8b42a9271b8c0049cba10bcb72a..2dfc4a4f0cd3f43b805179a7ab62edcf17a234ff 100644 --- a/devTools/javaSanityCheck/src/DisallowedTagException.java +++ b/devTools/javaSanityCheck/src/DisallowedTagException.java @@ -1,8 +1,11 @@ package org.arkerthan.sanityCheck; +/** + * @author Arkerthan + */ public class DisallowedTagException extends RuntimeException { - public DisallowedTagException(String tag) { - super(tag); - } + public DisallowedTagException(String tag) { + super(tag); + } } diff --git a/devTools/javaSanityCheck/src/Main.java b/devTools/javaSanityCheck/src/Main.java index 84c471d2148d57206c18d5ac8a217f67bac07d21..15ed975f26878ccbf93d95ead95073f19077dfbd 100644 --- a/devTools/javaSanityCheck/src/Main.java +++ b/devTools/javaSanityCheck/src/Main.java @@ -14,315 +14,318 @@ import java.util.*; /** * @author Arkerthan + * @version 1.0 */ public class Main { - public static TagSearchTree<Tag> htmlTags, twineTags; - private static String currentFile; - private static int currentLine, currentPosition; - private static Stack<Element> stack; - private static List<SyntaxError> errors = new LinkedList<>(); - private static String[] excluded; - - public static void main(String[] args) { - - //setup - setupExclude(); - setupHtmlTags(); - setupTwineTags(); - Path workingDir = Paths.get("").toAbsolutePath(); - - //actual sanityCheck - runSanityCheckInDirectory(workingDir, new File("src/")); - - //output errors - for (SyntaxError e : - errors) { - System.out.println(e.getError()); - } - } - - - /** - * Goes through the whole directory including subdirectories and runs - * {@link Main#sanityCheck(Path)} on all .tw files - * - * @param dir to be checked - */ - private static void runSanityCheckInDirectory(Path workingDir, File dir) { - //subdirectories are checked recursively - - try { - for (File file : dir.listFiles()) { - if (file.isFile()) { //run sanityCheck if file is a .tw file - String path = file.getAbsolutePath(); - if (path.endsWith(".tw")) { - sanityCheck(workingDir.relativize(file.toPath())); - } - } else if (file.isDirectory()) { - runSanityCheckInDirectory(workingDir, file.getAbsoluteFile()); - } - } - } catch (NullPointerException e) { - e.printStackTrace(); - System.err.println("Couldn't read directory " + currentFile); - System.exit(-1); - } - } - - /** - * Runs the sanity check for one file. Does not run if file is excluded. - * - * @param path file to be checked - */ - private static void sanityCheck(Path path) { - File file = path.toFile(); - - // replace this with a known encoding if possible - Charset encoding = Charset.defaultCharset(); - - if (!excluded(file.getPath())) { - currentFile = file.getPath(); - currentLine = 1; - stack = new Stack<>(); - - //actually opening and reading the file - try (InputStream in = new FileInputStream(file); - Reader reader = new InputStreamReader(in, encoding); - // buffer for efficiency - Reader buffer = new BufferedReader(reader)) { - handleCharacters(buffer); - } catch (IOException e) { - e.printStackTrace(); - System.err.println("Couldn't read " + file); - } - } - } - - /** - * sets up a {@link TagSearchTree<Tag>} for fast access of HTML tags later - */ - private static void setupHtmlTags() { - //load HTML tags into a list - List<Tag> TagsList = loadTags("devTools/javaSanityCheck/htmlTags"); - - //turn List into alphabetical search tree - try { - htmlTags = new TagSearchTree<>(TagsList); - } catch (ArrayIndexOutOfBoundsException e) { - System.err.println("Illegal Character in devTools/javaSanityCheck/htmlTags"); - System.exit(-1); - } - } - - /** - * sets up a {@link TagSearchTree<Tag>} for fast access of twine tags later - */ - private static void setupTwineTags() { - //load twine tags into a list - List tagsList = loadTags("devTools/javaSanityCheck/twineTags"); - - //turn List into alphabetical search tree - try { - twineTags = new TagSearchTree<>(tagsList); - } catch (ArrayIndexOutOfBoundsException e) { - System.err.println("Illegal Character in devTools/javaSanityCheck/twineTags"); - System.exit(-1); - } - } - - /** - * Loads a list of tags from a file - * - * @param filePath file to load tags from - * @return loaded tags - */ - private static List<Tag> loadTags(String filePath) { - List<Tag> tagsList = new LinkedList<>(); - try { - Files.lines(new File(filePath).toPath()).map(String::trim) - .filter(s -> !s.startsWith("#")) - .forEach(s -> tagsList.add(parseTag(s))); - } catch (IOException e) { - System.err.println("Couldn't read " + filePath); - } - return tagsList; - } - - /** - * Turns a string into a Tag - * ";1" at the end of the String indicates that the tag needs to be closed later - * - * @param s tag as String - * @return tag as Tag - */ - private static Tag parseTag(String s) { - String[] st = s.split(";"); - if (st.length > 1 && st[1].equals("1")) { - return new Tag(st[0], false); - } - return new Tag(st[0], true); - } - - /** - * sets up the excluded files array. - */ - private static void setupExclude() { - //load excluded files - List<String> excludedList = new ArrayList<>(); - try { - Files.lines(new File("devTools/javaSanityCheck/excluded").toPath()).map(String::trim) - .filter(s -> !s.startsWith("#")) - .forEach(excludedList::add); - } catch (IOException e) { - System.err.println("Couldn't read devTools/javaSanityCheck/excluded"); - } - - //turn excluded files into an array and change path to windows style if needed - if (isWindows()) { - excluded = new String[excludedList.size()]; - int i = 0; - for (String s : - excludedList) { - excluded[i++] = s.replaceAll("/", "\\\\"); - } - } else { - excluded = excludedList.toArray(new String[0]); - } - } - - /** - * @return whether OS is Windows or not - */ - private static boolean isWindows() { - return (System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("windows")); - } - - /** - * checks if a file or directory is excluded from the sanity check - * - * @param s file/directory to be checked - * @return whether it is excluded or not - */ - private static boolean excluded(String s) { - for (String ex : - excluded) { - if (s.startsWith(ex)) return true; - } - return false; - } - - /** - * Reads the file character by character. - * - * @param reader reader that is read - * @throws IOException thrown if the file can't be read - */ - private static void handleCharacters(Reader reader) throws IOException { - int r; - while ((r = reader.read()) != -1) { - char c = (char) r; - handleCharacter(c); - } - } - - /** - * Handles a single character - * - * @param c next character - */ - private static void handleCharacter(char c) { - //updating position - currentPosition++; - if (c == '\n') { - currentLine++; - currentPosition = 1; - } - - //try applying to the innermost element - if (!stack.empty()) { - int change; - try { - change = stack.peek().handleChar(c); - } catch (SyntaxError e) { - change = e.getChange(); - addError(e); - } - - //change greater 0 means the innermost element did some work - if (change > 0) { - //2 means the Element is complete - if (change == 2) { - //remove the topmost element from stack since it is complete - stack.pop(); - return; - } - //3 means the Element is complete and part of a two or more tag system - if (change == 3) { - //remove the topmost element from stack since it is complete - KnownElement k = stack.pop().getKnownElement(); - //if KnownElement k is closing another element, check if there is one and remove it - if (k.isClosing()) { - if (stack.empty()) { //there are no open elements at all - addError(new SyntaxError("Closed tag " + k.getShortDescription() + " without " + - "having any open tags.", -2)); - } else if (stack.peek() instanceof KnownElement) { - //get opening tag - KnownElement kFirst = (KnownElement) stack.pop(); - //check if closing element matches the opening element - if (!kFirst.isMatchingElement(k)) { - addError(new SyntaxError("Opening tag " + kFirst.getShortDescription() + - " does not match closing tag " + k.getShortDescription() + ".", -2)); - } - } else { - //There closing tag inside another not Known element: <div </html> - addError(new SyntaxError("Closing tag " + k.getShortDescription() + " inside " + - "another tag " + stack.peek().getShortDescription() + " without opening first.", - -2, true)); - } - } - //check if the element needs to be closed by another - if (k.isOpening()) { - stack.push(k); - } - return; - } - //means the element couldn't do anything with it and is finished - if (change == 4) { - stack.pop(); - } else { - return; - } - } - } - - - //innermost element was uninterested, trying to find matching element - switch (c) { - //case '@': - //stack.push(new AtElement(currentLine, currentPosition)); - //break; - case '<': - stack.push(new AngleBracketElement(currentLine, currentPosition)); - break; - //case '>': - //addError(new SyntaxError("Dangling \">\", current innermost: " + (stack.empty() ? "null" : stack.peek().getShortDescription()), -2)); - //break; - case '/': - stack.push(new CommentElement(currentLine, currentPosition)); - break; - } - } - - /** - * add an error to the error list - * - * @param e new error - */ - private static void addError(SyntaxError e) { - e.setFile(currentFile); - e.setLine(currentLine); - e.setPosition(currentPosition); - errors.add(e); - } + public static TagSearchTree<Tag> htmlTags, twineTags; + private static String currentFile; + private static int currentLine, currentPosition; + private static Stack<Element> stack; + private static List<SyntaxError> errors = new LinkedList<>(); + private static String[] excluded; + + public static void main(String[] args) { + + //setup + setupExclude(); + setupHtmlTags(); + setupTwineTags(); + Path workingDir = Paths.get("").toAbsolutePath(); + + //actual sanityCheck + runSanityCheckInDirectory(workingDir, new File("src/")); + + //output errors + for (SyntaxError e : + errors) { + System.out.println(e.getError()); + } + } + + + /** + * Goes through the whole directory including subdirectories and runs + * {@link Main#sanityCheck(Path)} on all .tw files + * + * @param dir to be checked + */ + private static void runSanityCheckInDirectory(Path workingDir, File dir) { + //subdirectories are checked recursively + + try { + for (File file : dir.listFiles()) { + if (file.isFile()) { //run sanityCheck if file is a .tw file + String path = file.getAbsolutePath(); + if (path.endsWith(".tw")) { + sanityCheck(workingDir.relativize(file.toPath())); + } + } else if (file.isDirectory()) { + runSanityCheckInDirectory(workingDir, file.getAbsoluteFile()); + } + } + } catch (NullPointerException e) { + e.printStackTrace(); + System.err.println("Couldn't read directory " + currentFile); + System.exit(-1); + } + } + + /** + * Runs the sanity check for one file. Does not run if file is excluded. + * + * @param path file to be checked + */ + private static void sanityCheck(Path path) { + File file = path.toFile(); + + // replace this with a known encoding if possible + Charset encoding = Charset.defaultCharset(); + + if (!excluded(file.getPath())) { + currentFile = file.getPath(); + currentLine = 1; + stack = new Stack<>(); + + //actually opening and reading the file + try (InputStream in = new FileInputStream(file); + Reader reader = new InputStreamReader(in, encoding); + // buffer for efficiency + Reader buffer = new BufferedReader(reader)) { + handleCharacters(buffer); + } catch (IOException e) { + e.printStackTrace(); + System.err.println("Couldn't read " + file); + } + } + } + + /** + * sets up a {@link TagSearchTree<Tag>} for fast access of HTML tags later + */ + private static void setupHtmlTags() { + //load HTML tags into a list + List<Tag> TagsList = loadTags("devTools/javaSanityCheck/htmlTags"); + + //turn List into alphabetical search tree + try { + htmlTags = new TagSearchTree<>(TagsList); + } catch (ArrayIndexOutOfBoundsException e) { + System.err.println("Illegal Character in devTools/javaSanityCheck/htmlTags"); + System.exit(-1); + } + } + + /** + * sets up a {@link TagSearchTree<Tag>} for fast access of twine tags later + */ + private static void setupTwineTags() { + //load twine tags into a list + List tagsList = loadTags("devTools/javaSanityCheck/twineTags"); + + //turn List into alphabetical search tree + try { + twineTags = new TagSearchTree<>(tagsList); + } catch (ArrayIndexOutOfBoundsException e) { + System.err.println("Illegal Character in devTools/javaSanityCheck/twineTags"); + System.exit(-1); + } + } + + /** + * Loads a list of tags from a file + * + * @param filePath file to load tags from + * @return loaded tags + */ + private static List<Tag> loadTags(String filePath) { + List<Tag> tagsList = new LinkedList<>(); + try { + Files.lines(new File(filePath).toPath()).map(String::trim) + .filter(s -> !s.startsWith("#")) + .forEach(s -> tagsList.add(parseTag(s))); + } catch (IOException e) { + System.err.println("Couldn't read " + filePath); + } + return tagsList; + } + + /** + * Turns a string into a Tag + * ";1" at the end of the String indicates that the tag needs to be closed later + * + * @param s tag as String + * @return tag as Tag + */ + private static Tag parseTag(String s) { + String[] st = s.split(";"); + if (st.length > 1 && st[1].equals("1")) { + return new Tag(st[0], false); + } + return new Tag(st[0], true); + } + + /** + * sets up the excluded files array. + */ + private static void setupExclude() { + //load excluded files + List<String> excludedList = new ArrayList<>(); + try { + Files.lines(new File("devTools/javaSanityCheck/excluded").toPath()).map(String::trim) + .filter(s -> !s.startsWith("#")) + .forEach(excludedList::add); + } catch (IOException e) { + System.err.println("Couldn't read devTools/javaSanityCheck/excluded"); + } + + //turn excluded files into an array and change path to windows style if needed + if (isWindows()) { + excluded = new String[excludedList.size()]; + int i = 0; + for (String s : + excludedList) { + excluded[i++] = s.replaceAll("/", "\\\\"); + } + } else { + excluded = excludedList.toArray(new String[0]); + } + } + + /** + * @return whether OS is Windows or not + */ + private static boolean isWindows() { + return (System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("windows")); + } + + /** + * checks if a file or directory is excluded from the sanity check + * + * @param s file/directory to be checked + * @return whether it is excluded or not + */ + private static boolean excluded(String s) { + for (String ex : + excluded) { + if (s.startsWith(ex)) return true; + } + return false; + } + + /** + * Reads the file character by character. + * + * @param reader reader that is read + * @throws IOException thrown if the file can't be read + */ + private static void handleCharacters(Reader reader) throws IOException { + int r; + while ((r = reader.read()) != -1) { + char c = (char) r; + handleCharacter(c); + } + } + + /** + * Handles a single character + * + * @param c next character + */ + private static void handleCharacter(char c) { + //updating position + currentPosition++; + if (c == '\n') { + currentLine++; + currentPosition = 1; + } + + //try applying to the innermost element + if (!stack.empty()) { + int change; + try { + change = stack.peek().handleChar(c); + } catch (SyntaxError e) { + change = e.getChange(); + addError(e); + } + + //change greater 0 means the innermost element did some work + if (change > 0) { + //2 means the Element is complete + if (change == 2) { + //remove the topmost element from stack since it is complete + stack.pop(); + return; + } + //3 means the Element is complete and part of a two or more tag system + if (change == 3) { + //remove the topmost element from stack since it is complete + KnownElement k = stack.pop().getKnownElement(); + //if KnownElement k is closing another element, check if there is one and remove it + if (k.isClosing()) { + if (stack.empty()) { //there are no open elements at all + addError(new SyntaxError("Closed tag " + k.getShortDescription() + " without " + + "having any open tags.", -2)); + } else if (stack.peek() instanceof KnownElement) { + //get opening tag + KnownElement kFirst = (KnownElement) stack.pop(); + //check if closing element matches the opening element + if (!kFirst.isMatchingElement(k)) { + addError(new SyntaxError("Opening tag " + kFirst.getShortDescription() + + " does not match closing tag " + k.getShortDescription() + ".", -2)); + } + } else { + //There closing tag inside another not Known element: <div </html> + addError(new SyntaxError("Closing tag " + k.getShortDescription() + " inside " + + "another tag " + stack.peek().getShortDescription() + " without opening first.", + -2, true)); + } + } + //check if the element needs to be closed by another + if (k.isOpening()) { + stack.push(k); + } + return; + } + //means the element couldn't do anything with it and is finished + if (change == 4) { + stack.pop(); + } else { + return; + } + } + } + + + //innermost element was uninterested, trying to find matching element + switch (c) { + //case '@': + //stack.push(new AtElement(currentLine, currentPosition)); + //break; + case '<': + stack.push(new AngleBracketElement(currentLine, currentPosition)); + break; + //case '>': + //addError(new SyntaxError("Dangling \">\", current innermost: " + (stack.empty() ? "null" : stack.peek().getShortDescription()), -2)); + //break; + case '/': + stack.push(new CommentElement(currentLine, currentPosition)); + break; + //case '(': + // stack.push(new BracketElement(currentLine, currentPosition)); + } + } + + /** + * add an error to the error list + * + * @param e new error + */ + private static void addError(SyntaxError e) { + e.setFile(currentFile); + e.setLine(currentLine); + e.setPosition(currentPosition); + errors.add(e); + } } diff --git a/devTools/javaSanityCheck/src/SyntaxError.java b/devTools/javaSanityCheck/src/SyntaxError.java index c30e5fbc101c558ff3cabe669d38c0e89f50e3f7..1e1b8936f8120cce9dfc88ce42bf29cff0c4e869 100644 --- a/devTools/javaSanityCheck/src/SyntaxError.java +++ b/devTools/javaSanityCheck/src/SyntaxError.java @@ -1,64 +1,67 @@ package org.arkerthan.sanityCheck; +/** + * @author Arkerthan + */ public class SyntaxError extends Exception { - private String file; - private int line, position; - private String description; - private int change; //see Element for values; -2 means not thrown - private boolean warning = false; + private String file; + private int line, position; + private String description; + private int change; //see Element for values; -2 means not thrown + private boolean warning = false; - /** - * @param description description of error - * @param change state change as specified in Element - */ - public SyntaxError(String description, int change) { - this.description = description; - this.change = change; - } + /** + * @param description description of error + * @param change state change as specified in Element + */ + public SyntaxError(String description, int change) { + this.description = description; + this.change = change; + } - /** - * @param description description of error - * @param change state change as specified in Element - * @param warning whether it is a warning or an error - */ - public SyntaxError(String description, int change, boolean warning) { - this(description, change); - this.warning = warning; - } + /** + * @param description description of error + * @param change state change as specified in Element + * @param warning whether it is a warning or an error + */ + public SyntaxError(String description, int change, boolean warning) { + this(description, change); + this.warning = warning; + } - /** - * @param file at which the error occurred - */ - public void setFile(String file) { - this.file = file; - } + /** + * @param file at which the error occurred + */ + public void setFile(String file) { + this.file = file; + } - /** - * @param line in which the error occurred - */ - public void setLine(int line) { - this.line = line; - } + /** + * @param line in which the error occurred + */ + public void setLine(int line) { + this.line = line; + } - /** - * @param position at which the error occurred - */ - public void setPosition(int position) { - this.position = position; - } + /** + * @param position at which the error occurred + */ + public void setPosition(int position) { + this.position = position; + } - /** - * @return error message - */ - public String getError() { - String s = warning ? "Warning: " : "Error: "; - return s + file + ": " + line + ":" + position + " : " + description; - } + /** + * @return error message + */ + public String getError() { + String s = warning ? "Warning: " : "Error: "; + return s + file + ": " + line + ":" + position + " : " + description; + } - /** - * @return change that happened in Element before it was thrown. -1 if not thrown. - */ - public int getChange() { - return change; - } + /** + * @return change that happened in Element before it was thrown. -1 if not thrown. + */ + public int getChange() { + return change; + } } diff --git a/devTools/javaSanityCheck/src/Tag.java b/devTools/javaSanityCheck/src/Tag.java index 5c3c92651a71beb8a4e3cba73d1eb64238fc9908..10ca580417dee08dada0e598c05331e66175b901 100644 --- a/devTools/javaSanityCheck/src/Tag.java +++ b/devTools/javaSanityCheck/src/Tag.java @@ -1,11 +1,14 @@ package org.arkerthan.sanityCheck; +/** + * @author Arkerthan + */ public class Tag { - public final String tag; - public final boolean single; + public final String tag; + public final boolean single; - public Tag(String tag, boolean single) { - this.tag = tag; - this.single = single; - } + public Tag(String tag, boolean single) { + this.tag = tag; + this.single = single; + } } diff --git a/devTools/javaSanityCheck/src/TagSearchTree.java b/devTools/javaSanityCheck/src/TagSearchTree.java index 71e89ec769ff658b246886a179976055f2633709..54c45bbd07c34e905ed19f2a18a22add447397b0 100644 --- a/devTools/javaSanityCheck/src/TagSearchTree.java +++ b/devTools/javaSanityCheck/src/TagSearchTree.java @@ -3,78 +3,79 @@ package org.arkerthan.sanityCheck; import java.util.List; /** + * @param <E> Tag class to be stored + * @author Arkerthan + * <p> * Tag SearchTree stores Tags in an alphabetical search tree. * Once created the search tree can't be changed anymore. - * - * @param <E> Tag class to be stored */ public class TagSearchTree<E extends Tag> { - private static final int SIZE = 128; - private final TagSearchTree<E>[] branches; - private E element = null; - private String path; + private static final int SIZE = 128; + private final TagSearchTree<E>[] branches; + private E element = null; + private String path; - /** - * creates a new empty TagSearchTree - */ - private TagSearchTree() { - branches = new TagSearchTree[SIZE]; - } + /** + * creates a new empty TagSearchTree + */ + private TagSearchTree() { + branches = new TagSearchTree[SIZE]; + } - /** - * Creates a new filled TagSearchTree - * - * @param list Tags to be inserted - */ - public TagSearchTree(List<E> list) { - this(); - for (E e : list) { - this.add(e, 0); - } - } + /** + * Creates a new filled TagSearchTree + * + * @param list Tags to be inserted + */ + public TagSearchTree(List<E> list) { + this(); + for (E e : list) { + this.add(e, 0); + } + } - /** - * adds a new Tag to the TagSearchTree - * - * @param e Tag to be stored - * @param index index of relevant char for adding in tag - */ - private void add(E e, int index) { - //set the path to here - path = e.tag.substring(0, index); - //checks if tag has to be stored here or further down - if (e.tag.length() == index) { - element = e; - } else { - //store tag in correct branch - char c = e.tag.charAt(index); - if (branches[c] == null) { - branches[c] = new TagSearchTree<>(); - } - branches[c].add(e, index + 1); - } - } + /** + * adds a new Tag to the TagSearchTree + * + * @param e Tag to be stored + * @param index index of relevant char for adding in tag + */ + private void add(E e, int index) { + //set the path to here + path = e.tag.substring(0, index); + //checks if tag has to be stored here or further down + if (e.tag.length() == index) { + element = e; + } else { + //store tag in correct branch + char c = e.tag.charAt(index); + if (branches[c] == null) { + branches[c] = new TagSearchTree<>(); + } + branches[c].add(e, index + 1); + } + } - /** - * @param c character of branch needed - * @return branch or null if branch doesn't exist - */ - public TagSearchTree<E> getBranch(char c) { - if (c >= SIZE) return null; - return branches[c]; - } + /** + * @param c character of branch needed + * @return branch or null if branch doesn't exist + */ + public TagSearchTree<E> getBranch(char c) { + if (c >= SIZE) return null; + return branches[c]; + } - /** - * @return stored Tag, null if empty - */ - public E getElement() { - return element; - } + /** + * @return stored Tag, null if empty + */ + public E getElement() { + return element; + } - /** - * @return path inside full tree to get to this Branch - */ - public String getPath() { - return path; - } + /** + * @return path inside full tree to get to this Branch + */ + public String getPath() { + return path; + } } diff --git a/devTools/javaSanityCheck/src/UnknownStateException.java b/devTools/javaSanityCheck/src/UnknownStateException.java index 80dbe598682d23875efe5517170f4f1c91a96246..77c91e73e10567e49514d3dd75970c2c041f7d1a 100644 --- a/devTools/javaSanityCheck/src/UnknownStateException.java +++ b/devTools/javaSanityCheck/src/UnknownStateException.java @@ -1,8 +1,11 @@ package org.arkerthan.sanityCheck; +/** + * @author Arkerthan + */ public class UnknownStateException extends RuntimeException { - public UnknownStateException(int state) { - super(String.valueOf(state)); - } + public UnknownStateException(int state) { + super(String.valueOf(state)); + } } diff --git a/devTools/javaSanityCheck/src/element/AngleBracketElement.java b/devTools/javaSanityCheck/src/element/AngleBracketElement.java index e129ee20cf401a23d83e520474a4aaa5a1b69991..8db115bf04cfa958d2a4dc88878249253de1f80f 100644 --- a/devTools/javaSanityCheck/src/element/AngleBracketElement.java +++ b/devTools/javaSanityCheck/src/element/AngleBracketElement.java @@ -5,375 +5,376 @@ import org.arkerthan.sanityCheck.*; import java.util.Arrays; import java.util.List; +/** + * @author Arkerthan + */ public class AngleBracketElement extends Element { - private static final List<String> logicTags = Arrays.asList("if", "elseif", "else", "switch", "case", "default"); - private int state = 0; - /* - 0 - initial: < - TWINE - 1 - << - -1 - <</ - 2 - trying to complete twine tag: <<tag ???>> - -2 - trying to complete twine tag: <</tag>> - 3 - waiting for >> - -3 - expecting > from 3 - 4 - waiting for >> with KnownElement - -4 - expecting > from 4 - 5 - expecting >> - -5 - expecting > - 6 - expecting > with KnownElement opening; comparison? - -6 - expecting > with KnownElement closing + private static final List<String> logicTags = Arrays.asList("if", "elseif", "else", "switch", "case", "default"); + private int state = 0; + /* + 0 - initial: < + TWINE + 1 - << + -1 - <</ + 2 - trying to complete twine tag: <<tag ???>> + -2 - trying to complete twine tag: <</tag>> + 3 - waiting for >> + -3 - expecting > from 3 + 4 - waiting for >> with KnownElement + -4 - expecting > from 4 + 5 - expecting >> + -5 - expecting > + 6 - expecting > with KnownElement opening; comparison? + -6 - expecting > with KnownElement closing - HTML - -9 - </ - 10 - trying to complete HTML tag: <tag ???> + HTML + -9 - </ + 10 - trying to complete HTML tag: <tag ???> -10 - trying to complete HTML tag: </tag> - 11 - waiting for > + 11 - waiting for > -11 - expecting > - 12 - waiting for > with KnownElement - */ + 12 - waiting for > with KnownElement + */ - private TagSearchTree<Tag> tree; + private TagSearchTree<Tag> tree; - public AngleBracketElement(int line, int pos) { - super(line, pos); - } + public AngleBracketElement(int line, int pos) { + super(line, pos); + } - @Override - public int handleChar(char c) throws SyntaxError { - switch (state) { - case 0: - switch (c) { - case '<': - state = 1; - return 1; - case '>': - throw new SyntaxError("Empty Statement?", 2); - case '/': - state = -9; - return 1; - case ' ':// assume comparison - case '=':// " - return 2; - case '3'://a heart: <3 - return 2; - default: - try { - state = 10; - tree = Main.htmlTags; - return handleOpeningHTML(c); - } catch (SyntaxError e) { - state = 1; - throw new SyntaxError("Opening \"<\" missing, found " + c, 1); - } - } - case 1: - if (c == '<') { - throw new SyntaxError("Too many \"<\".", 1); - } else if (c == '>') { - state = 3; - throw new SyntaxError("Empty Statement?", 1); - } else if (c == '/') { - state = -1; - return 1; - } - state = 2; - tree = Main.twineTags; - return handleOpeningTwine(c); - case -1: - if (c == '>') { - throw new SyntaxError("Empty Statement?", 2, true); - } - state = -2; - tree = Main.twineTags; - return handleClosingTwine(c); + @Override + public int handleChar(char c) throws SyntaxError { + switch (state) { + case 0: + switch (c) { + case '<': + state = 1; + return 1; + case '/': + state = -9; + return 1; + case '>':// empty <> + case ' ':// assume comparison + case '=':// " " + case '3':// a heart: <3 + return 2; + default: + try { + state = 10; + tree = Main.htmlTags; + return handleOpeningHTML(c); + } catch (SyntaxError e) { + state = 1; + throw new SyntaxError("Opening \"<\" missing, found " + c, 1); + } + } + case 1: + if (c == '<') { + throw new SyntaxError("Too many \"<\".", 1); + } else if (c == '>') { + state = 3; + throw new SyntaxError("Empty Statement?", 1); + } else if (c == '/') { + state = -1; + return 1; + } + state = 2; + tree = Main.twineTags; + return handleOpeningTwine(c); + case -1: + if (c == '>') { + throw new SyntaxError("Empty Statement?", 2, true); + } + state = -2; + tree = Main.twineTags; + return handleClosingTwine(c); - case 2: - return handleOpeningTwine(c); - case -2: - return handleClosingTwine(c); - case 3: - if (c == '>') { - state = -3; - return 1; - } - break; - case -3: - if (c == '>') { - return 2; - } else if (c == ' ' || c == '=') { // assuming comparison - state = 3; - return 1; - } else { - throw new SyntaxError("Closing \">\" missing, opened tag at [" + line + ":" + pos + "]", 2); - } - case 4: - if (c == '>') { - state = -4; - return 1; - } - break; - case -4: - if (c == '>') { - return 3; - } else if (c == ' ' || c == '=') { // assuming comparison - state = 4; - return 1; - } else { - throw new SyntaxError("Closing \">\" missing, opened tag at[" + line + ":" + pos + "]", 2); - } - case 5: - if (c == '>') { - state = -5; - return 1; - } else { - throw new SyntaxError("Closing \">\" missing, opened tag at [" + line + ":" + pos + "]", 2); - } - case -5: - if (c == '>') { - return 2; - } - throw new SyntaxError("Closing \">\" missing, opened tag at [" + line + ":" + pos + "]", 2); - case 6: - if (c == '>') { - return 3; - } else if (c == ' ' || c == '=') { - state = 3; - return 1; - } else { - throw new SyntaxError("Closing \">\" missing, opened tag at [" + line + ":" + pos + "]", 3); - } - case -6: - if (c == '>') { - return 3; - } - throw new SyntaxError("Closing \">\" missing, opened tag at [" + line + ":" + pos + "]", 3); + case 2: + return handleOpeningTwine(c); + case -2: + return handleClosingTwine(c); + case 3: + if (c == '>') { + state = -3; + return 1; + } + break; + case -3: + if (c == '>') { + return 2; + } else if (c == ' ' || c == '=') { // assuming comparison + state = 3; + return 1; + } else { + throw new SyntaxError("Closing \">\" missing, opened tag at [" + line + ":" + pos + "]", 2); + } + case 4: + if (c == '>') { + state = -4; + return 1; + } + break; + case -4: + if (c == '>') { + return 3; + } else if (c == ' ' || c == '=') { // assuming comparison + state = 4; + return 1; + } else { + throw new SyntaxError("Closing \">\" missing, opened tag at[" + line + ":" + pos + "]", 2); + } + case 5: + if (c == '>') { + state = -5; + return 1; + } else { + throw new SyntaxError("Closing \">\" missing, opened tag at [" + line + ":" + pos + "]", 2); + } + case -5: + if (c == '>') { + return 2; + } + throw new SyntaxError("Closing \">\" missing, opened tag at [" + line + ":" + pos + "]", 2); + case 6: + if (c == '>') { + return 3; + } else if (c == ' ' || c == '=') { + state = 3; + return 1; + } else { + throw new SyntaxError("Closing \">\" missing, opened tag at [" + line + ":" + pos + "]", 3); + } + case -6: + if (c == '>') { + return 3; + } + throw new SyntaxError("Closing \">\" missing, opened tag at [" + line + ":" + pos + "]", 3); - case -9: - if (c == '>') { - throw new SyntaxError("Empty Statement?", 2, true); - } - state = -10; - tree = Main.htmlTags; - return handleClosingHTML(c); - case 10: - return handleOpeningHTML(c); - case -10: - return handleClosingHTML(c); - case 11: - if (c == '>') - return 2; - if (c == '@') //@ inside HTML tags is allowed - return 1; - break; - case -11: - if (c == '>') - return 2; - throw new SyntaxError("Closing \">\" missing [2]", 2); - case 12: - if (c == '>') - return 3; - if (c == '@') //@ inside HTML tags is allowed - return 1; - break; - default: - throw new UnknownStateException(state); - } - return 0; - } + case -9: + if (c == '>') { + throw new SyntaxError("Empty Statement?", 2, true); + } + state = -10; + tree = Main.htmlTags; + return handleClosingHTML(c); + case 10: + return handleOpeningHTML(c); + case -10: + return handleClosingHTML(c); + case 11: + if (c == '>') + return 2; + if (c == '@') //@ inside HTML tags is allowed + return 1; + break; + case -11: + if (c == '>') + return 2; + throw new SyntaxError("Closing \">\" missing [2]", 2); + case 12: + if (c == '>') + return 3; + if (c == '@') //@ inside HTML tags is allowed + return 1; + break; + default: + throw new UnknownStateException(state); + } + return 0; + } - private int handleOpeningHTML(char c) throws SyntaxError { - if (c == ' ') { - state = 11; - if (tree.getElement() == null) { - throw new SyntaxError("Unknown HTML tag", 1); - } - if (!tree.getElement().single) { - k = new KnownHtmlElement(line, pos, true, tree.getElement().tag); - state = 12; - return 1; - } - return 1; - } - if (c == '>') { - if (tree.getElement() == null) { - throw new SyntaxError("Unknown HTML tag", 2); - } - if (!tree.getElement().single) { - k = new KnownHtmlElement(line, pos, true, tree.getElement().tag); - return 3; - } - return 2; - } + private int handleOpeningHTML(char c) throws SyntaxError { + if (c == ' ') { + state = 11; + if (tree.getElement() == null) { + throw new SyntaxError("Unknown HTML tag", 1); + } + if (!tree.getElement().single) { + k = new KnownHtmlElement(line, pos, true, tree.getElement().tag); + state = 12; + return 1; + } + return 1; + } + if (c == '>') { + if (tree.getElement() == null) { + throw new SyntaxError("Unknown HTML tag", 2); + } + if (!tree.getElement().single) { + k = new KnownHtmlElement(line, pos, true, tree.getElement().tag); + return 3; + } + return 2; + } - tree = tree.getBranch(c); - if (tree == null) { - state = 11; - throw new SyntaxError("Unknown HTML tag or closing \">\" missing, found " + c, 1); - } + tree = tree.getBranch(c); + if (tree == null) { + state = 11; + throw new SyntaxError("Unknown HTML tag or closing \">\" missing, found " + c, 1); + } - return 1; - } + return 1; + } - private int handleClosingHTML(char c) throws SyntaxError { - if (c == '>') { - if (tree.getElement() == null) { - throw new SyntaxError("Unknown HTML tag: " + tree.getPath(), 2); - } - if (tree.getElement().single) { - throw new SyntaxError("Single HTML tag used as closing Tag: " + tree.getElement().tag, 2); - } - k = new KnownHtmlElement(line, pos, false, tree.getElement().tag); - return 3; - } + private int handleClosingHTML(char c) throws SyntaxError { + if (c == '>') { + if (tree.getElement() == null) { + throw new SyntaxError("Unknown HTML tag: " + tree.getPath(), 2); + } + if (tree.getElement().single) { + throw new SyntaxError("Single HTML tag used as closing Tag: " + tree.getElement().tag, 2); + } + k = new KnownHtmlElement(line, pos, false, tree.getElement().tag); + return 3; + } - tree = tree.getBranch(c); - if (tree == null) { - state = -11; - throw new SyntaxError("Unknown HTML tag or closing \">\" missing, found " + c, 1); - } + tree = tree.getBranch(c); + if (tree == null) { + state = -11; + throw new SyntaxError("Unknown HTML tag or closing \">\" missing, found " + c, 1); + } - return 1; - } + return 1; + } - private int handleOpeningTwine(char c) throws SyntaxError { - if (c == ' ') { - state = 3; - if (tree.getElement() == null) { - //assuming not listed means widget until better solution - return 1; - } - if (!tree.getElement().single) { - if (logicTags.contains(tree.getElement().tag)) { - k = new KnownLogicElement(line, pos, tree.getElement().tag, false); - } else { - k = new KnownTwineElement(line, pos, true, tree.getElement().tag); - } - state = 4; - return 1; - } - return 1; - } - if (c == '>') { - state = -5; - if (tree.getElement() == null) { - //assuming not listed means widget until better solution - return 1; - } - if (!tree.getElement().single) { - if (logicTags.contains(tree.getElement().tag)) { - k = new KnownLogicElement(line, pos, tree.getElement().tag, false); - } else { - k = new KnownTwineElement(line, pos, true, tree.getElement().tag); - } - state = 6; - return 1; - } - return 2; - } + private int handleOpeningTwine(char c) throws SyntaxError { + if (c == ' ') { + state = 3; + if (tree.getElement() == null) { + //assuming not listed means widget until better solution + return 1; + } + if (!tree.getElement().single) { + if (logicTags.contains(tree.getElement().tag)) { + k = new KnownLogicElement(line, pos, tree.getElement().tag, false); + } else { + k = new KnownTwineElement(line, pos, true, tree.getElement().tag); + } + state = 4; + return 1; + } + return 1; + } + if (c == '>') { + state = -5; + if (tree.getElement() == null) { + //assuming not listed means widget until better solution + return 1; + } + if (!tree.getElement().single) { + if (logicTags.contains(tree.getElement().tag)) { + k = new KnownLogicElement(line, pos, tree.getElement().tag, false); + } else { + k = new KnownTwineElement(line, pos, true, tree.getElement().tag); + } + state = 6; + return 1; + } + return 2; + } - tree = tree.getBranch(c); - if (tree == null) { - //assuming not listed means widget until better solution - state = 3; - } + tree = tree.getBranch(c); + if (tree == null) { + //assuming not listed means widget until better solution + state = 3; + } - return 1; - } + return 1; + } - private int handleClosingTwine(char c) throws SyntaxError { - if (c == '>') { - if (tree.getElement() == null) { - throw new SyntaxError("Unknown Twine tag: " + tree.getPath(), 2); - } - if (tree.getElement().single) { - throw new SyntaxError("Single Twine tag used as closing Tag: " + tree.getElement().tag, 2); - } - if (logicTags.contains(tree.getElement().tag)) { - k = new KnownLogicElement(line, pos, tree.getElement().tag, true); - } else { - k = new KnownTwineElement(line, pos, false, tree.getElement().tag); - } - state = -6; - return 1; - } + private int handleClosingTwine(char c) throws SyntaxError { + if (c == '>') { + if (tree.getElement() == null) { + throw new SyntaxError("Unknown Twine tag: " + tree.getPath(), 2); + } + if (tree.getElement().single) { + throw new SyntaxError("Single Twine tag used as closing Tag: " + tree.getElement().tag, 2); + } + if (logicTags.contains(tree.getElement().tag)) { + k = new KnownLogicElement(line, pos, tree.getElement().tag, true); + } else { + k = new KnownTwineElement(line, pos, false, tree.getElement().tag); + } + state = -6; + return 1; + } - tree = tree.getBranch(c); - if (tree == null) { - state = 3; - throw new SyntaxError("Unknown Twine closing tag or closing \">>\" missing, found " + c, 1); - } + tree = tree.getBranch(c); + if (tree == null) { + state = 3; + throw new SyntaxError("Unknown Twine closing tag or closing \">>\" missing, found " + c, 1); + } - return 1; - } + return 1; + } - @Override - public String getShortDescription() { - StringBuilder builder = new StringBuilder(); - builder.append('[').append(line).append(":").append(pos).append("] "); - switch (state) { - case 0: - builder.append("<"); - break; - //TWINE - case 1: - builder.append("<<"); - break; - case -1: - builder.append("<</"); - break; - case 2: - builder.append("<<").append(tree.getPath()); - break; - case -2: - builder.append("<</").append(tree.getPath()); - break; - case 3: - builder.append("<<???"); - break; - case -3: - builder.append("<<???>"); - break; - case 4: - builder.append("<<").append(tree.getPath()).append(" ???"); - break; - case -4: - builder.append("<<").append(tree.getPath()).append(" ???>"); - break; - case 5: - builder.append("<<???"); - break; - case -5: - builder.append("<<").append(tree == null ? "???" : tree.getPath()).append(">"); - break; - case 6: - builder.append("<<").append(tree.getPath()).append(" ???>"); - break; - case -6: - builder.append("<</").append(tree.getPath()).append(">"); - break; - //HTML - case -9: - builder.append("</"); - break; - case 10: - builder.append("<").append(tree.getPath()); - break; - case -10: - builder.append("</").append(tree.getPath()); - break; - case 11: - builder.append("<?").append(tree == null ? "???" : tree.getPath()); - break; - case -11: - builder.append("</").append(tree == null ? "???" : tree.getPath()); - break; - case 12: - builder.append("<").append(tree.getPath()).append(" ???"); - default: - throw new UnknownStateException(state); - } - return builder.toString(); - } + @Override + public String getShortDescription() { + StringBuilder builder = new StringBuilder(); + builder.append(getPositionAsString()).append(" "); + switch (state) { + case 0: + builder.append("<"); + break; + //TWINE + case 1: + builder.append("<<"); + break; + case -1: + builder.append("<</"); + break; + case 2: + builder.append("<<").append(tree.getPath()); + break; + case -2: + builder.append("<</").append(tree.getPath()); + break; + case 3: + builder.append("<<???"); + break; + case -3: + builder.append("<<???>"); + break; + case 4: + builder.append("<<").append(tree.getPath()).append(" ???"); + break; + case -4: + builder.append("<<").append(tree.getPath()).append(" ???>"); + break; + case 5: + builder.append("<<???"); + break; + case -5: + builder.append("<<").append(tree == null ? "???" : tree.getPath()).append(">"); + break; + case 6: + builder.append("<<").append(tree.getPath()).append(" ???>"); + break; + case -6: + builder.append("<</").append(tree.getPath()).append(">"); + break; + //HTML + case -9: + builder.append("</"); + break; + case 10: + builder.append("<").append(tree.getPath()); + break; + case -10: + builder.append("</").append(tree.getPath()); + break; + case 11: + builder.append("<?").append(tree == null ? "???" : tree.getPath()); + break; + case -11: + builder.append("</").append(tree == null ? "???" : tree.getPath()); + break; + case 12: + builder.append("<").append(tree.getPath()).append(" ???"); + default: + throw new UnknownStateException(state); + } + return builder.toString(); + } } diff --git a/devTools/javaSanityCheck/src/element/AtElement.java b/devTools/javaSanityCheck/src/element/AtElement.java index 168e340a4326b24c0dff912c64d25ec5042d6fe5..598dad63eea9d7aea1c8058c89a2584c752afee1 100644 --- a/devTools/javaSanityCheck/src/element/AtElement.java +++ b/devTools/javaSanityCheck/src/element/AtElement.java @@ -3,103 +3,106 @@ package org.arkerthan.sanityCheck.element; import org.arkerthan.sanityCheck.SyntaxError; import org.arkerthan.sanityCheck.UnknownStateException; +/** + * @author Arkerthan + */ public class AtElement extends Element { - private int state = 0; - // 0 = @ - // 1 = @@ - // 2 = @@. - // 3 = @@.a -- @@.ab -- @@.abc - // 4 = @@.abc;abc - // 5 = @@.abc;abc@ + private int state = 0; + // 0 = @ + // 1 = @@ + // 2 = @@. + // 3 = @@.a -- @@.ab -- @@.abc + // 4 = @@.abc;abc + // 5 = @@.abc;abc@ - // example: @@.red;some text@@ + // example: @@.red;some text@@ - public AtElement(int line, int pos) { - super(line, pos); - } + public AtElement(int line, int pos) { + super(line, pos); + } - @Override - public int handleChar(char c) throws SyntaxError { - switch (state) { - case 0: - state = 1; - if (c == '@') { - return 1; - } else { - if (c == '.') { - state = 2; - } - throw new SyntaxError("Opening \"@\" missing.", 1); - } - case 1: - if (c == '.') { - state = 2; - return 1; - } else { - state = 4; - throw new SyntaxError("\".\" missing, found \"" + c + "\". This might also indicate a " + - "missing closure in the previous color code.", 0, true); - } - case 2: - state = 3; - if (Character.isAlphabetic(c)) { - return 1; - } else { - throw new SyntaxError("Identifier might be wrong.", 1, true); - } - case 3: - if (c == ';') { - state = 4; - return 1; - } else if (c == ' ') { - state = 4; - throw new SyntaxError("\";\" missing or wrong space.", 1); - } - break; - case 4: - if (c == '@') { - state = 5; - return 1; - } - break; - case 5: - if (c == '@') { - return 2; - } else { - throw new SyntaxError("Closing \"@\" missing.", 2); - } - default: - throw new UnknownStateException(state); - } - return 0; - } + @Override + public int handleChar(char c) throws SyntaxError { + switch (state) { + case 0: + state = 1; + if (c == '@') { + return 1; + } else { + if (c == '.') { + state = 2; + } + throw new SyntaxError("Opening \"@\" missing.", 1); + } + case 1: + if (c == '.') { + state = 2; + return 1; + } else { + state = 4; + throw new SyntaxError("\".\" missing, found \"" + c + "\". This might also indicate a " + + "missing closure in the previous color code.", 0, true); + } + case 2: + state = 3; + if (Character.isAlphabetic(c)) { + return 1; + } else { + throw new SyntaxError("Identifier might be wrong.", 1, true); + } + case 3: + if (c == ';') { + state = 4; + return 1; + } else if (c == ' ') { + state = 4; + throw new SyntaxError("\";\" missing or wrong space.", 1); + } + break; + case 4: + if (c == '@') { + state = 5; + return 1; + } + break; + case 5: + if (c == '@') { + return 2; + } else { + throw new SyntaxError("Closing \"@\" missing.", 2); + } + default: + throw new UnknownStateException(state); + } + return 0; + } - @Override - public String getShortDescription() { - StringBuilder builder = new StringBuilder(); - builder.append(line).append(":").append(pos).append(" "); - switch (state) { - case 0: - builder.append("@"); - break; - case 1: - builder.append("@@"); - break; - case 2: - builder.append("@@."); - break; - case 3: - builder.append("@@.???"); - break; - case 4: - builder.append("@@???"); - break; - case 5: - builder.append("@@???@"); - break; - default: - throw new UnknownStateException(state); - } - return builder.toString(); - } + @Override + public String getShortDescription() { + StringBuilder builder = new StringBuilder(); + builder.append(getPositionAsString()).append(" "); + switch (state) { + case 0: + builder.append("@"); + break; + case 1: + builder.append("@@"); + break; + case 2: + builder.append("@@."); + break; + case 3: + builder.append("@@.???"); + break; + case 4: + builder.append("@@???"); + break; + case 5: + builder.append("@@???@"); + break; + default: + throw new UnknownStateException(state); + } + return builder.toString(); + } } diff --git a/devTools/javaSanityCheck/src/element/BracketElement.java b/devTools/javaSanityCheck/src/element/BracketElement.java new file mode 100644 index 0000000000000000000000000000000000000000..b9848941653e6cb3715e60ac7342a1d087e0ebba --- /dev/null +++ b/devTools/javaSanityCheck/src/element/BracketElement.java @@ -0,0 +1,28 @@ +package org.arkerthan.sanityCheck.element; + +import org.arkerthan.sanityCheck.SyntaxError; + +/** + * @author Arkerthan + */ +public class BracketElement extends Element { + //int state = 0; + + public BracketElement(int line, int pos) { + super(line, pos); + } + + @Override + public int handleChar(char c) throws SyntaxError { + if (c == ')') { + return 2; + } else { + return 0; + } + } + + @Override + public String getShortDescription() { + return getPositionAsString() + " (???"; + } +} diff --git a/devTools/javaSanityCheck/src/element/CommentElement.java b/devTools/javaSanityCheck/src/element/CommentElement.java index 0ae0908201c914db2284087e89079760d42ae245..a03c929a2114615e8f243a7887b02ecb386b52ad 100644 --- a/devTools/javaSanityCheck/src/element/CommentElement.java +++ b/devTools/javaSanityCheck/src/element/CommentElement.java @@ -3,68 +3,73 @@ package org.arkerthan.sanityCheck.element; import org.arkerthan.sanityCheck.SyntaxError; import org.arkerthan.sanityCheck.UnknownStateException; +/** + * @author Arkerthan + */ public class CommentElement extends Element { - private int state = 0; - /* - 0 - / - 1 - /*??? - 2 - /*???* - 3 - /%??? - 4 - /%???% - */ + private int state = 0; + /* + 0 - / + 1 - /*??? + 2 - /*???* + 3 - /%??? + 4 - /%???% + */ - /** - * @param line line in which comment starts - * @param pos position in line where comment starts - */ - public CommentElement(int line, int pos) { - super(line, pos); - } + /** + * @param line line in which comment starts + * @param pos position in line where comment starts + */ + public CommentElement(int line, int pos) { + super(line, pos); + } - @Override - public int handleChar(char c) throws SyntaxError { - switch (state) { - case 0: - if (c == '*') { - state = 1; - } else if (c == '%') { - state = 3; - } else if (c == '>') { - throw new SyntaxError("XHTML style closure", 4, true); - } else { - return 4; - } - break; - case 1: - if (c == '*') { - state = 2; - } - break; - case 2: - if (c == '/') { - return 2; - } - state = 1; - break; - case 3: - if (c == '%') { - state = 4; - } - break; - case 4: - if (c == '/') { - return 2; - } - state = 3; - break; - default: - throw new UnknownStateException(state); - } - return 1; - } + @Override + public int handleChar(char c) throws SyntaxError { + switch (state) { + case 0: + if (c == '*') { + state = 1; + } else if (c == '%') { + state = 3; + } else if (c == '>') { + throw new SyntaxError("XHTML style closure", 4, true); + } else { + return 4; + } + break; + case 1: + if (c == '*') { + state = 2; + } + break; + case 2: + if (c == '/') { + return 2; + } else if (c == '*') { + return 1; + } + state = 1; + break; + case 3: + if (c == '%') { + state = 4; + } + break; + case 4: + if (c == '/') { + return 2; + } + state = 3; + break; + default: + throw new UnknownStateException(state); + } + return 1; + } - @Override - public String getShortDescription() { - return null; - } + @Override + public String getShortDescription() { + return getPositionAsString() + "comment"; + } } diff --git a/devTools/javaSanityCheck/src/element/Element.java b/devTools/javaSanityCheck/src/element/Element.java index d0e1bf7cd1210b08f1f888103278cd66ad1a218d..02400f2a5319b99aee1f19216ff401b3121e46aa 100644 --- a/devTools/javaSanityCheck/src/element/Element.java +++ b/devTools/javaSanityCheck/src/element/Element.java @@ -2,42 +2,54 @@ package org.arkerthan.sanityCheck.element; import org.arkerthan.sanityCheck.SyntaxError; +/** + * @author Arkerthan + */ public abstract class Element { - protected KnownElement k; - protected int line, pos; + protected KnownElement k; + protected int line, pos; - /** - * @param line Line the instance was created - * @param pos Position in line the instance was created - */ - protected Element(int line, int pos) { - this.line = line; - this.pos = pos; - } + /** + * @param line Line the instance was created + * @param pos Position in line the instance was created + */ + protected Element(int line, int pos) { + this.line = line; + this.pos = pos; + } - /** - * Parses a Char and returns an int depending on the state of the element - * 0 - the Element did nothing - * 1 - the Element changed state - * 2 - the Element is finished - * 3 - the Element is finished and a KnownHtmlElement was generated - * 4 - the Element is finished and the char is still open for use - * - * @param c char to be parsed - * @return state change - * @throws SyntaxError thrown when an syntax error is detected - */ - public abstract int handleChar(char c) throws SyntaxError; + /** + * Parses a Char and returns an int depending on the state of the element + * 0 - the Element did nothing + * 1 - the Element changed state + * 2 - the Element is finished + * 3 - the Element is finished and a KnownHtmlElement was generated + * 4 - the Element is finished and the char is still open for use + * + * @param c char to be parsed + * @return state change + * @throws SyntaxError thrown when an syntax error is detected + */ + public abstract int handleChar(char c) throws SyntaxError; - /** - * @return the constructed KnownElement. null if none was constructed yet. - */ - public KnownElement getKnownElement() { - return k; - } + /** + * @return the constructed KnownElement. null if none was constructed yet. + */ + public KnownElement getKnownElement() { + return k; + } - /** - * @return a short description usually based on state and position of the Element - */ - public abstract String getShortDescription(); + /** + * Returns the line and position of the Element in the file it was created in. + * + * @return position of Element in file as String + */ + public String getPositionAsString() { + return "[" + line + ":" + pos + "]"; + } + + /** + * @return a short description usually based on state and position of the Element + */ + public abstract String getShortDescription(); } diff --git a/devTools/javaSanityCheck/src/element/KnownElement.java b/devTools/javaSanityCheck/src/element/KnownElement.java index d09a5a7a5cc7279bda7cc03a0a674b1243217847..9b64eb18a877527e76b336fc602312df8d984e43 100644 --- a/devTools/javaSanityCheck/src/element/KnownElement.java +++ b/devTools/javaSanityCheck/src/element/KnownElement.java @@ -2,34 +2,37 @@ package org.arkerthan.sanityCheck.element; import org.arkerthan.sanityCheck.SyntaxError; +/** + * @author Arkerthan + */ public abstract class KnownElement extends Element { - /** - * @param line at which it begins - * @param pos at which it begins - */ - public KnownElement(int line, int pos) { - super(line, pos); - } + /** + * @param line at which it begins + * @param pos at which it begins + */ + public KnownElement(int line, int pos) { + super(line, pos); + } - /** - * @return true, if it needs another Known Element to close it. - */ - public abstract boolean isOpening(); + /** + * @return true, if it needs another Known Element to close it. + */ + public abstract boolean isOpening(); - /** - * @return true if it closes another Element. - */ - public abstract boolean isClosing(); + /** + * @return true if it closes another Element. + */ + public abstract boolean isClosing(); - /** - * @param k Element to be checked - * @return true if given Element closes Element - */ - public abstract boolean isMatchingElement(KnownElement k); + /** + * @param k Element to be checked + * @return true if given Element closes Element + */ + public abstract boolean isMatchingElement(KnownElement k); - @Override - public int handleChar(char c) throws SyntaxError { - return 0; - } + @Override + public int handleChar(char c) throws SyntaxError { + return 0; + } } diff --git a/devTools/javaSanityCheck/src/element/KnownHtmlElement.java b/devTools/javaSanityCheck/src/element/KnownHtmlElement.java index 8ae21e1a402d3fd8c3a8a5010c03527aab2c9a3c..6edaa6723ba4d8ec68e0d549da56e7494dc20918 100644 --- a/devTools/javaSanityCheck/src/element/KnownHtmlElement.java +++ b/devTools/javaSanityCheck/src/element/KnownHtmlElement.java @@ -1,47 +1,50 @@ package org.arkerthan.sanityCheck.element; +/** + * @author Arkerthan + */ public class KnownHtmlElement extends KnownElement { - private boolean opening; - private String statement; + private boolean opening; + private String statement; - /** - * @param line at which it begins - * @param pos at which it begins - * @param opening if it opens a tag: <tag> or closes it: </tag> - * @param statement statement inside the tag - */ - public KnownHtmlElement(int line, int pos, boolean opening, String statement) { - super(line, pos); - this.opening = opening; - this.statement = statement; - } + /** + * @param line at which it begins + * @param pos at which it begins + * @param opening if it opens a tag: <tag> or closes it: </tag> + * @param statement statement inside the tag + */ + public KnownHtmlElement(int line, int pos, boolean opening, String statement) { + super(line, pos); + this.opening = opening; + this.statement = statement; + } - @Override - public String getShortDescription() { - StringBuilder builder = new StringBuilder(); - builder.append('[').append(line).append(":").append(pos).append("] <"); - if (!opening) { - builder.append("/"); - } - return builder.append(statement).append(">").toString(); - } + @Override + public String getShortDescription() { + StringBuilder builder = new StringBuilder(); + builder.append(getPositionAsString()).append(" <"); + if (!opening) { + builder.append("/"); + } + return builder.append(statement).append(">").toString(); + } - @Override - public boolean isOpening() { - return opening; - } + @Override + public boolean isOpening() { + return opening; + } - @Override - public boolean isClosing() { - return !opening; - } + @Override + public boolean isClosing() { + return !opening; + } - @Override - public boolean isMatchingElement(KnownElement k) { - if (k instanceof KnownHtmlElement) { - return ((KnownHtmlElement) k).statement.equals(this.statement); - } - return false; - } + @Override + public boolean isMatchingElement(KnownElement k) { + if (k instanceof KnownHtmlElement) { + return ((KnownHtmlElement) k).statement.equals(this.statement); + } + return false; + } } diff --git a/devTools/javaSanityCheck/src/element/KnownLogicElement.java b/devTools/javaSanityCheck/src/element/KnownLogicElement.java index 994201c5a9ba40a4aea01252bb0ba6765a5841b7..e887b2989362daf737204d8c378c8efe6c778ecf 100644 --- a/devTools/javaSanityCheck/src/element/KnownLogicElement.java +++ b/devTools/javaSanityCheck/src/element/KnownLogicElement.java @@ -6,112 +6,115 @@ import org.arkerthan.sanityCheck.UnknownStateException; import java.util.Arrays; import java.util.List; +/** + * @author Arkerthan + */ public class KnownLogicElement extends KnownElement { - private static final List<String> allowedTags = Arrays.asList("if", "elseif", "else"); - private final int state; - private boolean last; - /* - 0 - if - 1 - elseif - 2 - else - 3 - switch - 4 - case - 5 - default - */ + private static final List<String> allowedTags = Arrays.asList("if", "elseif", "else"); + private final int state; + private boolean last; + /* + 0 - if + 1 - elseif + 2 - else + 3 - switch + 4 - case + 5 - default + */ - public KnownLogicElement(int line, int pos, String tag, boolean last) { - this(line, pos, tag); - this.last = last; - } + public KnownLogicElement(int line, int pos, String tag, boolean last) { + this(line, pos, tag); + this.last = last; + } - public KnownLogicElement(int line, int pos, String tag) { - super(line, pos); - switch (tag) { - case "if": - state = 0; - break; - case "elseif": - state = 1; - break; - case "else": - state = 2; - break; - case "switch": - state = 3; - break; - case "case": - state = 4; - break; - case "default": - state = 5; - break; - default: - throw new DisallowedTagException(tag); - } - last = false; - } + public KnownLogicElement(int line, int pos, String tag) { + super(line, pos); + switch (tag) { + case "if": + state = 0; + break; + case "elseif": + state = 1; + break; + case "else": + state = 2; + break; + case "switch": + state = 3; + break; + case "case": + state = 4; + break; + case "default": + state = 5; + break; + default: + throw new DisallowedTagException(tag); + } + last = false; + } - @Override - public boolean isOpening() { - return !last; - } + @Override + public boolean isOpening() { + return !last; + } - @Override - public boolean isClosing() { - return (state != 0 && state != 3) || last; - } + @Override + public boolean isClosing() { + return (state != 0 && state != 3) || last; + } - @Override - public boolean isMatchingElement(KnownElement k) { - if (!(k instanceof KnownLogicElement)) { - return false; - } - KnownLogicElement l = (KnownLogicElement) k; - switch (state) { - case 0: - case 1: - return l.state == 1 || l.state == 2 || (l.state == 0 && l.last); - case 2: - return l.state == 0 && l.last; - case 3: - case 4: - return l.state == 3 || l.state == 4; - case 5: - return l.state == 3 && l.last; - default: - throw new UnknownStateException(state); - } - } + @Override + public boolean isMatchingElement(KnownElement k) { + if (!(k instanceof KnownLogicElement)) { + return false; + } + KnownLogicElement l = (KnownLogicElement) k; + switch (state) { + case 0: + case 1: + return l.state == 1 || l.state == 2 || (l.state == 0 && l.last); + case 2: + return l.state == 0 && l.last; + case 3: + case 4: + return l.state == 3 || l.state == 4; + case 5: + return l.state == 3 && l.last; + default: + throw new UnknownStateException(state); + } + } - @Override - public String getShortDescription() { - StringBuilder builder = new StringBuilder(); - builder.append("[").append(line).append(":").append(pos).append("] <<"); - if (last) { - builder.append('/'); - } - switch (state) { - case 0: - builder.append("if"); - break; - case 1: - builder.append("elseif"); - break; - case 2: - builder.append("else"); - break; - case 3: - builder.append("switch"); - break; - case 4: - builder.append("case"); - break; - case 5: - builder.append("default"); - break; - default: - throw new UnknownStateException(state); - } - return builder.append(">>").toString(); - } + @Override + public String getShortDescription() { + StringBuilder builder = new StringBuilder(); + builder.append(getPositionAsString()).append(" <<"); + if (last) { + builder.append('/'); + } + switch (state) { + case 0: + builder.append("if"); + break; + case 1: + builder.append("elseif"); + break; + case 2: + builder.append("else"); + break; + case 3: + builder.append("switch"); + break; + case 4: + builder.append("case"); + break; + case 5: + builder.append("default"); + break; + default: + throw new UnknownStateException(state); + } + return builder.append(">>").toString(); + } } diff --git a/devTools/javaSanityCheck/src/element/KnownTwineElement.java b/devTools/javaSanityCheck/src/element/KnownTwineElement.java index 4bd78b2d585d014186d7ded56d804352e8e5d8db..020aad7819fecac96bac7ac0f8da906d79d32321 100644 --- a/devTools/javaSanityCheck/src/element/KnownTwineElement.java +++ b/devTools/javaSanityCheck/src/element/KnownTwineElement.java @@ -1,48 +1,50 @@ package org.arkerthan.sanityCheck.element; +/** + * @author Arkerthan + */ public class KnownTwineElement extends KnownElement { - private boolean opening; - private String statement; + private boolean opening; + private String statement; - /** - * - * @param line at which it begins - * @param pos at which it begins - * @param opening if it opens a tag: <<tag>> or closes it: <</tag>> - * @param statement statement inside the tag - */ - public KnownTwineElement(int line, int pos, boolean opening, String statement) { - super(line, pos); - this.opening = opening; - this.statement = statement; - } + /** + * @param line at which it begins + * @param pos at which it begins + * @param opening if it opens a tag: <<tag>> or closes it: <</tag>> + * @param statement statement inside the tag + */ + public KnownTwineElement(int line, int pos, boolean opening, String statement) { + super(line, pos); + this.opening = opening; + this.statement = statement; + } - @Override - public String getShortDescription() { - StringBuilder builder = new StringBuilder(); - builder.append("[").append(line).append(":").append(pos).append("] <<"); - if (!opening) { - builder.append("/"); - } - return builder.append(statement).append(">>").toString(); - } + @Override + public String getShortDescription() { + StringBuilder builder = new StringBuilder(); + builder.append(getPositionAsString()).append(" <<"); + if (!opening) { + builder.append("/"); + } + return builder.append(statement).append(">>").toString(); + } - @Override - public boolean isOpening() { - return opening; - } + @Override + public boolean isOpening() { + return opening; + } - @Override - public boolean isClosing() { - return !opening; - } + @Override + public boolean isClosing() { + return !opening; + } - @Override - public boolean isMatchingElement(KnownElement k) { - if (k instanceof KnownTwineElement) { - return ((KnownTwineElement) k).statement.equals(this.statement); - } - return false; - } + @Override + public boolean isMatchingElement(KnownElement k) { + if (k instanceof KnownTwineElement) { + return ((KnownTwineElement) k).statement.equals(this.statement); + } + return false; + } } diff --git a/java+gitGrep-sanityCheck.sh b/java+gitGrep-sanityCheck.sh index 02e5e0853125872d38d548a37361eedd16fca35d..b46d4dd1c320dc803f254fd4816944efc01d3c9f 100755 --- a/java+gitGrep-sanityCheck.sh +++ b/java+gitGrep-sanityCheck.sh @@ -59,7 +59,7 @@ $GREP "\$slaves\[\$i\]\. " -- 'src/*' | myprint "MissingPropertyAfterSlaves" # Check using refreshmentType instead of refreshment $GREP "\$PC.refreshmentType[^ =]" -- 'src/*' | myprint "ShouldBeRefreshment" # Check, e.g., <<//if>> -$GREP "<</[a-zA-Z]*[^a-zA-Z<>]\+[a-zA-Z]*>>" -- 'src/*' | myprint "DoubleSlash" +#$GREP "<</[a-zA-Z]*[^a-zA-Z<>]\+[a-zA-Z]*>>" -- 'src/*' | myprint "DoubleSlash" # Check, e.g. <<else $foo==4 #$GREP "<<else >\?[^>]" -- 'src/*' | myprint "ShouldBeElseIf" # Check, e.g., =to diff --git a/sanityCheck b/sanityCheck index e8e842b19766a9b04452b30f317e5af78755a42f..98ca937510f9fc43700befb58eee0cfa16204515 100755 --- a/sanityCheck +++ b/sanityCheck @@ -99,6 +99,8 @@ $GREP -e "<<option " --and --not -e "<<option *\(-\?[0-9]\+\|[\'\"].*[\'\"]\|fa # check for missing ; before statement $GREP 'if $ ' -- 'src/*' | myprint "missing ; before statement" $GREP 'elseif $ ' -- 'src/*' | myprint "missing ; before statement" +# Check for an unrecognized letter before >> +$GREP "[^]a-zA-Z0-9 \")}'+-\*\`] *>>" -- 'src/*' | myprint "StrangeCharacterAtEndOfCommand" # Check for a . inside a <<>> $GREP "<<[a-zA-Z]\([^\"'>]\|[^\"'>]>[^\"'>]\)*[a-zA-Z][.][^a-zA-Z]" | myprint "StrangeCharacterAfterDot" # Check for @@. instead of .@@ diff --git a/src/SecExp/SecExpBackwardCompatibility.tw b/src/SecExp/SecExpBackwardCompatibility.tw index 1708368a8f1e4b921a17a88cd37abbc0a77688aa..8efeeb27226b8b128c52b13658afdbcbdf6d3741 100644 --- a/src/SecExp/SecExpBackwardCompatibility.tw +++ b/src/SecExp/SecExpBackwardCompatibility.tw @@ -433,20 +433,20 @@ defense: 0, hp:0}>> <<else>> - <<if isInt($droneUpgrades)>> + <<if Number.isInteger($droneUpgrades)>> <<unset $droneUpgrades>> <<set $droneUpgrades = { attack: 0, defense: 0, hp:0}>> <</if>> - <<if ndef $droneUpgrades.attack || !isInt($droneUpgrades.attack)>> + <<if ndef $droneUpgrades.attack || !Number.isInteger($droneUpgrades.attack)>> <<set $droneUpgrades.attack = 0>> <</if>> - <<if ndef $droneUpgrades.defense || !isInt($droneUpgrades.defense)>> + <<if ndef $droneUpgrades.defense || !Number.isInteger($droneUpgrades.defense)>> <<set $droneUpgrades.defense = 0>> <</if>> - <<if ndef $droneUpgrades.hp || !isInt($droneUpgrades.hp)>> + <<if ndef $droneUpgrades.hp || !Number.isInteger($droneUpgrades.hp)>> <<set $droneUpgrades.hp = 0>> <</if>> <</if>> @@ -463,7 +463,7 @@ hp:0, morale: 0}>> <<else>> - <<if isInt($humanUpgrade)>> + <<if Number.isInteger($humanUpgrade)>> <<unset $humanUpgrade>> <<set $humanUpgrade = { attack: 0, @@ -471,16 +471,16 @@ hp:0, morale: 0}>> <</if>> - <<if ndef $humanUpgrade.attack || !isInt($humanUpgrade.attack)>> + <<if ndef $humanUpgrade.attack || !Number.isInteger($humanUpgrade.attack)>> <<set $humanUpgrade.attack = 0>> <</if>> - <<if ndef $humanUpgrade.defense || !isInt($humanUpgrade.defense)>> + <<if ndef $humanUpgrade.defense || !Number.isInteger($humanUpgrade.defense)>> <<set $humanUpgrade.defense = 0>> <</if>> - <<if ndef $humanUpgrade.hp || !isInt($humanUpgrade.hp)>> + <<if ndef $humanUpgrade.hp || !Number.isInteger($humanUpgrade.hp)>> <<set $humanUpgrade.hp = 0>> <</if>> - <<if ndef $humanUpgrade.morale || !isInt($humanUpgrade.morale)>> + <<if ndef $humanUpgrade.morale || !Number.isInteger($humanUpgrade.morale)>> <<set $humanUpgrade.morale = 0>> <</if>> <</if>> diff --git a/src/SecExp/attackReport.tw b/src/SecExp/attackReport.tw index c258dbdf444c4e78cf60c5e9c2e6adab4e13a053..d36aff21bcfe8eadd0e72a1d0041fa84b6650af9 100644 --- a/src/SecExp/attackReport.tw +++ b/src/SecExp/attackReport.tw @@ -750,7 +750,7 @@ <</if>> <<run cashX(forceNeg($bribeCost), "war")>> <</if>> -<<if !isInt($lowerClass)>> +<<if !Number.isInteger($lowerClass)>> <<if isNaN($lowerClass)>> <br>@@.red;Error: lowerClass is NaN, please report this issue@@ <<elseif $lowerClass > 0>> @@ -759,7 +759,7 @@ <<set $lowerClass = 0>> <</if>> <</if>> -<<if !isInt($NPCSlaves)>> +<<if !Number.isInteger($NPCSlaves)>> <<if isNaN($NPCSlaves)>> <br>@@.red;Error: NPCSlaves is NaN, please report this issue@@ <<elseif $NPCSlaves > 0>> diff --git a/src/SecExp/rebellionGenerator.tw b/src/SecExp/rebellionGenerator.tw index a8b7d30003150fa013f80419b69d157f20eb573e..7f629bc71fb98e6696fe9277dd793e994097d404 100644 --- a/src/SecExp/rebellionGenerator.tw +++ b/src/SecExp/rebellionGenerator.tw @@ -196,7 +196,7 @@ <<elseif $citizenRebellionEventFires == 1>> @@.red;citizen malcontent increased@@. <</if>> -<<elseif !isInt($tension)>> +<<elseif !Number.isInteger($tension)>> <br>Error: tension is outside accepted range. <</if>> diff --git a/src/SecExp/unitsBattleReport.tw b/src/SecExp/unitsBattleReport.tw index fce1092cc1b686f22419014aaa28e9be13209071..503111bf7546bdde879d02bebee1d0f7c35d9730 100644 --- a/src/SecExp/unitsBattleReport.tw +++ b/src/SecExp/unitsBattleReport.tw @@ -81,7 +81,7 @@ /* sanity check for losses */ <<set _count = 0>> <<for _i = 0; _i < _lossesList.length; _i++>> - <<if !isInt(_lossesList[_i])>> + <<if !Number.isInteger(_lossesList[_i])>> <<set _lossesList[_i] = 0>> <</if>> <<set _count += _lossesList[_i]>> diff --git a/src/SecExp/unitsRebellionReport.tw b/src/SecExp/unitsRebellionReport.tw index 235bbacc991fbb26961f821054ffb46cb036de58..7b6a1c20c85fc22263be5be3efe7074d0dd5106c 100644 --- a/src/SecExp/unitsRebellionReport.tw +++ b/src/SecExp/unitsRebellionReport.tw @@ -279,7 +279,7 @@ /* sanity check for losses */ <<set _count = 0>> <<for _i = 0; _i < _lossesList.length; _i++>> - <<if !isInt(_lossesList[_i])>> + <<if !Number.isInteger(_lossesList[_i])>> <<set _lossesList[_i] = 0>> <</if>> <<set _count += _lossesList[_i]>> diff --git a/src/SecExp/widgets/battleWidgets.tw b/src/SecExp/widgets/battleWidgets.tw index fbf36b41b7c4a108e98bdceab28245703f3049f7..183ca80de9af834dd8e2574bac6db1a6be6978cb 100644 --- a/src/SecExp/widgets/battleWidgets.tw +++ b/src/SecExp/widgets/battleWidgets.tw @@ -4,14 +4,14 @@ <<if $slaveRebellion != 1 || $citizenRebellion != 1>> /* atk, def */ <<set _upgradesSum = $SF.Squad.Armoury + $SF.Squad.Drugs + ($SF.Squad.AA+$SF.Squad.TA < 1) + ($SF.Squad.AV+$SF.Squad.TV)>> - <<if !isInt(_upgradesSum)>> + <<if !Number.isInteger(_upgradesSum)>> <<set _upgradesSum = random(10,15)>> <</if>> <<set $SFatk = Math.trunc(0.65 * _upgradesSum)>> <<set $SFdef = Math.trunc(0.40 * _upgradesSum)>> /* hp */ <<set $carriableSoldiers = 125 * ($SF.Squad.GunS + (($SF.Squad.AV + $SF.Squad.TV)/2))>> - <<if !isInt($carriableSoldiers)>> + <<if !Number.isInteger($carriableSoldiers)>> <<set $carriableSoldiers = $SF.Squad.Troops / 10>> <</if>> <<if $SF.Squad.Troops > $carriableSoldiers>> @@ -23,7 +23,7 @@ <<else>> /* atk, def */ <<set _upgradesSum = $SF.Squad.Armoury + $SF.Squad.Drugs + ($SF.Squad.AA+$SF.Squad.TA < 1) + ($SF.Squad.AV+$SF.Squad.TV)>> - <<if !isInt(_upgradesSum)>> + <<if !Number.isInteger(_upgradesSum)>> <<set _upgradesSum = random(10,15)>> <</if>> <<set $SFatk = Math.trunc(0.75 * _upgradesSum)>> diff --git a/src/SecExp/widgets/miscSecExpWidgets.tw b/src/SecExp/widgets/miscSecExpWidgets.tw index e704c8f183aeca1e8f57d2b7b25fec165cf00fea..5fd970e2375ccf76b80e681f5a6e1b409c48aca3 100644 --- a/src/SecExp/widgets/miscSecExpWidgets.tw +++ b/src/SecExp/widgets/miscSecExpWidgets.tw @@ -233,7 +233,7 @@ <br>Fixed security bots wrong max troop count. <<set $secBots.maxTroops = 30>> <</if>> - <<if !isInt($secBots.troops)>> + <<if !Number.isInteger($secBots.troops)>> <br>Fixed security bots wrong max troop count. <<set $secBots.troops = $secBots.maxTroops>> <</if>> @@ -263,7 +263,7 @@ <br>Fixed militia unit wrong max troop count. <<set $militiaUnits[_i].maxTroops = 30>> <</if>> - <<if !isInt($militiaUnits[_i].troops)>> + <<if !Number.isInteger($militiaUnits[_i].troops)>> <<set $militiaUnits[_i].troops = $militiaUnits[_i].maxTroops>> <br>Fixed militia unit wrong troop count. <</if>> @@ -294,7 +294,7 @@ <br>Fixed slave unit wrong max troop count. <<set $slaveUnits[_i].maxTroops = 30>> <</if>> - <<if !isInt($slaveUnits[_i].troops)>> + <<if !Number.isInteger($slaveUnits[_i].troops)>> <<set $slaveUnits[_i].troops = $slaveUnits[_i].maxTroops>> <br>Fixed slave unit wrong troop count. <</if>> @@ -325,7 +325,7 @@ <br>Fixed merc unit wrong max troop count. <<set $mercUnits[_i].maxTroops = 30>> <</if>> - <<if !isInt($mercUnits[_i].troops)>> + <<if !Number.isInteger($mercUnits[_i].troops)>> <<set $mercUnits[_i].troops = $mercUnits[_i].maxTroops>> <br>Fixed merc unit wrong troop count. <</if>> @@ -337,37 +337,37 @@ <</widget>> <<widget "fixBrokenStats">> - <<if !isInt($totalKills)>> + <<if !Number.isInteger($totalKills)>> <<set $totalKills = 0>> <</if>> - <<if !isInt($mercTotalCasualties)>> + <<if !Number.isInteger($mercTotalCasualties)>> <<set $mercTotalCasualties = 0>> <</if>> - <<if !isInt($mercEmployedManpower)>> + <<if !Number.isInteger($mercEmployedManpower)>> <<set $mercEmployedManpower = 0>> <</if>> - <<if !isInt($mercTotalManpower)>> + <<if !Number.isInteger($mercTotalManpower)>> <<set $mercTotalManpower = 0>> <</if>> - <<if !isInt($slavesTotalCasualties)>> + <<if !Number.isInteger($slavesTotalCasualties)>> <<set $slavesTotalCasualties = 0>> <</if>> - <<if !isInt($slavesEmployedManpower)>> + <<if !Number.isInteger($slavesEmployedManpower)>> <<set $slavesEmployedManpower = 0>> <</if>> - <<if !isInt($militiaTotalCasualties)>> + <<if !Number.isInteger($militiaTotalCasualties)>> <<set $militiaTotalCasualties = 0>> <</if>> - <<if !isInt($militiaEmployedManpower)>> + <<if !Number.isInteger($militiaEmployedManpower)>> <<set $militiaEmployedManpower = 0>> <</if>> - <<if !isInt($militiaFreeManpower)>> + <<if !Number.isInteger($militiaFreeManpower)>> <<set $militiaFreeManpower = 0>> <</if>> - <<if !isInt($militiaTotalManpower)>> + <<if !Number.isInteger($militiaTotalManpower)>> <<set $militiaTotalManpower = 0>> <</if>> - <<if !isInt($battlesCount)>> + <<if !Number.isInteger($battlesCount)>> <<set $battlesCount = 0>> <</if>> <</widget>> diff --git a/src/events/intro/introSummary.tw b/src/events/intro/introSummary.tw index 0ad9c8ad6dddd5ef6aba4b8629265557ad3f0991..5690b39a8c48071bf43d058ba94e0c7344383c86 100644 --- a/src/events/intro/introSummary.tw +++ b/src/events/intro/introSummary.tw @@ -887,12 +887,12 @@ __''Player Character''__ <<options $PC.preg>> You are ''<<print $PC.preg>> weeks pregnant with octuplets'' and your water just broke. - <<options 0 "Not pregnant" "$PC.pregType = 0, $PC.labor = 0">> + <<option 0 "Not pregnant" "$PC.pregType = 0, $PC.labor = 0">> <</options>> <<elseif $PC.preg > 37>> <<options $PC.preg>> You are ''<<print $PC.preg>> weeks pregnant'' and going to go into labor soon. - <<options 0 "Not pregnant" "$PC.pregType = 0, $PC.labor = 0">> + <<option 0 "Not pregnant" "$PC.pregType = 0, $PC.labor = 0">> <<option 43 "Stuffed to capacity" "$PC.pregType = 8, $PC.labor = 1">> <</options>> <<elseif $PC.preg > 0>> @@ -1159,6 +1159,8 @@ __''Player Character''__ <</options>> <br> +<<set _exampleSlave = BaseSlave()>> + <<if $seeImages == 1>> <<options $imageChoice>> Using @@ -1174,6 +1176,10 @@ __''Player Character''__ <br>@@.red;Git compiled only, no exceptions.@@ <</options>> <<if $imageChoice == 1>> + <br> + <div style="position:relative;width:200px;height:200px;margin:0 auto;"> + <<SlaveArt _exampleSlave 0 0>> + </div> <br> <<options $seeFaces>> Face art @@ -1201,7 +1207,15 @@ __''Player Character''__ @@.cyan;ENABLED@@ on all images. <</options>> <<elseif $imageChoice == 2>> + <br> + <div style="position:relative;width:200px;height:200px;margin:0 auto;"> + <<SlaveArt _exampleSlave 0 0>> + </div> <<elseif $imageChoice == 3>> + <br> + <div style="position:relative;width:200px;height:200px;margin:0 auto;"> + <<SlaveArt _exampleSlave 0 0>> + </div> <br> <<options $seeVectorArtHighlights>> Highlights on shiny clothing diff --git a/src/facilities/nursery/childInteract.tw b/src/facilities/nursery/childInteract.tw index cb9b5b4480c95246f81cd62e64c35eee5e06ceba..84c6aee5d00bbceba96b0526d03fd5a24f7c9e7e 100644 --- a/src/facilities/nursery/childInteract.tw +++ b/src/facilities/nursery/childInteract.tw @@ -151,7 +151,6 @@ <</if>> <</if>> <</if>> - </span> <<if canDoVaginal($activeChild)>> | <<link "Have another slave fuck $his pussy" "FSlaveSlaveVag">><</link>> <</if>> diff --git a/src/js/optionsMacro.js b/src/js/optionsMacro.js index 3e089e5815aaaf2e5a826bdbfec06d9de81d6e77..b4d81c6d548aecbba2d12f180509f62df7af8a56 100644 --- a/src/js/optionsMacro.js +++ b/src/js/optionsMacro.js @@ -31,12 +31,13 @@ Macro.add('options', { var comment = null; var hasMultipleOptionsWithSameValue = false; var description = ""; + var hasCurrentOption = this.payload[0].args.full && + this.payload[0].args.full !== '""' && this.payload[0].args.full !== "''"; /* Check if we have a first argument - if we do, it should be a variable like $foo */ - if (this.payload[0].args.full && - this.payload[0].args.full !== '""' && this.payload[0].args.full !== "''") { + if (hasCurrentOption) { if (currentOption === undefined) currentOption = false; if (this.payload[0].args.full.startsWith("State.temporary.")) { @@ -95,6 +96,21 @@ Macro.add('options', { throw new Error("Only valid tag is 'option' inside 'options'"); } } + } else { + // No variable was passed to <<options>> + // This is valid, but then we only allow an empty <<option>> or <<comment>> + // inside + for (let i = 1, len = this.payload.length; i < len; ++i) { + if (this.payload[i].name === 'option' && this.payload[i].args.length === 0) { + // This is valid for an empty <<options>> + } else if (this.payload[i].name === "comment") { + // This is valid for an empty <<options>> + } else { + throw new Error("Missing variable to <<options>>"); + } + + } + } var showSelectedOption = true; //this.payload.length !== 3 || !description; diff --git a/src/js/utilJS.js b/src/js/utilJS.js index e3cb2928bb36e496705724e1c64fa623e26a52ee..45c3d0c925a946a7f95744c6f37ad7c29cceb6f3 100644 --- a/src/js/utilJS.js +++ b/src/js/utilJS.js @@ -413,29 +413,6 @@ window.gaussianPair = function() { return [r * Math.cos(sigma), r * Math.sin(sigma)]; }; -if (!Array.prototype.findIndex) { - Array.prototype.findIndex = function(predicate) { - if (this == null) { - throw new TypeError('Array.prototype.find called on null or undefined'); - } - if (typeof predicate !== 'function') { - throw new TypeError('predicate must be a function'); - } - let list = Object(this); - let length = list.length >>> 0; - let thisArg = arguments[1]; - let value; - - for (let i = 0; i < length; i++) { - value = list[i]; - if (predicate.call(thisArg, value, i, list)) { - return i; - } - } - return -1; - }; -} - /* A categorizer is used to "slice" a value range into distinct categories in an efficient manner. @@ -736,11 +713,7 @@ window.budgetLine = function(category, title) { }; window.isFloat = function(n) { - return n === +n && n !== (n|0); -}; - -window.isInt = function(n) { - return n === +n && n === (n|0); + return Number.isFinite(n) && Math.floor(n) !== n; }; window.jsRandom = function(min, max) { @@ -1511,8 +1484,20 @@ window.resyncSlaveToAge = function(slave) { slave.boobs = 200; slave.birthWeek = 0; SetBellySize(slave); + if (slave.dick > 0) { + slave.dick = 1; + } + if (slave.balls > 0) { + slave.balls = 1; + } } else { slave.boobs = Math.max(slave.boobs, 500); + if (slave.dick > 2) { + slave.dick = 2; + } + if (slave.balls > 2) { + slave.balls = 2; + } } slave.career = randomCareer(slave); } diff --git a/src/npc/startingGirls/startingGirls.tw b/src/npc/startingGirls/startingGirls.tw index c95cf083c73cae40f2ee5ce6b514a17f2de67055..49c4dda59d0a324deea8090599a0f28298b80e78 100644 --- a/src/npc/startingGirls/startingGirls.tw +++ b/src/npc/startingGirls/startingGirls.tw @@ -555,9 +555,9 @@ __You are customizing this slave:__ <<options $activeSlave.genes>> ''Genes:'' - <<option "XX" "XX" "$activeSlave.dick = 0, $activeSlave.balls = 0,$activeSlave.clit = 0,$activeSlave.pubertyXY = 0,$activeSlave.pubertyAgeXY = $potencyAge, $activeSlave.pubertyXX=($activeSlave.pubertyAgeXX<$activeSlave.actualAge?1:0),$activeSlave.vagina=Math.max(0, $activeSlave.vagina),$activeSlave.boobs=Math.max(500,$activeSlave.boobs), $activeSlave.balls=0, $activeSlave.scrotum=0, $activeSlave.prostate=0,$activeSlave.shoulders=either(-2,-1,0),$activeSlave.hips=either(-2,-1,0)">> + <<option "XX" "XX" "$activeSlave.dick = 0, $activeSlave.balls = 0, $activeSlave.clit = 0, $activeSlave.pubertyXY = 0, $activeSlave.pubertyAgeXY = $potencyAge, $activeSlave.pubertyXX = ($activeSlave.pubertyAgeXX < $activeSlave.actualAge ? 1 : 0), $activeSlave.vagina = Math.max(0, $activeSlave.vagina), $activeSlave.boobs = Math.max(500, $activeSlave.boobs), $activeSlave.balls = 0, $activeSlave.scrotum = 0, $activeSlave.prostate = 0, $activeSlave.shoulders = either(-2,-1,0), $activeSlave.hips = either(-2,-1,0)">> @@.yellow;XX@@ (Female) - <<option "XY" "XY" "$activeSlave.dick = 3, $activeSlave.vagina=-1, $activeSlave.preg = 0, WombFlush($activeSlave), $activeSlave.belly = 0,$activeSlave.bellyPreg = 0,$activeSlave.pubertyXY=($activeSlave.pubertyAgeXY<$activeSlave.actualAge?1:0), $activeSlave.pregType = 0, $activeSlave.pregSource = 0, $activeSlave.pregWeek = 0, $activeSlave.pregKnown = 0,$activeSlave.pubertyXX = 0,$activeSlave.pubertyAgeXX = $fertilityAge, $activeSlave.ovaries = 0, $activeSlave.boobs=0, $activeSlave.balls=3, $activeSlave.scrotum=3, $activeSlave.prostate=1,$activeSlave.shoulders=either(0,1,2),$activeSlave.hips=either(0,1,2)">> + <<option "XY" "XY" "$activeSlave.dick = 3, $activeSlave.vagina = -1, $activeSlave.preg = 0, WombFlush($activeSlave), $activeSlave.belly = 0, $activeSlave.bellyPreg = 0, $activeSlave.pubertyXY = ($activeSlave.pubertyAgeXY < $activeSlave.actualAge ? 1 : 0), $activeSlave.pregType = 0, $activeSlave.pregSource = 0, $activeSlave.pregWeek = 0, $activeSlave.pregKnown = 0, $activeSlave.pubertyXX = 0, $activeSlave.pubertyAgeXX = $fertilityAge, $activeSlave.ovaries = 0, $activeSlave.boobs = 0, $activeSlave.balls = 3, $activeSlave.scrotum = 3, $activeSlave.prostate = 1, $activeSlave.shoulders = either(0,1,2), $activeSlave.hips = either(0,1,2)">> @@.yellow;XY@@ (Male) <</options>> @@ -894,7 +894,7 @@ __You are customizing this slave:__ <</options>> <br> - <<options >> + <<options $activeSlave.tastes>> ''Taste ability:'' <<option 0 "Normal">> Normal. <<option -1 "None">> Unable to taste. @@ -902,14 +902,17 @@ __You are customizing this slave:__ <</if>> <br> <br> + <<options $activeSlave.boobs>> ''Breasts:'' - <<optionlte 200 200 "Flat">> Flat. - <<optionlte 500 500 "Healthy">> Healthy. - <<optionlte 800 800 "Large">> Large. - <<optionlte 1200 1200 "Very Large">> Very Large. - <<optionlte 2000 2000 "Huge">> Huge. - <<optionlte 4000 4000 "Massive">> Massive. + <<optionlte 200 200 "Flat">> Flat (AA-cup). + <<optionlte 300 300 "Small">> Small (A-cup). + <<optionlte 400 400 "Medium">> Medium (B-cup). + <<optionlte 500 500 "Healthy">> Healthy (C-cup). + <<optionlte 800 800 "Large">> Large (DD-cup). + <<optionlte 1200 1200 "Very Large">> Very Large (G-cup). + <<optionlte 2050 2050 "Huge">> Huge (K-cup). + <<optionlte 3950 3950 "Massive">> Massive (Q-cup). <<optionlte 6000 6000 "Monstrous">> Monstrous. <<optiondefault 8000 "Science experiment">>Science experiment. <<option>> @@ -1192,7 +1195,7 @@ __You are customizing this slave:__ //Must have a vagina to have vaginal skills// <</options>> <<else>> - <<options $activeSlave.vagina>> + <<options $activeSlave.vaginalSkill>> ''Vaginal sex:'' <<optionlte 10 0 "Unskilled">>Unskilled. <<optionlte 30 15 "Basic">>@@.cyan;Basic.@@ diff --git a/src/uncategorized/arcmgmt.tw b/src/uncategorized/arcmgmt.tw index 0013f17583c9afb0a24c8e4909eec38fbec43c28..f6bce3e54467d37bb95fb52f288d5b488229062f 100644 --- a/src/uncategorized/arcmgmt.tw +++ b/src/uncategorized/arcmgmt.tw @@ -1079,7 +1079,7 @@ _percTopClass = Math.trunc(($topClass / ($ACitizens + $ASlaves)) * 1000) / 10>> Those of your citizens who have not yet subscribed to the society you are building are permitted to live and do business here, but must pay a moderate jizya tax for the privilege as part of their rent. <</if>> <<set _rents = Math.trunc(($lowerClass * $LCRent + $middleClass * $MCRent + $upperClass * $UCRent + $topClass * $TCRent) * _rentMultiplier / 25)>> -<<if !isInt(_rents)>> +<<if !Number.isInteger(_rents)>> <br>@@.red;Error: rents is outside accepted range, please report this issue@@ <<else>> <<run cashX(_rents, "rents")>> diff --git a/src/uncategorized/bodyModification.tw b/src/uncategorized/bodyModification.tw index 3ebc6ef2d386beeaa971a5f3dbd83ba6b949a705..9e77734b1200cdcdca3e954ff67859c5820c5f60 100644 --- a/src/uncategorized/bodyModification.tw +++ b/src/uncategorized/bodyModification.tw @@ -395,7 +395,7 @@ Choose piercing style: <<if $activeSlave.lipsPiercing != 1>><<set $activeSlave.lipsPiercing = 1>> <<run cashX(forceNeg($modCost), "slaveMod", $activeSlave)>><</if>> <<if $activeSlave.tonguePiercing != 1>><<set $activeSlave.tonguePiercing = 1>> <<run cashX(forceNeg($modCost), "slaveMod", $activeSlave)>><</if>> <<if $activeSlave.nipples != "fuckable">> - <<if $activeSlave.nipplesPiercing != 1 && >><<set $activeSlave.nipplesPiercing = 1>><<run cashX(forceNeg($modCost), "slaveMod", $activeSlave)>><</if>> + <<if $activeSlave.nipplesPiercing != 1>><<set $activeSlave.nipplesPiercing = 1>><<run cashX(forceNeg($modCost), "slaveMod", $activeSlave)>><</if>> <</if>> <<if $activeSlave.areolaePiercing != 1>><<set $activeSlave.areolaePiercing = 1>> <<run cashX(forceNeg($modCost), "slaveMod", $activeSlave)>><</if>> <<if $activeSlave.corsetPiercing != 1>><<set $activeSlave.corsetPiercing = 1>> <<run cashX(forceNeg($modCost), "slaveMod", $activeSlave)>><</if>> diff --git a/src/uncategorized/costsBudget.tw b/src/uncategorized/costsBudget.tw index 329ed2cd00b98e4c237e79eed28274f96972a4e5..564e1f4ca8643ad9ed5dc70012426d9a5ec83507 100644 --- a/src/uncategorized/costsBudget.tw +++ b/src/uncategorized/costsBudget.tw @@ -11,7 +11,7 @@ //Here you can view many of the financial details of your arcology, <<= properTitle()>>. The detailed list of slaves and their costs (food, hormones) that you may remember can now be found in the "Slave maintenance" link. Other links will allow you to directly control areas of your arcology to adjust spending to suit your tastes.// -<br style="clear:both" /><<if $lineSeparations == 0>><br><<else>><hr style="margin:0"><</if>> +<br style="clear:both"><<if $lineSeparations == 0>><br><<else>><hr style="margin:0"><</if>> <<if $difficultySwitch == 1>> //The Local Economy score effects some prices in your ecology. The lower the score, the higher the prices. The base score is ''100''.// @@ -59,7 +59,7 @@ <<set _econPercent = Math.trunc(100000/$localEcon-1000)/10>> increasing prices by @@.red;''<<print _econPercent>>%.''@@ <</if>> - <br style="clear:both" /><<if $lineSeparations == 0>><br><br><<else>><hr style="margin:0"><</if>> + <br style="clear:both"><<if $lineSeparations == 0>><br><br><<else>><hr style="margin:0"><</if>> <</if>> //Your weekly costs are as follows:// diff --git a/src/uncategorized/dairyReport.tw b/src/uncategorized/dairyReport.tw index 551513703c5d7df8906d4053eb0fbf7108c63ecd..c66e64ef586510f0092a2b552096c507da5d5c2d 100644 --- a/src/uncategorized/dairyReport.tw +++ b/src/uncategorized/dairyReport.tw @@ -458,7 +458,7 @@ <<run cashX(forceNeg($surgeryCost), "slaveSurgery", $slaves[$i])>> <</if>> <<if $slaves[$i].vasectomy == 1>> - <<set $slaves[$i].vasectomy = 0, $slaves[$i].health -= 10,>> + <<set $slaves[$i].vasectomy = 0, $slaves[$i].health -= 10>> <<run cashX(forceNeg($surgeryCost), "slaveSurgery", $slaves[$i])>> <</if>> <<if ($dairySlimMaintain == 0)>> diff --git a/src/uncategorized/endWeek.tw b/src/uncategorized/endWeek.tw index c208ce983b8650da9bc9f6542e85d7096002c62e..c6909755b9a052142dc52a5af79182b0e6337f27 100644 --- a/src/uncategorized/endWeek.tw +++ b/src/uncategorized/endWeek.tw @@ -1,10 +1,5 @@ :: End Week [nobr] -<<if $personalAttention.length > 0>> - <<if !$personalAttention.trainingRegimen.includes("explore her sexuality")>> - <<set $PC.slaving += 0.1>> - <</if>> -<</if>> <<set State.expired.length = 0>> <<setupLastWeeksCash>> diff --git a/src/uncategorized/persBusiness.tw b/src/uncategorized/persBusiness.tw index 31e7c744dc0237060921bc09be4617a33c92c62b..1b5f7747402b2a2c1a550f4060bd0f0ae2f0d1e1 100644 --- a/src/uncategorized/persBusiness.tw +++ b/src/uncategorized/persBusiness.tw @@ -737,7 +737,7 @@ <<set _upgradeCount += 1>> <</if>> <<set _dataGain = _upgradeCount * 200>> - <<if !isInt(_dataGain)>> + <<if !Number.isInteger(_dataGain)>> <br>@@.red;Error, dataGain is NaN@@ <<else>> You are selling the data collected by your security department, which earns a discreet sum of @@.yellowgreen;<<print cashFormat(_dataGain)>>@@. @@ -855,7 +855,7 @@ Routine upkeep of your demesne costs @@.yellow;<<print cashFormat($costs)>>.@@ <</if>> <<set _income = Math.trunc(_income * 0.5)>> This week we made @@.yellowgreen;<<print cashFormat(_income)>>.@@ - <<if !isInt(_income)>> + <<if !Number.isInteger(_income)>> <br>@@.red;Error failed to calculate income@@ <<else>> <<run cashX(_income, "personalBusiness")>> diff --git a/src/uncategorized/ptWorkaround.tw b/src/uncategorized/ptWorkaround.tw index 181ba9c38236c007b614e2d9d47ae7a665f6db0e..f717b9a850538ad6f147ac8f5e65583b697e8b3e 100644 --- a/src/uncategorized/ptWorkaround.tw +++ b/src/uncategorized/ptWorkaround.tw @@ -82,6 +82,7 @@ <<set $activeSlave.training = 0>> <<case "look after her">> + <<set $PC.slaving += 0.1>> <<if $activeSlave.relationship == -3 && $activeSlave.fetish == "mindbroken">> Since $activeSlave.slaveName is your wife and not all there, you keep $him under a watchful eye to make sure no harm comes to the broken $girl. $He almost seems in better spirits under your care, not that it will matter in an hour or two. <<set $activeSlave.kindness++>> @@ -108,7 +109,6 @@ <<set $activeSlave.training = 0>> <<case "soften her behavioral flaw">> - <<set $PC.slaving += 0.2>> <<if ($activeSlave.behavioralFlaw == "none")>> $activeSlave.slaveName got over $his behavioral flaw without you; @@.yellow;$his training assignment has defaulted to @@ -156,8 +156,10 @@ $activeSlave.slaveName remains devoted to an old world faith that serves $him as a reservoir of mental resilience. Like all such beliefs, $hers has certain sexual elements; you amuse yourself by forcing $him to break them, and rewarding $him generously when $he does. <</if>> <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> You make progress, but $he's the same at the end of the week. <<else>> + <<set $PC.slaving += 0.5>> <<set $activeSlave.training = 0>> By the end of the week, @@.green;you resolve $his flaw into something special.@@ @@.hotpink;$His obedience has increased.@@ <<run SoftenBehavioralFlaw($activeSlave)>> @@ -198,7 +200,6 @@ <</if>> <<case "soften her sexual flaw">> - <<set $PC.slaving += 0.2>> <<if ($activeSlave.sexualFlaw == "none")>> $activeSlave.slaveName got over $his sexual flaw without you, @@.yellow;$his training assignment has defaulted to @@ -281,8 +282,10 @@ has something. You should probably report this as nobody knows what is currently happening. $His flaw was supposed to be $activeSlave.sexualFlaw. <</switch>> <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> You make progress, but $he's the same at the end of the week. <<else>> + <<set $PC.slaving += 0.5>> <<set $activeSlave.training = 0>> By the end of the week, @@.green;you resolve $his flaw into something special.@@ @@.hotpink;$His obedience has increased.@@ <<run SoftenSexualFlaw($activeSlave)>> @@ -434,15 +437,19 @@ <<if ($activeSlave.trust < -20) && ($activeSlave.fetishKnown == 0)>> $He is now fully broken; @@.yellow;$his training assignment has defaulted to exploring $his sexuality.@@ <<set $personalAttention[_ptwi].trainingRegimen = "explore her sexuality">> + <<set $PC.slaving += 0.5>> <<elseif ($activeSlave.trust < -20)>> $He is now fully broken; @@.yellow;$his training assignment has defaulted to fostering devotion.@@ <<set $personalAttention[_ptwi].trainingRegimen = "build her devotion">> + <<set $PC.slaving += 0.5>> <<elseif ($activeSlave.devotion > 20) && ($activeSlave.fetishKnown == 0)>> $He is now obedient and attentive; @@.yellow;$his training assignment has defaulted to exploring $his sexuality.@@ <<set $personalAttention[_ptwi].trainingRegimen = "explore her sexuality">> + <<set $PC.slaving += 0.5>> <<elseif ($activeSlave.devotion > 20)>> $He is now obedient and attentive; @@.yellow;$his training assignment has defaulted to fostering devotion.@@ <<set $personalAttention[_ptwi].trainingRegimen = "build her devotion">> + <<set $PC.slaving += 0.5>> <</if>> <<set $activeSlave.training = 0>> @@ -511,11 +518,11 @@ <<if ($activeSlave.devotion > 20)>> $He is now fully broken; @@.yellow;$his training assignment has defaulted to fostering devotion.@@ <<set $personalAttention[_ptwi].trainingRegimen = "build her devotion">> + <<set $PC.slaving += 1>> <</if>> <<set $activeSlave.training = 0>> <<case "fix her behavioral flaw">> - <<set $PC.slaving += 0.2>> <<if ($activeSlave.behavioralFlaw == "arrogant")>> $activeSlave.slaveName seems to think $he's better than everyone else. Naturally, as $his owner you have the means to correct this sad misapprehension. As you train $him during the week, you ensure that $he submits to anyone and everyone. $He is rarely permitted to enjoy sex under your tutelage, but is instead required to use $his mouth and hands to get others off. $He cleans, washes, and serves. <<set $activeSlave.oralCount += 10, $oralTotal += 10>> @@ -551,8 +558,10 @@ <</if>> <<set $activeSlave.training += 40>> /* fixing is easier than softening */ <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> You make progress, but $he's the same at the end of the week. <<else>> + <<set $PC.slaving += 0.5>> <<set $activeSlave.training = 0>> By the end of the week, @@.green;you break $him of $his bad habits.@@ @@.hotpink;$His obedience has increased.@@ <<set $activeSlave.behavioralFlaw = "none", $activeSlave.devotion += 4>> @@ -589,7 +598,6 @@ <</if>> <<case "fix her sexual flaw">> - <<set $PC.slaving += 0.2>> <<switch $activeSlave.sexualFlaw>> <<case "hates oral">> $activeSlave.slaveName has a powerful gag reflex. As a result, it's pretty unpleasant to receive oral sex from $him, no matter how hard $he tries. You apply various inventive techniques for addressing this, all of which involve requiring $him to repeatedly deepthroat some object or other. @@ -683,8 +691,10 @@ <</switch>> <<set $activeSlave.training += 40>> /* fixing is easier than softening */ <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> You make progress, but $he's the same at the end of the week. <<else>> + <<set $PC.slaving += 0.5>> <<set $activeSlave.training = 0>> By the end of the week, @@.green;you break $him of $his bad habits.@@ @@.hotpink;$His obedience has increased.@@ <<set $activeSlave.sexualFlaw = "none", $activeSlave.devotion += 4>> @@ -723,7 +733,7 @@ <</if>> <<case "explore her sexuality">> - <<set $PC.slaving += 0.2>> + <<set $PC.slaving += 0.1>> <<set $activeSlave.attrKnown = 1>> You set about investigating $his sexuality. <<if ($activeSlave.devotion < -20) && ($activeSlave.trust >= -20)>> @@ -862,311 +872,339 @@ <<BasicTrainingDefaulter>> <<case "induce arrogance">> - <<set $PC.slaving += 0.2>> Since you've decided to incite $him to arrogance, you praise $him effusively, and give orders that others are to do so as well. Other slaves are punished for things $he's allowed to get away with. <<InduceFlawLenityEffects>> <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> $He isn't seriously affected; you'll have to be more subtle next week. <<else>> + <<set $PC.slaving += 0.5>> <<set $activeSlave.training = 0>> $He begins to think $himself special, and is now @@.red;arrogant.@@ <<set $activeSlave.behavioralFlaw = "arrogant">> <<BasicTrainingDefaulter>> <</if>> <<case "induce bitchiness">> - <<set $PC.slaving += 0.2>> Since you've decided to induce $him to bitchiness, you keep $him in your office and induce $him to criticize other slaves, rewarding $him when $he's especially catty. <<InduceFlawLenityEffects>> <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> $He goes along, but remains cautious and will need more practice. <<else>> + <<set $PC.slaving += 0.5>> $He starts making @@.red;bitchy@@ remarks without being prompted. <<set $activeSlave.behavioralFlaw = "bitchy">> <<BasicTrainingDefaulter>> <</if>> <<case "induce odd behavior">> - <<set $PC.slaving += 0.2>> Since you've decided to abuse $him into odd behavior, you target $him for a campaign of surprise sex. You constantly ambush $him, shove $him onto the ground, and fuck $him. Sometimes $he wakes up from bad dreams to find you penetrating $him. <<InduceFlawAbuseEffects>> <<if canDoVaginal($activeSlave)>><<= VaginalVCheck(10)>><<elseif canDoAnal($activeSlave)>><<= AnalVCheck(10)>><<else>><<set $activeSlave.oralCount += 10, $oralTotal += 10>><</if>> <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> $He does $his best to tolerate the abuse. <<else>> + <<set $PC.slaving += 0.5>> $He starts @@.red;behaving oddly,@@ jumping at noises and mumbling to $himself. <<set $activeSlave.behavioralFlaw = "odd">> <<BasicTrainingDefaulter>> <</if>> <<case "induce hatred of men">> - <<set $PC.slaving += 0.2>> In order to make $him hate men, you sometimes simply <<if $PC.dick == 1>>stick your dick in $him without asking<<else>>stuff a strap-on inside $him without asking<</if>>, and sometimes force shockingly juvenile pranks on $him. $He is regularly smacked in the face with floppy dildos. <<InduceFlawAbuseEffects>> <<if canDoVaginal($activeSlave)>><<= VaginalVCheck(10)>><<elseif canDoAnal($activeSlave)>><<= AnalVCheck(10)>><<else>><<set $activeSlave.oralCount += 10, $oralTotal += 10>><</if>> <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> $He focuses more on you than on the masculine aspects of this. You'll need to be more subtle next week. <<else>> + <<set $PC.slaving += 0.5>> You notice $him starting to @@.red;shoot hateful glances@@ at any men $he sees. <<set $activeSlave.behavioralFlaw = "hates men">> <<BasicTrainingDefaulter>> <</if>> <<case "induce hatred of women">> - <<set $PC.slaving += 0.2>> In order to make $him hate women, you keep $him in your office when $he's not otherwise occupied, and <<if $PC.vagina == 0>>make $him eat other slaves out<<else>>sit on $his face<</if>> until $he's thoroughly sick of pussy. <<InduceFlawAbuseEffects>> <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> $He focuses more on you than on the feminine aspects of this. You'll need to be more subtle next week. <<else>> + <<set $PC.slaving += 0.5>> You notice $him starting to @@.red;shoot hateful glances@@ at any vaginas $he sees. <<set $activeSlave.behavioralFlaw = "hates women">> <<BasicTrainingDefaulter>> <</if>> <<case "induce gluttony">> - <<set $PC.slaving += 0.2>> Inducing gluttony is harder than inducing anorexia; you force $him to orgasm when $he's eating, and praise $him effusively when $he gains weight. You also provide $him with ample rations for stress eating. <<set $activeSlave.training -= 20>> /* more difficult training */ <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> $He eats when ordered, but isn't deeply affected. $He'll need more practice being a pig. <<else>> + <<set $PC.slaving += 0.5>> You notice $him starting to @@.red;enjoy eating@@ for its own sake, even when $he's not hungry. <<set $activeSlave.behavioralFlaw = "gluttonous">> <<BasicTrainingDefaulter>> <</if>> <<case "induce anorexia">> - <<set $PC.slaving += 0.2>> You criticize $him cruelly whenever $he eats, and praise thinner slaves to $his face at every opportunity. <<InduceFlawAbuseEffects>> <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> $He continues consuming $his rations when ordered, and will need further training. <<else>> + <<set $PC.slaving += 0.5>> $He begins to @@.red;eat only when repeatedly ordered to.@@ <<set $activeSlave.behavioralFlaw = "anorexic">> <<BasicTrainingDefaulter>> <</if>> <<case "induce religious devotion">> - <<set $PC.slaving += 0.2>> You direct a campaign of abuse and threats at $him, and surreptitiously ensure that a little religious text from $his home country finds its way into a hiding place in $his living area. <<InduceFlawAbuseEffects>> <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> $He keeps $his head down and shows no sign of religious introspection, at least this week. <<else>> + <<set $PC.slaving += 0.5>> $He begins to read it when $he thinks $he's alone, and @@.red;talks to God@@ when $he thinks only He is listening. <<set $activeSlave.behavioralFlaw = "devout">> <<BasicTrainingDefaulter>> <</if>> <<case "induce liberation">> - <<set $PC.slaving += 0.2>> You direct a campaign of abuse and threats at $him, making sure to threaten $him with the absolute worst of slavery in your arcology. You also arrange for $him to witness other citizen's slaves in situations that aren't much fun. <<InduceFlawAbuseEffects>> <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> $He does $his best to endure the abuse, unknowingly condemning $himself to more. <<else>> + <<set $PC.slaving += 0.5>> A deep @@.red;anger about slavery@@ builds within $him. <<set $activeSlave.behavioralFlaw = "liberated">> <<BasicTrainingDefaulter>> <</if>> <<case "induce hatred of oral">> - <<set $PC.slaving += 0.2>> Since you've decided to force $him to dislike oral sex, you're forced to use a complicated and refined slave breaking technique: constantly raping $his face. <<InduceFlawAbuseEffects>> <<set $activeSlave.oralCount += 10, $oralTotal += 10>> <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> $He does $his best to comply with the oral abuse, unknowingly condemning $himself to more. <<else>> + <<set $PC.slaving += 0.5>> After gagging enough, $he finally starts to @@.red;hate oral.@@ <<set $activeSlave.sexualFlaw = "hates oral">> <<BasicTrainingDefaulter>> <</if>> <<case "induce hatred of anal">> - <<set $PC.slaving += 0.2>> Since you've decided to force $him to dislike anal sex, you're forced to use a complicated and refined slave breaking technique: constantly raping $his ass. <<if !canDoAnal($activeSlave)>>Every time you catch $him with $his chastity off, you're there to penetrate $his rectum<</if>>. <<InduceFlawAbuseEffects>> <<= AnalVCheck(10)>> <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> $He does $his best to comply with your abuse of $his butthole, unknowingly condemning $himself to more assrape. <<else>> + <<set $PC.slaving += 0.5>> After feeling $his poor sphincter grow sorer and sorer, $he starts to @@.red;hate anal.@@ <<set $activeSlave.sexualFlaw = "hates anal">> <<BasicTrainingDefaulter>> <</if>> <<case "induce hatred of penetration">> - <<set $PC.slaving += 0.2>> Since you've decided to force $him to dislike penetration, you're forced to use a complicated and refined slave breaking technique: constantly raping $him. <<InduceFlawAbuseEffects>> <<if canDoVaginal($activeSlave)>><<= VaginalVCheck(10)>><<elseif canDoAnal($activeSlave)>><<= AnalVCheck(10)>><<else>><<set $activeSlave.oralCount += 10, $oralTotal += 10>><</if>> <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> $He does $his best to comply with your abuse, unknowingly condemning $himself to more of it. <<else>> + <<set $PC.slaving += 0.5>> After feeling $his poor holes grow sorer and sorer, $he starts to @@.red;hate getting fucked.@@ <<set $activeSlave.sexualFlaw = "hates penetration">> <<BasicTrainingDefaulter>> <</if>> <<case "induce shame">> - <<set $PC.slaving += 0.2>> Since you've decided to force shame on $him, you keep $him in your office whenever $he's not otherwise occupied, and heap derision on $him at every opportunity, even inviting visitors to join you in chats about how unattractive and worthless $he is. <<InduceFlawAbuseEffects>> <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> $He does $his best to keep $his chin up, unknowingly condemning $himself to more of this abuse. <<else>> + <<set $PC.slaving += 0.5>> $He wants nothing more than to hide in corner and cry, and is now @@.red;shamefast.@@ <<set $activeSlave.sexualFlaw = "shamefast">> <<BasicTrainingDefaulter>> <</if>> <<case "induce sexual idealism">> - <<set $PC.slaving += 0.2>> Since you've decided to induce $him to sexual idealism, you keep $him in your office, and when the two of you are all alone, gossip with $him about other slaves and even citizens. You do your best to encourage $him to believe absurdities. <<InduceFlawLenityEffects>> <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> $He doesn't know what to make of this; you'll have to keep at it. <<else>> + <<set $PC.slaving += 0.5>> $He follows along, and is now @@.red;sexually idealistic.@@ <<set $activeSlave.sexualFlaw = "idealistic">> <<BasicTrainingDefaulter>> <</if>> <<case "induce sexual repression">> - <<set $PC.slaving += 0.2>> Since you've decided to force sexual repression on $him, you keep $him in your office whenever $he's not otherwise occupied. You use the monitoring systems to reveal $his sexual arousal whenever it appears, and castigate and punish $him for it. <<InduceFlawAbuseEffects>> <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> $He does $his best to keep $his chin up, unknowingly condemning $himself to more of this abuse. <<else>> + <<set $PC.slaving += 0.5>> $He desperately tries to avoid even thinking about subjects that get $him punished, and is now @@.red;sexually repressed.@@ <<set $activeSlave.sexualFlaw = "repressed">> <<BasicTrainingDefaulter>> <</if>> <<case "induce sexual apathy">> - <<set $PC.slaving += 0.2>> Since you've decided to force sexual apathy on $him, you keep $him in your office whenever $he's not otherwise occupied. You use $him regularly, and punish $him whenever $he shows any sign of enjoyment. <<InduceFlawAbuseEffects>> <<if canDoVaginal($activeSlave)>><<= VaginalVCheck(10)>><<elseif canDoAnal($activeSlave)>><<= AnalVCheck(10)>><<else>><<set $activeSlave.oralCount += 10, $oralTotal += 10>><</if>> <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> $He continues to experience arousal when fucked, and will need more of this treatment. <<else>> + <<set $PC.slaving += 0.5>> $He desperately tries to avoid arousal, and is now @@.red;sexually apathetic.@@ <<set $activeSlave.sexualFlaw = "apathetic">> <<BasicTrainingDefaulter>> <</if>> <<case "induce crudity">> - <<set $PC.slaving += 0.2>> Since you've decided to force sexual crudeness on $him, you keep $him in your office whenever $he's not otherwise occupied, and degrade $him cruelly. You relax the normal cleanliness rules, and require $him to leave $his used holes as they are until $he's too disgusting to fuck. <<if canDoVaginal($activeSlave)>><<= VaginalVCheck(10)>><<elseif canDoAnal($activeSlave)>><<= AnalVCheck(10)>><<else>><<set $activeSlave.oralCount += 10, $oralTotal += 10>><</if>> <<InduceFlawAbuseEffects>> <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> $He does $his best to tolerate the unclean feelings, condemning $himself to more of this. <<else>> + <<set $PC.slaving += 0.5>> $He slowly stops caring, and is now @@.red;sexually crude.@@ <<set $activeSlave.sexualFlaw = "crude">> <<BasicTrainingDefaulter>> <</if>> <<case "induce judgement">> - <<set $PC.slaving += 0.2>> Since you've decided to make $him sexually judgemental, you keep $him in your office and fuck $him, <<if $PC.dick == 1>>praising $him whenever $he takes your big dick well<<else>>using a huge strap-on on $him and praising $him when $he takes it like a good girl<</if>>. You also judge others' endowments in $his presence. <<InduceFlawLenityEffects>> <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> $He writes this off as bravado, and will need more training. <<else>> + <<set $PC.slaving += 0.5>> $He starts to consider $himself reserved for special sexual treatment, and is now @@.red;sexually judgemental.@@ <<set $activeSlave.sexualFlaw = "judgemental">> <<BasicTrainingDefaulter>> <</if>> <<case "induce cum addiction">> - <<set $PC.slaving += 0.2>> The cumslut is quite pleased when you order $him to stay in your office whenever $he can for use as one of your personal oral toys. You carefully limit $his orgasms to when <<if $PC.dick == 1>>you're blowing your load down $his throat<<else>>$he's swallowing your pussyjuice<</if>>, and make $his oral adventures predictably regular. <<set $activeSlave.oralCount += 10, $oralTotal += 10>> <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> $He enjoys giving you lots of oral, but will need more training to develop psychological addiction to it. <<else>> + <<set $PC.slaving += 0.5>> $He begins to develop a psychological @@.yellow;addiction to cum.@@ <<set $activeSlave.sexualFlaw = "cum addict">> <<BasicTrainingDefaulter>> <</if>> <<case "induce anal addiction">> - <<set $PC.slaving += 0.2>> The buttslut is quite pleased when you order $him to stay in your office<<if !canDoAnal($activeSlave)>>and remove $his chastity<</if>> whenever $he can for use as one of your personal anal toys. You make $his anal orgasms predictably regular, doing your best to inculcate reliance on them. <<= AnalVCheck(10)>> <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> $He enjoys all the anal attention, but will need more training to develop psychological addiction to buttsex. <<else>> + <<set $PC.slaving += 0.5>> $He begins to develop a psychological @@.yellow;addiction to anal sex.@@ <<set $activeSlave.sexualFlaw = "anal addict">> <<BasicTrainingDefaulter>> <</if>> <<case "induce attention whoring">> - <<set $PC.slaving += 0.2>> The humiliation slut is quite pleased when you order $him to stay in your office whenever $he can, and fucking $him whenever other slaves are present. You do your best to focus $his attention on how the others react to the spectacle. <<if canDoVaginal($activeSlave)>><<= VaginalVCheck(10)>><<elseif canDoAnal($activeSlave)>><<= AnalVCheck(10)>><<else>><<set $activeSlave.oralCount += 10, $oralTotal += 10>><</if>> <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> $He enjoys all the humiliation, but will need more training to become a true attention whore. <<else>> + <<set $PC.slaving += 0.5>> $He becomes a @@.yellow;true attention whore,@@ caring more about the spectators than the sex. <<set $activeSlave.sexualFlaw = "attention whore">> <<BasicTrainingDefaulter>> <</if>> <<case "induce breast growth obsession">> - <<set $PC.slaving += 0.2>> You inspect $his breasts multiple times a day, and praise $him effusively when they grow at all. You treat it as though it were something $he could control personally. <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> $He enjoys your attention to $his favorite part of $himself, but doesn't truly internalize your focus on their growth. <<else>> + <<set $PC.slaving += 0.5>> $He begins to believe you despite $himself, and becomes @@.yellow;obsessed with breast growth.@@ <<set $activeSlave.sexualFlaw = "breast growth">> <<BasicTrainingDefaulter>> <</if>> <<case "induce abusiveness">> - <<set $PC.slaving += 0.2>> The dom is gratified when you order $him to stay in your office whenever $he can to fuck any slave you feel like throwing $his way. You do your best to limit $his menu items to reluctant or even rebellious slaves, and praise $him when $he forces $himself on them. <<set $activeSlave.penetrativeCount += 20, $penetrativeTotal += 20>> <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> $He has fun, but $he continues to enjoy getting off more than getting to use bitches. $He'll need more practice. <<else>> + <<set $PC.slaving += 0.5>> $He becomes @@.yellow;sexually abusive,@@ looking over each slave that comes into your office in the hope they'll resist. <<set $activeSlave.sexualFlaw = "abusive">> <<BasicTrainingDefaulter>> <</if>> <<case "induce maliciousness">> - <<set $PC.slaving += 0.2>> The sadist is gratified when you order $him to stay in your office whenever $he can to have $his way with any slave you feel like throwing $his way. You do your best to limit $his menu items to rebellious slaves, and praise $him when $his sadism makes $him an effective punishment tool. <<set $activeSlave.penetrativeCount += 20, $penetrativeTotal += 20>> <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> $He enjoys $himself, but still betrays occasional concern when slaves are really broken by what $he does to them. $He'll need more practice. <<else>> + <<set $PC.slaving += 0.5>> $He becomes @@.yellow;sexually malicious,@@ going so far as to lick tears off $his victims' faces. <<set $activeSlave.sexualFlaw = "malicious">> <<BasicTrainingDefaulter>> <</if>> <<case "induce self hatred">> - <<set $PC.slaving += 0.2>> You order the masochist to stay in your office whenever $he's not working or resting. You fuck $him cruelly, going beyond the pain $he enjoys into harsh degradation. And every time you use $him, you make sure to tell $him how useless $he is. <<if canDoVaginal($activeSlave)>><<= VaginalVCheck(10)>><<elseif canDoAnal($activeSlave)>><<= AnalVCheck(10)>><<else>><<set $activeSlave.oralCount += 10, $oralTotal += 10>><</if>> <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> $He gets off on the pain, but $his sense of self isn't seriously affected this week. <<else>> + <<set $PC.slaving += 0.5>> $He becomes @@.yellow;sexually self hating,@@ and tearfully begs to you do worse to $him, no matter how bad it gets. <<set $activeSlave.sexualFlaw = "self hating">> <<BasicTrainingDefaulter>> <</if>> <<case "induce sexual self neglect">> - <<set $PC.slaving += 0.2>> You order the sub to stay in your office whenever $he's not working or resting, and use $his body for your pleasure. The instant you climax, you go back to your work or to another slave, treating $him like a piece of used tissue. <<if canDoVaginal($activeSlave)>><<= VaginalVCheck(10)>><<elseif canDoAnal($activeSlave)>><<= AnalVCheck(10)>><<else>><<set $activeSlave.oralCount += 10, $oralTotal += 10>><</if>> <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> $He accepts $his utterly submissive role, but $his sense of self isn't seriously affected this week. <<else>> + <<set $PC.slaving += 0.5>> $He becomes @@.yellow;sexually self neglectful,@@ and loses all expectation that those who use $him will address $his pleasure at all. <<set $activeSlave.sexualFlaw = "neglectful">> <<BasicTrainingDefaulter>> <</if>> <<case "induce breeding obsession">> - <<set $PC.slaving += 0.2>> You order the pregnant slut to stay in your office whenever $he's not working or resting. <<if $activeSlave.pregKnown == 0>>Since $he's not pregnant, you keep $him rigged up with an enormous sympathy belly when $he's there.<</if>> Rather than fucking $him, you praise $his pregnancy effusively, and only allow $him to get off when you're doing so. <<if $activeSlave.training < 100>> + <<set $PC.slaving += 0.2>> $He enjoys $himself, but mostly because of the pleasure. $He'll need more training. <<else>> + <<set $PC.slaving += 0.5>> $He develops an @@.yellow;obsession with breeding,@@ and begins to stroke $his belly in a disturbingly masturbatory way. <<set $activeSlave.sexualFlaw = "breeder">> <<BasicTrainingDefaulter>> <</if>> <</switch>> +<<set $PC.slaving = Math.clamp($PC.slaving, -100, 100)>> <<if $activeSlave.ID == $slaves[$i].ID>> <<set $slaves[$i] = $activeSlave>>