- You DO NOT need to know how to code to be able to create simple modules. However, you will need to know some javascript to be able to make more complicated modules or a personality. There are plenty of great guides on javascript out there so, I won't be covering that here.
- If you don't know what Tease AI Java is, you can see the main thread for it here.
I am ski23, creator of the Tease AI Java personality Mischevious and contributor to Tease AI Java itself. I am a senior in Computer Science at Virginia Tech, and I have real world programming job experience. Most likely any question you may have about Tease AI Java or personalities I will be able to answer.
Introduction
This is the general guide for developers for Tease AI Java. This guide is focused towards demonstrating how to create modules and personalities for Tease AI Java.
Resources
TAJUtils: TAJUtils are a series of utility files that I wrote that will allow developers to write modules and personalities quickly and easily. You can see my detailed post about TAJUtils and how to use everything provided in them here.
TAJ wiki: You can view the detailed TAJ wiki here. Some of this post repeats what is on the wiki. However, when that is the case, I tried to go into more detail or explain concepts from a different angle than the wiki.
Javascript guide: Here is a decent javascript guide. However there are plenty of others online.
Java guide: Here is a decent java guide. However there are plenty of others online.
The Developers: GodDragon and I are here to help with any questions related to TAJ and we will make sure to get an answer to your question. Don't be afraid to post or pm us with a question.
Mischevious/TAJUtils Structure and Intro
Throughout this guide, I will be explaining how to implement most concepts using TAJUtils. The reason for this is that TAJ does not have a default way to do a personality without extra coding on the developer end. If you use TAJUtils, you will not have to do this coding and it will make your life easier. All of these concepts, however, could be implemented without TAJUtils with a bit of extra code.
Here, I will outline the general structure for Mischevious (The first personality available using TAJUtils). Note that not all personalities that use TAJUtils will need to use this exact structure. However, it is the structure that made sense to me when writing Mischevious.
First, the Responses, System, and Vocabularies folder need to be in every personality.
Next, in Mischevious, I put TAJUtils in the main directory. However, it may be beneficial for some to put them in a utils folder.
The next important thing to understand is the Structure folder. This folder is the core of the structure of the personality. Inside of Structure, there is an End, Link, Modules, Start folder, and a javascript file called MischeviousStructure. This javascript file is what defines the structure of the personality to be the same as the original Tease AI. You can make your own personalities with TAJUtils that do not have the same structure as Tease AI by modifying or creating your own version of this javascript file.
The next thing to note is the End, Link, and Start Folders. Any modules you create of these types need to go in these folders, and the disabled folder inside of these folders can be used to disable certain scripts.
The next folder is the Modules folder. Inside the Modules folder is a script called ModuleSelector and several folders for different categories of modules: Fetishes, Games, Learning, LongModules, MediumModules, and ShortModules. The ModuleSelector will choose one of these folders to select a random module from as long as the folder is not empty. You may be asking, "Why not just have all of the scripts in one folder and randomly select from there?" I originally laid it out this way. However, there would be issues of if there are 10 very short scripts and 1 long script, there would be an overwhelmingly high chance that the short scripts would get run, thus making the personality more repetitive and boring.
When you create a module, simply figure out which folder it should go in and place it inside. The module will now be active and ready to run. You can put all other modules in the disabled folder temporarily to ensure that only your new module will run for testing
Part 1: Creating a simple module with TAJUtils
Here I will show you how to create a simple module with TAJUtils. First, we are going to look at emulating the structure from the original Tease AI. This is useful because it allows us to be able to use personalities from Tease AI, and have a designated structure. For those unaware, the structure of Tease AI is as follows where the section in parenthesis will repeat:
Start->(StrokeCycle->Module->Link->)->End
To emulate this structure in TeaseAI Java, the developer needs to know 2 things:
- All Start and Link modules must end with a stroking method.
- When a module starts, the sub will still be stroking. At some point, in the module, the developer needs to either make the sub stop stroking or do an edge so that at the end of the module, the sub will not be stroking.
Code: Select all
CMessage("%stopstroking%", 0);
stopStroking();
CMessage("On second thought");
startEdging();
CMessage("%stopstrokingedge%", null, false);
CMessage("%lettheedgefade%");
Let's go line by line:
Code: Select all
CMessage("%stopstroking%", 0);
Let's look at the next line now:
Code: Select all
stopStroking();
Code: Select all
CMessage("On second thought");
Code: Select all
startEdging();
Code: Select all
CMessage("%stopstrokingedge%", null, false);
Code: Select all
CMessage("%lettheedgefade%");
Congratulations! You've just learned how a simple module works. I recommend using what you've learned here to make some of your own modules and get some experience with what you've learned.
Part 2: Testing and Debugging in Tease AI Java
You've now created your first module for Tease AI Java. If you did everything perfectly, your module will run and everything will work exactly as you intended. However, we are all humans, and unfortunately no one writes perfect code on the first time every time. I'm going to teach you some basics on how to fix your code when it doesn't work how you want. The first thing you need to know is that every time Tease AI Java runs, it creates a log file in the Logs folder. You can go into this folder and look for the most recent log file and this will show you the logs for your most recent run. Let's create an error and see what happens. We are going to use our module from part 1 but make an error by misspelling CMessage:
Code: Select all
CMessag("%stopstroking%", 0);
stopStroking();
CMessage("On second thought");
startEdging();
CMessage("%stopstrokingedge%", null, false);
CMessage("%lettheedgefade%");
Code: Select all
01:09:11 PM SEVERE: Latest loaded file was 'C:\Users\ski23\Desktop\githubta\Personalities\Mischevious\Structure\Modules\ShortModules\edge_2_85.js' and error was found in line 1
Error: ReferenceError: "CMessag" is not defined in <eval> at line number 1
javax.script.ScriptException: ReferenceError: "CMessag" is not defined in <eval> at line number 1
at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.throwAsScriptException(Unknown Source)
at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(Unknown Source)
at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(Unknown Source)
at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(Unknown Source)
at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.eval(Unknown Source)
at java.scripting/javax.script.AbstractScriptEngine.eval(Unknown Source)
at me.goddragon.teaseai.api.scripts.ScriptHandler.runScript(ScriptHandler.java:142)
at me.goddragon.teaseai.api.scripts.ScriptHandler.evalScript(ScriptHandler.java:124)
at jdk.scripting.nashorn.scripts/jdk.nashorn.internal.scripts.Script$Recompilation$249$\^eval\_$cu1$restOf.:program(<eval>:39)
at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(Unknown Source)
at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ScriptFunction.invoke(Unknown Source)
at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ScriptRuntime.apply(Unknown Source)
at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(Unknown Source)
at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(Unknown Source)
at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(Unknown Source)
at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.eval(Unknown Source)
at java.scripting/javax.script.AbstractScriptEngine.eval(Unknown Source)
at me.goddragon.teaseai.api.scripts.ScriptHandler.runScript(ScriptHandler.java:142)
at me.goddragon.teaseai.api.scripts.ScriptHandler.evalScript(ScriptHandler.java:124)
at jdk.scripting.nashorn.scripts/jdk.nashorn.internal.scripts.Script$Recompilation$158$\^eval\_/1765819540.:scopeCall(<eval>)
at jdk.scripting.nashorn.scripts/jdk.nashorn.internal.scripts.Script$Recompilation$158$\^eval\_/1765819540.:program(<eval>:8)
at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(Unknown Source)
at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ScriptFunction.invoke(Unknown Source)
at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ScriptRuntime.apply(Unknown Source)
at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(Unknown Source)
at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(Unknown Source)
at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(Unknown Source)
at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.eval(Unknown Source)
at java.scripting/javax.script.AbstractScriptEngine.eval(Unknown Source)
at me.goddragon.teaseai.api.scripts.ScriptHandler.runScript(ScriptHandler.java:142)
at me.goddragon.teaseai.api.scripts.ScriptHandler.evalScript(ScriptHandler.java:124)
at jdk.scripting.nashorn.scripts/jdk.nashorn.internal.scripts.Script$Recompilation$40$\^eval\_/1119693123.:program(<eval>:10)
at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(Unknown Source)
at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ScriptFunction.invoke(Unknown Source)
at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ScriptRuntime.apply(Unknown Source)
at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(Unknown Source)
at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(Unknown Source)
at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(Unknown Source)
at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.eval(Unknown Source)
at java.scripting/javax.script.AbstractScriptEngine.eval(Unknown Source)
at me.goddragon.teaseai.api.scripts.ScriptHandler.runScript(ScriptHandler.java:142)
at me.goddragon.teaseai.api.scripts.ScriptHandler.startPersonality(ScriptHandler.java:103)
at me.goddragon.teaseai.api.session.Session$1.run(Session.java:58)
Caused by: <eval>:1 ReferenceError: "CMessag" is not defined
at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ECMAErrors.error(Unknown Source)
at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ECMAErrors.referenceError(Unknown Source)
at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ECMAErrors.referenceError(Unknown Source)
at jdk.scripting.nashorn/jdk.nashorn.internal.objects.Global.__noSuchProperty__(Unknown Source)
at jdk.scripting.nashorn.scripts/jdk.nashorn.internal.scripts.Script$Recompilation$251$\^eval\_/333258056.:program(<eval>:1)
at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(Unknown Source)
at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ScriptFunction.invoke(Unknown Source)
at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ScriptRuntime.apply(Unknown Source)
... 42 more
Code: Select all
'C:\Users\ski23\Desktop\githubta\Personalities\Mischevious\Structure\Modules\ShortModules\edge_2_85.js' and error was found in line 1
Error: ReferenceError: "CMessag" is not defined in <eval> at line number 1
Code: Select all
Caused by: <eval>:1 ReferenceError: "CMessag" is not defined
So, now you know some basics about how to track down your bugs and find them. While using log files to search for bugs is useful, often-times, code may get complicated across many files and another technique may prove useful. This technique is using debug messages in your code to be able to easily track and understand your bugs. Let me present an example module:
Code: Select all
CMessage("%stopstroking%", 0);
let x = 1;
stopStroking();
CMessage("On second thought");
if (x == 2)
{
startEdging();
}
CMessage("%stopstrokingedge%", null, false);
CMessage("%lettheedgefade%");
Code: Select all
DMessage("Beginning of module (modulename)");
CMessage("%stopstroking%", 0);
let x = 1;
stopStroking();
CMessage("On second thought");
DMessage("Value of x = " + x);
if (x == 2)
{
startEdging();
}
CMessage("%stopstrokingedge%", null, false);
CMessage("%lettheedgefade%");
DMessage("End of module (modulename)");
Part 3: Creating a More Complicated Module
After parts 1 and 2, you should be able to create, debug, and run a very simple module. Now, I'm going to teach you some more advanced methods you can use in your modules to be able to achieve more complicated designs. Here is a module from Mischevious:
Code: Select all
answer = getInput("Are you aching a lot right now %subname%?", 0);
if (answer.isLike("yes", "yea", "yep"))
{
increaseAnger(-1);
CMessage("Mmmm");
CMessage("I want you to ache <i>more<>");
startEdging();
CMessage("%stopstrokingedge%", null, false);
CMessage("%lettheedgefade%", 0);
}
else
{
CMessage("No?");
CMessage("Well I can't have that %Grin%");
increaseAnger(4);
startEdging();
if (randomInteger(0, 10) <= 6)
{
CMessage("%stopstrokingedge%", null, false);
CMessage("%lettheedgefade%", 0);
}
else
{
holdEdge();
CMessage("%stopstrokingedge%", null, false);
CMessage("%lettheedgefade%", 0);
}
}
CMessage("Don't worry %PetName%");
CMessage("There's plenty more ache where that came from %Grin%");
Code: Select all
answer = getInput("Are you aching a lot right now %subname%?", 0);
Code: Select all
if (answer.isLike("yes", "yea", "yep"))
{
increaseAnger(-1);
CMessage("Mmmm");
CMessage("I want you to ache <i>more<>");
startEdging();
CMessage("%stopstrokingedge%", null, false);
CMessage("%lettheedgefade%", 0);
}
Code: Select all
else
{
CMessage("No?");
CMessage("Well I can't have that %Grin%");
increaseAnger(4);
startEdging();
if (randomInteger(1, 10) <equalsign 7){
CMessage("%stopstrokingedge%", null, false);
CMessage("%lettheedgefade%", 0);
}
else{
holdEdge();
CMessage("%stopstrokingedge%", null, false);
CMessage("%lettheedgefade%", 0);
}
}
Part 4: Creating End Modules
End modules are very similar to the other types of modules with a few small differences. Let's look at an end module:
Code: Select all
CMessage("%TimeToFindIfYouGetToCum%");
let cumming = calculateOrgasm();
let ruining = false;
if (cumming)
{
ruining = calculateRuin();
}
if (ruining)
{
startEdging(220, "Bring yourself to the edge one more time");
let answer = getInput("%ruinyourorgasm%");
if (answer.isLike("ruined", "finished", "did")) {
CMessage("Good %Grin%");
}
else {
CMessage("Hehe just calm down now");
CMessage("I love building up all that pleasure just to snatch it away from you");
CMessage("Better luck next time");
}
}
else if (cumming)
{
startEdging(220, "Bring yourself to the edge one more time");
let answer = getInput("%cumforme%");
if (answer.isLike("came", "finished", "did")) {
CMessage("Good %Grin%");
}
else {
CMessage("You're welcome %PetName% %Grin%");
CMessage("Hehe just calm down now");
CMessage("I hope you enjoyed that orgasm %SubName%");
CMessage("Who knows how many you're actually going to get?");
}
}
else
{
startEdging(220, "Bring yourself to the edge one more time");
let answer = getInput("Put it back in your pants, you don't get to cum tonight");
CMessage("Too bad");
CMessage("Better luck next time %Grin%");
}
CMessage("Thanks for giving me such a good time tonight %PetName%");
CMessage("I can't wait to see you again %EmoteHappy%");
Part 5: Creating Responses
Now you know everything you need to know to make many modules. However, to help make the experience more like a conversation and less like a guided tour, responses are invaluable. You've already learned about using user inputs to questions the domme asks. We will refer to these as inputs. Responses are very similar to inputs; However, responses can be triggered at any time the user types the keyword(s) that trigger the response. Let's look at the example response Test.js:
Code: Select all
addResponseIndicator("this is a test");
function testResponse(message) {
if (getResponsesDisabled()) {
return false;
}
if (isEdging())
{
CMessge("edging test");
}
else if (isStroking())
{
CMessage("stroking test");
}
else
{
CMessage("test");
}
}
Code: Select all
addResponseIndicator("this is a test");
Code: Select all
addResponseRegex("test([ ])");
Code: Select all
if (getResponsesDisabled()) {
return false;
}
Code: Select all
if (isEdging())
{
CMessge("edging test");
}
else if (isStroking())
{
CMessage("stroking test");
}
else
{
CMessage("test");
}
Part 6: Creating and using vocabulary
The use of vocabulary is one of the key features of TAJ that keeps modules feeling fresh and new no matter how many times they are run. Here, I'll show you how to use and create vocabularies in a variety of ways. First, let's look at how to use vocabularies:
Code: Select all
CMessage("Hello %subname%");
Code: Select all
registerVocab("name", "bob", "bill", "joe");
Code: Select all
function goodToKnowVocabulary() {
let answers = ["Good", "Very good", "Excellent", "Perfect", "Great", "Marvelous", "Wonderful", "Splendid"];
if(randomInteger(1, 10) == 1) playSound("Audio/Spicy/QuestionAndShortWords/Good/*.mp3");
return answers[randomInteger(0, answers.length - 1)];
}
Part 7: Advanced personality creation
You should now know everything you need to know to create a personality. However, here I will teach you a few advanced principles that can be useful in personalities.
Accessing Java through scripts:
Everything you've done so far is in javascript. Javascript is a very useful scripting language, and you can do lots with it. However, there are some parts where we need to use a different language. TAJ, itself, is written in java, and it utilizes a library called Nashorn to use javascript scripts. Because of this, the javascript scripts are able to access java methods and classes. For this part, it is reccomended that you know some java. You can access any java class by referencing its path in javascript using java.path.path. Let's look at an example from TAJUtils:
Code: Select all
let separator = java.io.File.separator;
let path = "C:" + separator + "users" + separator + "username" + separator + "Desktop" + separator + "fileName"
let file = new java.io.File(path);
CMessage(file.getPath());
Using load and unload:
There isn't much to mention here beyond GodDragon's wiki page on this topic.
Auto Updating:
You can look at Mischevious or GodDragon's wiki post to see how to make your new personality automatically update with github
Using runnables for advanced scheduling:
Here is GodDragon's wiki page on this topic. Only use scheduling if you really know what you are doing.
Part 8: Style Guidelines
You now know everything you need to know to be able to create modules and even entire personalities. However, here I'm going to cover some style guidelines that you should adhere to to keep your personality or module(s) readable to other developers. In the case of Mischevious, I will not accept any modules as additions to Mischevious if they do not meet these standards. All naming needs to be meaningful and easy for a developer to understand that did not write the code. Here are the [https://google.github.io/styleguide/jsguide.html]guidelines for naming[/url].
You also must at least add a Debug message DMessage() (or another form of debug message if you don't use TAJUtils) at the beginning and end of any modules you create and use the format:
Code: Select all
DMessage("(ModuleName): Beginning");
DMessage("(ModuleName): End");
Conclusion
Congratulations on making it through this marathon of a guide (or skipping to the bottom if you're lazy). I hope you found it useful. Please post any and all questions regarding development for TAJ below.