summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2019-04-05 21:28:04 +0100
committerDan Goodliffe <dan@randomdan.homeip.net>2019-04-18 20:55:34 +0100
commitf1abde00dadf832e302827479dc386365e315f08 (patch)
tree4f4d0bff87b7da600776e7d55c3943f2e650c1ca
parentNo clamps, no preClamps play (diff)
downloadtoy-f1abde00dadf832e302827479dc386365e315f08.zip
Wrap everything in an anonymous object
-rw-r--r--scripts/toy.groovy3663
1 files changed, 1834 insertions, 1829 deletions
diff --git a/scripts/toy.groovy b/scripts/toy.groovy
index 93cd179..246dd63 100644
--- a/scripts/toy.groovy
+++ b/scripts/toy.groovy
@@ -9,1970 +9,1975 @@
// CC by-NC, see http://creativecommons.org/licenses/by-nc/3.0/
//
setInfos(9, "Toy", "Become my new plaything.", "rascalDan", "WIP", 0xFFFFFF, "en", ["bondage", "femaledom", "formale", "long", "pain", "toys", "joi"]);
-final VERSION = 1;
-final DAY = 86400;
-final HOUR = 3600.0;
-final soonFormatter = java.time.format.DateTimeFormatter.ofPattern("EEEE 'at' h:mma");
-// Notes
-// toys.<name> ankle_cuffs, ballgag, blindfold, chastity_belt, clothespins, cockring, dog_collar, handcuffs, hood, nipple_clamps, ring_gag
-final BALLGAG = "ballgag", COLLAR = "dog_collar", CLAMPS = "nipple_clamps", CHASTITY = "chastity_belt", HANDCUFFS = "handcuffs", DILDO = "dildo";
-final SPOON = "spoon";
-// fetish.<name>
-final BONDAGE = "bondage", CBT = "cbt", CHORES = "chores", PAIN = "pain";
-// toy.permission.<name>
-final CUM = "cum", EDGE = "edge"
-final PERMIT = "permit";
-final PLAY = "play";
-final PERM_CHASTE = "perm_chaste", PERM_CHASTE_ASK = "perm_chaste_ask";
-// toy.state.<name>
-final CHASTE = "chaste", COLLARED = "collared", CUFFED = "cuffed", CLAMPED = "clamped", GAGGED = "gagged", NAKED = "naked";
-final REDRESS = "redress";
-final TOYTOYS = [CUFFED, COLLARED, CLAMPED, GAGGED];
-final RELEASEFROM = "releaseFrom";
-final LUNCH = "lunch", SHOPPING = "shopping", PARTY = "party", SLEEPING = "sleeping";
-final BEDTIME = "bedtime", WAKEUP = "wakeup", BEDTIMECHECK = "bedtimeCheck";
-final BEGINPLAN = "beginPlan", ENDPLAN = "endPlan";
-final FRIENDS = [ "Tori", "Sophie", "Krystal" ];
-// toy.position
-final KNEELING = "kneeling", ALLFOURS = "allfours", STANDING = "standing";
-def OWNER = null;
-def DOMME = null;
-final SITTER = "sarah-james";
-final SOFT = "soft";
-final DATAFOLDER = getDataFolder();
-// Imagery
-final DRESSED = "dressed", TITS = "tits", PUSSY = "pussy", LINGERIE = "lingerie", TEASE = "tease", SIT = "sit", BOOTS = "boots", KNEEL = "kneel", STOOD = "stood", MEAN = "mean", CROP = "crop", ASS = "ass", SQUAT = "squat", SSSH = "sssh";
-final nDRESSED = "!$DRESSED", nTITS = "!$TITS", nTEASE = "!$TEASE";
-final IMAGEDATA = {
- return new File("$DATAFOLDER/images/toy")
- .listFiles()
- .findAll { d -> d.isDirectory(); }
- .collectEntries { d -> [
- d.getName(), [
- domme: d.getName(),
- sets: d.listFiles()
- .findAll { s -> s.isDirectory(); }
- .collect { s -> [ sub: s, f: new File(s.getPath() + "/tags")] }
- .findAll { s -> s.f.canRead() }
- .collectEntries { s -> [
- s.sub.getName(), [
- set: s.sub.getName(),
- images: s.f
- .readLines()
- .collect { l ->
- def fields = l.split(":");
- return [
- image: fields[0],
- tags: fields[1]
- .split(",")
- .findAll { t -> !t.isEmpty() }
- ];
- }
- ]
- ]}
+return new Object() {
+ final VERSION = 1;
+ final DAY = 86400;
+ final HOUR = 3600.0;
+ final soonFormatter = java.time.format.DateTimeFormatter.ofPattern("EEEE 'at' h:mma");
+ // Notes
+ // toys.<name> ankle_cuffs, ballgag, blindfold, chastity_belt, clothespins, cockring, dog_collar, handcuffs, hood, nipple_clamps, ring_gag
+ final BALLGAG = "ballgag", COLLAR = "dog_collar", CLAMPS = "nipple_clamps", CHASTITY = "chastity_belt", HANDCUFFS = "handcuffs", DILDO = "dildo";
+ final SPOON = "spoon";
+ // fetish.<name>
+ final BONDAGE = "bondage", CBT = "cbt", CHORES = "chores", PAIN = "pain";
+ // toy.permission.<name>
+ final CUM = "cum", EDGE = "edge"
+ final PERMIT = "permit";
+ final PLAY = "play";
+ final PERM_CHASTE = "perm_chaste", PERM_CHASTE_ASK = "perm_chaste_ask";
+ // toy.state.<name>
+ final CHASTE = "chaste", COLLARED = "collared", CUFFED = "cuffed", CLAMPED = "clamped", GAGGED = "gagged", NAKED = "naked";
+ final REDRESS = "redress";
+ final TOYTOYS = [CUFFED, COLLARED, CLAMPED, GAGGED];
+ final RELEASEFROM = "releaseFrom";
+ final LUNCH = "lunch", SHOPPING = "shopping", PARTY = "party", SLEEPING = "sleeping";
+ final BEDTIME = "bedtime", WAKEUP = "wakeup", BEDTIMECHECK = "bedtimeCheck";
+ final BEGINPLAN = "beginPlan", ENDPLAN = "endPlan";
+ final FRIENDS = [ "Tori", "Sophie", "Krystal" ];
+ // toy.position
+ final KNEELING = "kneeling", ALLFOURS = "allfours", STANDING = "standing";
+ def OWNER = null;
+ def DOMME = null;
+ final SITTER = "sarah-james";
+ final SOFT = "soft";
+
+ final DATAFOLDER = getDataFolder();
+ // Imagery
+ final DRESSED = "dressed", TITS = "tits", PUSSY = "pussy", LINGERIE = "lingerie", TEASE = "tease", SIT = "sit", BOOTS = "boots", KNEEL = "kneel", STOOD = "stood", MEAN = "mean", CROP = "crop", ASS = "ass", SQUAT = "squat", SSSH = "sssh";
+ final nDRESSED = "!$DRESSED", nTITS = "!$TITS", nTEASE = "!$TEASE";
+ final IMAGEDATA = {
+ return new File("$DATAFOLDER/images/toy")
+ .listFiles()
+ .findAll { d -> d.isDirectory(); }
+ .collectEntries { d -> [
+ d.getName(), [
+ domme: d.getName(),
+ sets: d.listFiles()
+ .findAll { s -> s.isDirectory(); }
+ .collect { s -> [ sub: s, f: new File(s.getPath() + "/tags")] }
+ .findAll { s -> s.f.canRead() }
+ .collectEntries { s -> [
+ s.sub.getName(), [
+ set: s.sub.getName(),
+ images: s.f
+ .readLines()
+ .collect { l ->
+ def fields = l.split(":");
+ return [
+ image: fields[0],
+ tags: fields[1]
+ .split(",")
+ .findAll { t -> !t.isEmpty() }
+ ];
+ }
+ ]
+ ]}
+ ]
]
- ]
+ };
+ }();
+ def loadDomme = { domme, set = null ->
+ final readDomme = { path ->
+ if (!path) return [:];
+ final f = new File(path);
+ if (!f.exists()) return [:];
+ return Eval.me(f.text);
};
-}();
-def loadDomme = { domme, set = null ->
- final readDomme = { path ->
- if (!path) return [:];
- final f = new File(path);
- if (!f.exists()) return [:];
- return Eval.me(f.text);
- };
- return [
- "$DATAFOLDER/images/toy/domme.groovy",
- "$DATAFOLDER/images/toy/$domme/person.groovy",
- "$DATAFOLDER/images/toy/$domme/$set/set.groovy" ]
- .collect { readDomme(it) }
- .sum()
-};
-def selectImage = { domme, set, spec ->
- def meets = { i ->
- return spec.every({ s ->
- return (s[0] == "!") ? i.tags.indexOf(s.drop(1)) == -1 : i.tags.indexOf(s) != -1;
- });
+ return [
+ "$DATAFOLDER/images/toy/domme.groovy",
+ "$DATAFOLDER/images/toy/$domme/person.groovy",
+ "$DATAFOLDER/images/toy/$domme/$set/set.groovy" ]
+ .collect { readDomme(it) }
+ .sum()
};
- def matches = IMAGEDATA[domme];
- if (!matches) return null;
- matches = matches.sets[set];
- if (!matches) return null;
- matches = matches
- .images.findAll({ i -> meets(i) });
- if (matches.isEmpty()) return null;
- return matches[getRandom(matches.size())];
-};
-def showImage = { spec ->
- def outfit = loadString("toy.owner.outfit");
- def image = selectImage(OWNER, outfit, spec);
- if (image) {
- setImage("toy/$OWNER/$outfit/${image.image}.jpg");
- return image.tags;
- }
- else {
- setImage(null);
- return null;
- }
-};
-def showLounge = {
- setImage("toy/$OWNER/lounge.jpg");
-};
-def selectImageSet = { domme, specs ->
- def matches = IMAGEDATA[domme];
- if (!matches) return null;
- matches = matches.sets.values().findAll({ s -> specs.every({ spec -> selectImage(domme, s.set, spec)})});
- return matches[getRandom(matches.size())];
-};
-def dress = { specs ->
- def outfit = loadString("toy.owner.outfit");
- def outfitTime = loadInteger("toy.owner.outfitTime");
- if (outfitTime > getTime() - 7200) { // Recent, check
- def prev = IMAGEDATA[OWNER];
- if (prev) {
- prev = prev.sets[outfit];
- if (prev && specs.every({ spec -> selectImage(OWNER, prev.set, spec)})) {
- DOMME = loadDomme(OWNER, outfit);
- return outfit;
+ def selectImage = { domme, set, spec ->
+ def meets = { i ->
+ return spec.every({ s ->
+ return (s[0] == "!") ? i.tags.indexOf(s.drop(1)) == -1 : i.tags.indexOf(s) != -1;
+ });
+ };
+ def matches = IMAGEDATA[domme];
+ if (!matches) return null;
+ matches = matches.sets[set];
+ if (!matches) return null;
+ matches = matches
+ .images.findAll({ i -> meets(i) });
+ if (matches.isEmpty()) return null;
+ return matches[getRandom(matches.size())];
+ };
+ def showImage = { spec ->
+ def outfit = loadString("toy.owner.outfit");
+ def image = selectImage(OWNER, outfit, spec);
+ if (image) {
+ setImage("toy/$OWNER/$outfit/${image.image}.jpg");
+ return image.tags;
+ }
+ else {
+ setImage(null);
+ return null;
+ }
+ };
+ def showLounge = {
+ setImage("toy/$OWNER/lounge.jpg");
+ };
+ def selectImageSet = { domme, specs ->
+ def matches = IMAGEDATA[domme];
+ if (!matches) return null;
+ matches = matches.sets.values().findAll({ s -> specs.every({ spec -> selectImage(domme, s.set, spec)})});
+ return matches[getRandom(matches.size())];
+ };
+ def dress = { specs ->
+ def outfit = loadString("toy.owner.outfit");
+ def outfitTime = loadInteger("toy.owner.outfitTime");
+ if (outfitTime > getTime() - 7200) { // Recent, check
+ def prev = IMAGEDATA[OWNER];
+ if (prev) {
+ prev = prev.sets[outfit];
+ if (prev && specs.every({ spec -> selectImage(OWNER, prev.set, spec)})) {
+ DOMME = loadDomme(OWNER, outfit);
+ return outfit;
+ }
}
}
- }
- outfit = selectImageSet(OWNER, specs);
- if (!outfit) {
- showPopup("No outfit for $OWNER : $specs");
- save("toy.owner.outfit", null);
- save("toy.owner.outfitTime", null);
- DOMME = loadDomme(OWNER, outfit);
- return;
- }
- save("toy.owner.outfit", outfit.set);
- save("toy.owner.outfitTime", getTime());
- DOMME = loadDomme(OWNER, outfit.set);
-};
-// Utils
-def localTimeOffset = {
- return java.time.ZoneId.systemDefault()
- .getRules()
- .getOffset(java.time.Instant.now())
- .getTotalSeconds();
-};
-def localTimeOf = { s ->
- java.time.LocalDateTime.ofInstant(
- java.time.Instant.ofEpochSecond(s), java.time.ZoneId.systemDefault())
-}
-def localTime = {
- // A float between 4.0 (4am) and 28.0 (4am)
- def wallclock = ((getTime() + localTimeOffset()) % DAY) / HOUR;
- if (wallclock < 4) {
- wallclock += 24;
- }
- return wallclock;
-};
-def getDay = { (int)(getTime() / DAY) * DAY };
-def getProp = {i, f, d = null ->
- final v = f("toy.$i".toString());
- if (v == null) return d;
- return v;
-};
-def getDommeProp = { i, d = null ->
- if (DOMME == null) return d;
- final v = DOMME[i];
- if (v == null) return d;
- return v;
-};
-def dommeTitle = { getDommeProp("title", "Mistress") };
-def dommeName = { getDommeProp("name", "") };
-def loadB = { p -> loadBoolean(p)};
-def loadI = { p -> loadInteger(p)};
-def loadS = { p -> loadString(p)};
-def setProp = {i, v -> save("toy.$i".toString(), v)};
-def has = {i -> loadBoolean("toys.$i") == true};
-def likes = {i -> loadBoolean("fetish.$i") == true};
-def can = {i -> loadBoolean("toy.permission.$i") == true};
-def perm = can;
-def getPermission = {i -> getProp("permission.$i", loadB)};
-def setPermission = {i, v -> setProp("permission.$i", v)};
-def givePermission = {i -> setPermission(i, true)};
-def revokePermission = {i -> setPermission(i, false)};
-def is = {i -> loadBoolean("toy.state.$i") == true};
-def set = {i, s -> save("toy.state.$i", s)};
-def positioned = { i -> loadString("toy.position") == i };
-def getPunish = { loadInteger("toy.punishment") ?: 0; };
-def adjustPunish = { p -> save("toy.punishment", Math.max(getPunish() + (int)p, 0)); };
-def getAway = { loadString("toy.owner.away") };
-def setAway = { a -> save("toy.owner.away", a) };
-def randRange = { min, max -> (int)min + getRandom((int)(1 + max - min)) }
-def namedEvents;
-def loadEvents = {
- return (loadMap("toy.events") ?: [:]);
-}
-def saveEvents = { events ->
- save("toy.events", events);
-}
-def nextEvent = { events ->
- def first = null;
- events.each{ k, v ->
- if (!first || first.event.time > v.time) {
- first = [ name: k, event: v ];
- }
- };
- return first;
-};
-def setEvent = { events, name, time, func, arg = null ->
- if (namedEvents.containsKey(func)) {
- events[name] = [
- time: time,
- func: func,
- arg: arg
- ];
- saveEvents(events);
- return true;
- }
- else {
- showPopup("No such event $func");
- return false;
- }
-};
-def addEvent = { name, time, func, arg = null ->
- def events = loadEvents();
- return setEvent(events, name, time, func, arg);
-}
-def addEventIfMissing = { name, time, func, arg = null ->
- def events = loadEvents();
- if (!events.containsKey(name)) {
+ outfit = selectImageSet(OWNER, specs);
+ if (!outfit) {
+ showPopup("No outfit for $OWNER : $specs");
+ save("toy.owner.outfit", null);
+ save("toy.owner.outfitTime", null);
+ DOMME = loadDomme(OWNER, outfit);
+ return;
+ }
+ save("toy.owner.outfit", outfit.set);
+ save("toy.owner.outfitTime", getTime());
+ DOMME = loadDomme(OWNER, outfit.set);
+ };
+ // Utils
+ def localTimeOffset = {
+ return java.time.ZoneId.systemDefault()
+ .getRules()
+ .getOffset(java.time.Instant.now())
+ .getTotalSeconds();
+ };
+ def localTimeOf = { s ->
+ java.time.LocalDateTime.ofInstant(
+ java.time.Instant.ofEpochSecond(s), java.time.ZoneId.systemDefault())
+ }
+ def localTime = {
+ // A float between 4.0 (4am) and 28.0 (4am)
+ def wallclock = ((getTime() + localTimeOffset()) % DAY) / HOUR;
+ if (wallclock < 4) {
+ wallclock += 24;
+ }
+ return wallclock;
+ };
+ def getDay = { (int)(getTime() / DAY) * DAY };
+ def getProp = {i, f, d = null ->
+ final v = f("toy.$i".toString());
+ if (v == null) return d;
+ return v;
+ };
+ def getDommeProp = { i, d = null ->
+ if (DOMME == null) return d;
+ final v = DOMME[i];
+ if (v == null) return d;
+ return v;
+ };
+ def dommeTitle = { getDommeProp("title", "Mistress") };
+ def dommeName = { getDommeProp("name", "") };
+ def loadB = { p -> loadBoolean(p)};
+ def loadI = { p -> loadInteger(p)};
+ def loadS = { p -> loadString(p)};
+ def setProp = {i, v -> save("toy.$i".toString(), v)};
+ def has = {i -> loadBoolean("toys.$i") == true};
+ def likes = {i -> loadBoolean("fetish.$i") == true};
+ def can = {i -> loadBoolean("toy.permission.$i") == true};
+ def perm = can;
+ def getPermission = {i -> getProp("permission.$i", loadB)};
+ def setPermission = {i, v -> setProp("permission.$i", v)};
+ def givePermission = {i -> setPermission(i, true)};
+ def revokePermission = {i -> setPermission(i, false)};
+ def is = {i -> loadBoolean("toy.state.$i") == true};
+ def set = {i, s -> save("toy.state.$i", s)};
+ def positioned = { i -> loadString("toy.position") == i };
+ def getPunish = { loadInteger("toy.punishment") ?: 0; };
+ def adjustPunish = { p -> save("toy.punishment", Math.max(getPunish() + (int)p, 0)); };
+ def getAway = { loadString("toy.owner.away") };
+ def setAway = { a -> save("toy.owner.away", a) };
+ def randRange = { min, max -> (int)min + getRandom((int)(1 + max - min)) }
+ def loadEvents = {
+ return (loadMap("toy.events") ?: [:]);
+ }
+ def saveEvents = { events ->
+ save("toy.events", events);
+ }
+ def nextEvent = { events ->
+ def first = null;
+ events.each{ k, v ->
+ if (!first || first.event.time > v.time) {
+ first = [ name: k, event: v ];
+ }
+ };
+ return first;
+ };
+ def setEvent = { events, name, time, func, arg = null ->
+ if (namedEvents.containsKey(func)) {
+ events[name] = [
+ time: time,
+ func: func,
+ arg: arg
+ ];
+ saveEvents(events);
+ return true;
+ }
+ else {
+ showPopup("No such event $func");
+ return false;
+ }
+ };
+ def addEvent = { name, time, func, arg = null ->
+ def events = loadEvents();
return setEvent(events, name, time, func, arg);
}
-};
-def removeEvent = { name ->
- def events = loadEvents();
- events.remove(name);
- saveEvents(events);
-};
-def execEvents = { rt ->
- for (def e = nextEvent(loadEvents()); e && e.event.time <= getTime(); e = nextEvent(loadEvents())) {
- def f = namedEvents[e.event.func];
- removeEvent(e.name);
- if (f) {
- f(e.name, e.event.arg, e.event.time, rt);
+ def addEventIfMissing = { name, time, func, arg = null ->
+ def events = loadEvents();
+ if (!events.containsKey(name)) {
+ return setEvent(events, name, time, func, arg);
}
- }
-};
-def sessionAborted = null;
-def sessionToys = [:];
-def gagText = { t, p ->
- if (!is(GAGGED)) return t.toString();
- return t.split(/\s+/)
- .collect {
- 'm' * getRandom((int)Math.max(1.0, it.length() * 1.0)) +
- 'p' * getRandom((int)Math.max(1.0, it.length() * 0.4)) +
- 'h' * getRandom((int)Math.max(1.0, it.length() * 0.8))
- }
- .join(" ")
- .capitalize() + " ($p)";
-};
-def showButtonG = { s, p, t = null ->
- return t != null ? showButton(gagText(s, p), t) : showButton(gagText(s, p));
-};
-def compose = { texts ->
- if (!texts || texts.isEmpty()) return null;
- return texts.collect {
- t -> t[getRandom(t.size())]
- }.join(" ").capitalize();
-};
-def present = { imageSpec, texts ->
- if (texts) {
- show(compose(texts));
- }
- if (imageSpec) {
- return showImage(imageSpec);
- }
- return null;
-};
-def showButtonGT = { s, p, t, pc ->
- def tt = showButton(gagText(s, p), t);
- if (tt == t) {
- present(null, [
- ["Don't keep me waiting!", "Hurry up!", "Quicker, toy!"]]);
- def pt = showButton(gagText(s, p));
- adjustPunish(pt * pc);
- return pt + tt;
- }
- return tt;
-};
-def imageTagsComment = { tags ->
- if (!tags || tags.isEmpty()) return null;
- tags = tags.intersect([ASS, CROP, BOOTS, PUSSY, SSSH])
- if (tags.isEmpty()) return null;
- Collections.shuffle(tags);
- switch (tags[0]) {
- case ASS:
- if (!is(GAGGED))
- return compose([
- ["Come closer,", "Don't be shy,"],
- ["kiss it!", "two kisses on each cheek."]]);
- else
- return compose([
- ["Too bad you can't kiss it like that.", "Maybe I should ungag you so you can kiss it?"]]);
- break;
- case CROP:
- return compose([
- ["You know what this is for?", "Good boys get rewards, bad ones getting a beating.", "Would you like your ass a darker shade?"]]);
- break;
- case BOOTS:
- if (is(GAGGED))
- return compose([
- ["I know you'd like to worship them.", "Too bad that tongue can't be put to good use."]]);
- else
- return compose([
- ["Get down there, worship my boots.", "See any dirt on my boots? Maybe you should lick them clean!"]]);
- case PUSSY:
- if (is(GAGGED))
+ };
+ def removeEvent = { name ->
+ def events = loadEvents();
+ events.remove(name);
+ saveEvents(events);
+ };
+ def execEvents = { rt ->
+ for (def e = nextEvent(loadEvents()); e && e.event.time <= getTime(); e = nextEvent(loadEvents())) {
+ def f = namedEvents[e.event.func];
+ removeEvent(e.name);
+ if (f) {
+ f(e.name, e.event.arg, e.event.time, rt);
+ }
+ }
+ };
+ def sessionAborted = null;
+ def sessionToys = [:];
+ def gagText = { t, p ->
+ if (!is(GAGGED)) return t.toString();
+ return t.split(/\s+/)
+ .collect {
+ 'm' * getRandom((int)Math.max(1.0, it.length() * 1.0)) +
+ 'p' * getRandom((int)Math.max(1.0, it.length() * 0.4)) +
+ 'h' * getRandom((int)Math.max(1.0, it.length() * 0.8))
+ }
+ .join(" ")
+ .capitalize() + " ($p)";
+ };
+ def showButtonG = { s, p, t = null ->
+ return t != null ? showButton(gagText(s, p), t) : showButton(gagText(s, p));
+ };
+ def compose = { texts ->
+ if (!texts || texts.isEmpty()) return null;
+ return texts.collect {
+ t -> t[getRandom(t.size())]
+ }.join(" ").capitalize();
+ };
+ def present = { imageSpec, texts ->
+ if (texts) {
+ show(compose(texts));
+ }
+ if (imageSpec) {
+ return showImage(imageSpec);
+ }
+ return null;
+ };
+ def showButtonGT = { s, p, t, pc ->
+ def tt = showButton(gagText(s, p), t);
+ if (tt == t) {
+ present(null, [
+ ["Don't keep me waiting!", "Hurry up!", "Quicker, toy!"]]);
+ def pt = showButton(gagText(s, p));
+ adjustPunish(pt * pc);
+ return pt + tt;
+ }
+ return tt;
+ };
+ def imageTagsComment = { tags ->
+ if (!tags || tags.isEmpty()) return null;
+ tags = tags.intersect([ASS, CROP, BOOTS, PUSSY, SSSH])
+ if (tags.isEmpty()) return null;
+ Collections.shuffle(tags);
+ switch (tags[0]) {
+ case ASS:
+ if (!is(GAGGED))
+ return compose([
+ ["Come closer,", "Don't be shy,"],
+ ["kiss it!", "two kisses on each cheek."]]);
+ else
+ return compose([
+ ["Too bad you can't kiss it like that.", "Maybe I should ungag you so you can kiss it?"]]);
+ break;
+ case CROP:
return compose([
- ["I know you'd like to pleasure me.", "Too bad that tongue can't be put to good use."]]);
- else
+ ["You know what this is for?", "Good boys get rewards, bad ones getting a beating.", "Would you like your ass a darker shade?"]]);
+ break;
+ case BOOTS:
+ if (is(GAGGED))
+ return compose([
+ ["I know you'd like to worship them.", "Too bad that tongue can't be put to good use."]]);
+ else
+ return compose([
+ ["Get down there, worship my boots.", "See any dirt on my boots? Maybe you should lick them clean!"]]);
+ case PUSSY:
+ if (is(GAGGED))
+ return compose([
+ ["I know you'd like to pleasure me.", "Too bad that tongue can't be put to good use."]]);
+ else
+ return compose([
+ ["How about you start licking it?", "How much would like your tongue in there?"]]);
+ break;
+ case SSSH:
return compose([
- ["How about you start licking it?", "How much would like your tongue in there?"]]);
- break;
- case SSSH:
- return compose([
- ["Quiet now.", "Sssssh.", "Patience."]]);
- break;
- }
- return null;
-};
-def harden = { imageSpec ->
- present(imageSpec, [
- ["I want to see you hard.", "I need you hard now, very hard."],
- ["Stroke it, slowly...", "Slow worship strokes..."],
- ["don't edge...", "no edging..."],
- ["and do NOT cum.", "and definitely no cumming."],
- ["Not yet.", "Maybe soon."]]);
- playBackgroundSound("toy/90bpm.mp3", 2); //45sec
- if (showButtonG("Hard, ${dommeTitle()}", "hard", 60) == 60) {
- playBackgroundSound(null);
+ ["Quiet now.", "Sssssh.", "Patience."]]);
+ break;
+ }
+ return null;
+ };
+ def harden = { imageSpec ->
present(imageSpec, [
- ["What's taking so long!?", "Come on!", "Don't disappoint me."],
- ["Slap it about a bit!.", "Get it hard, now!", "Pinch your nipples."]]);
- playBackgroundSound("toy/165bpm.mp3");
- if (showButtonG("Hard, ${dommeTitle()}", "hard", 30) == 30) {
- playBackgroundSound("toy/180bpm.mp3");
+ ["I want to see you hard.", "I need you hard now, very hard."],
+ ["Stroke it, slowly...", "Slow worship strokes..."],
+ ["don't edge...", "no edging..."],
+ ["and do NOT cum.", "and definitely no cumming."],
+ ["Not yet.", "Maybe soon."]]);
+ playBackgroundSound("toy/90bpm.mp3", 2); //45sec
+ if (showButtonG("Hard, ${dommeTitle()}", "hard", 60) == 60) {
+ playBackgroundSound(null);
+ present(imageSpec, [
+ ["What's taking so long!?", "Come on!", "Don't disappoint me."],
+ ["Slap it about a bit!.", "Get it hard, now!", "Pinch your nipples."]]);
+ playBackgroundSound("toy/165bpm.mp3");
if (showButtonG("Hard, ${dommeTitle()}", "hard", 30) == 30) {
- sessionAborted = SOFT;
- present(imageSpec, [
- ["Bah!", "Pathetic!"],
- ["That's no good to me!", "How do I have fun with that!?"]]);
- adjustPunish(100);
- showButtonG("Sorry, ${dommeTitle()}", "sorry");
+ playBackgroundSound("toy/180bpm.mp3");
+ if (showButtonG("Hard, ${dommeTitle()}", "hard", 30) == 30) {
+ sessionAborted = SOFT;
+ present(imageSpec, [
+ ["Bah!", "Pathetic!"],
+ ["That's no good to me!", "How do I have fun with that!?"]]);
+ adjustPunish(100);
+ showButtonG("Sorry, ${dommeTitle()}", "sorry");
+ }
}
}
- }
- playBackgroundSound(null);
-};
-def expose = { imageSpec ->
- if (!is(NAKED)) {
- present(imageSpec, [
- ["Get that cock out, toy;", "Let's see that cock of mine."],
- ["I want to torment it.", "It's playtime!"]]);
- wait(10);
- }
-};
-// Return whether toy came or not
-def mightCum = { time, lenient = false, reason = "without permission" ->
- final taken = showButtonG("Sorry, ${dommeTitle()}, I'm cumming $reason", "cumming", time);
- if (taken < time) {
playBackgroundSound(null);
- if (lenient && taken < 2) {
- present(null, [
- ["Awww.", "Damn."],
- ["That was close;", "I'll let you have that one;"],
- ["And I was looking forward to punishing you.", "No punishment this time."]]);
+ };
+ def expose = { imageSpec ->
+ if (!is(NAKED)) {
+ present(imageSpec, [
+ ["Get that cock out, toy;", "Let's see that cock of mine."],
+ ["I want to torment it.", "It's playtime!"]]);
+ wait(10);
}
- else {
- present(null, [
- ["Bah!", "Pfft. I'm very disappointed in you."],
- ["Ruin it.", "Don't touch it."]]);
- sessionAborted = CUM;
- adjustPunish(80);
+ };
+ // Return whether toy came or not
+ def mightCum = { time, lenient = false, reason = "without permission" ->
+ final taken = showButtonG("Sorry, ${dommeTitle()}, I'm cumming $reason", "cumming", time);
+ if (taken < time) {
+ playBackgroundSound(null);
+ if (lenient && taken < 2) {
+ present(null, [
+ ["Awww.", "Damn."],
+ ["That was close;", "I'll let you have that one;"],
+ ["And I was looking forward to punishing you.", "No punishment this time."]]);
+ }
+ else {
+ present(null, [
+ ["Bah!", "Pfft. I'm very disappointed in you."],
+ ["Ruin it.", "Don't touch it."]]);
+ sessionAborted = CUM;
+ adjustPunish(80);
+ }
+ adjustPunish(taken * 10);
+ wait(10);
+ present([DRESSED], [["Clean up your mess!"]]);
+ showButtonG("Yes, ${dommeTitle()}", "ok");
+ wait(10);
+ showButtonG("Cleaned up, ${dommeTitle()}, back", "back");
+ return true;
}
- adjustPunish(taken * 10);
- wait(10);
- present([DRESSED], [["Clean up your mess!"]]);
- showButtonG("Yes, ${dommeTitle()}", "ok");
+ return false;
+ };
+ // Return whether toy came or not, despite being denied
+ def cumChanceDenied = { lenient = false ->
+ present([TEASE], [
+ ["Stop!", "Nope!", "Haha! No!"],
+ ["Let go.", "Hands off!", "Hands behind your back."],
+ ["Not this time.", "Maaaaybe next time, toy."]]);
+ return mightCum(15, lenient);
+ };
+ def cumChanceCountdown = {
+ present([TEASE], [
+ ["OK, toy, I'm going to count you down.", "Would you like a countdown, toy?"],
+ ["Get stroking!", "Jerk it!"]]);
+ if (mightCum(5 + getRandom(5))) return true;
+ present([TITS], []);
+ def numbers = "";
+ for (def n = 10; n > 0; n--) {
+ numbers += "${n}... ";
+ show(numbers);
+ mightCum(1, false, "too soon");
+ if (getRandom(100) > 85 || !can(CUM)) {
+ return cumChanceDenied();
+ }
+ }
+ present([TITS], [
+ ["Cum, cum", "Cum for me"],
+ ["you little slut.", "my lucky toy.", "you dirty boy."]]);
wait(10);
- showButtonG("Cleaned up, ${dommeTitle()}, back", "back");
+ showButtonG("Thank you, ${dommeTitle()}.", "ok");
return true;
- }
- return false;
-};
-// Return whether toy came or not, despite being denied
-def cumChanceDenied = { lenient = false ->
- present([TEASE], [
- ["Stop!", "Nope!", "Haha! No!"],
- ["Let go.", "Hands off!", "Hands behind your back."],
- ["Not this time.", "Maaaaybe next time, toy."]]);
- return mightCum(15, lenient);
-};
-def cumChanceCountdown = {
- present([TEASE], [
- ["OK, toy, I'm going to count you down.", "Would you like a countdown, toy?"],
- ["Get stroking!", "Jerk it!"]]);
- if (mightCum(5 + getRandom(5))) return true;
- present([TITS], []);
- def numbers = "";
- for (def n = 10; n > 0; n--) {
- numbers += "${n}... ";
- show(numbers);
- mightCum(1, false, "too soon");
- if (getRandom(100) > 85 || !can(CUM)) {
+ };
+ def cumChanceWindow = {
+ present([TEASE], [
+ ["OK, toy, I'm going to give you a chance to cum.", "Would you like a small chance to cum, toy?"],
+ ["Get stroking!", "Stroke it, you'll need to be close!"],
+ ["You won't get long.", "You might not get long.", "Wait for my say so..."]]);
+ if (mightCum(15 + getRandom(60), false, "too soon")) return true;
+ if (getRandom(5) > 0 || !can(CUM)) {
return cumChanceDenied();
}
- }
- present([TITS], [
- ["Cum, cum", "Cum for me"],
- ["you little slut.", "my lucky toy.", "you dirty boy."]]);
- wait(10);
- showButtonG("Thank you, ${dommeTitle()}.", "ok");
- return true;
-};
-def cumChanceWindow = {
- present([TEASE], [
- ["OK, toy, I'm going to give you a chance to cum.", "Would you like a small chance to cum, toy?"],
- ["Get stroking!", "Stroke it, you'll need to be close!"],
- ["You won't get long.", "You might not get long.", "Wait for my say so..."]]);
- if (mightCum(15 + getRandom(60), false, "too soon")) return true;
- if (getRandom(5) > 0 || !can(CUM)) {
- return cumChanceDenied();
- }
- present([TITS], [
- ["Cum, cum", "Cum for me"],
- ["you little slut.", "my lucky toy.", "you dirty boy."]]);
- def w = 4 + getRandom(4);
- if (showButtonG("Cumming, ${dommeTitle()}", "cumming", w) == w) {
- w = 3;
- present(null, [
- ["Quickly now!", "Hurry!"]]);
+ present([TITS], [
+ ["Cum, cum", "Cum for me"],
+ ["you little slut.", "my lucky toy.", "you dirty boy."]]);
+ def w = 4 + getRandom(4);
if (showButtonG("Cumming, ${dommeTitle()}", "cumming", w) == w) {
- present([TEASE], [
- ["Stop!", "Let go.", "Hands off!"],
- ["Time's up!", "You had your chance."]]);
- return mightCum(15, true, "too late");
+ w = 3;
+ present(null, [
+ ["Quickly now!", "Hurry!"]]);
+ if (showButtonG("Cumming, ${dommeTitle()}", "cumming", w) == w) {
+ present([TEASE], [
+ ["Stop!", "Let go.", "Hands off!"],
+ ["Time's up!", "You had your chance."]]);
+ return mightCum(15, true, "too late");
+ }
}
- }
- wait(10);
- showButtonG("Thank you, ${dommeTitle()}.", "ok");
- return true;
-};
-def cumChanceRuin = {
- present([TEASE], [
- ["Stroke!", "Jerk it."],
- ["Get close to the edge, toy...", "Get yourself close..."]]);
- if (mightCum(5 + getRandom(10), false, "too soon")) return true;
- if (getRandom(5) > 0 || !can(CUM)) {
- return cumChanceDenied();
- }
- for (def n = 3 + getRandom(6); n >= 0; n--) {
- present([TITS], [
- ["Try to cum!"]]);
- def w = 3 + getRandom(8);
- if (showButtonG("Cumming, ${dommeTitle()}", "cumming", w) < w) {
- present([TEASE], [
- ["Hands off!", "Leave it."],
- ["Let it all ooze out.", "You're not getting a proper release."]]);
- wait(10);
- showButtonG("Thank you, ${dommeTitle()}.", "ok");
- return true;
+ wait(10);
+ showButtonG("Thank you, ${dommeTitle()}.", "ok");
+ return true;
+ };
+ def cumChanceRuin = {
+ present([TEASE], [
+ ["Stroke!", "Jerk it."],
+ ["Get close to the edge, toy...", "Get yourself close..."]]);
+ if (mightCum(5 + getRandom(10), false, "too soon")) return true;
+ if (getRandom(5) > 0 || !can(CUM)) {
+ return cumChanceDenied();
}
- if (n > 0) {
+ for (def n = 3 + getRandom(6); n >= 0; n--) {
present([TITS], [
- ["Stop!", "Not now!", "Wait!"],
- ["Hands off!", "Hands by your side."]]);
- w = (w - 2) + getRandom(8);
- if (mightCum(w, true, "but it's ruined")) return true;
+ ["Try to cum!"]]);
+ def w = 3 + getRandom(8);
+ if (showButtonG("Cumming, ${dommeTitle()}", "cumming", w) < w) {
+ present([TEASE], [
+ ["Hands off!", "Leave it."],
+ ["Let it all ooze out.", "You're not getting a proper release."]]);
+ wait(10);
+ showButtonG("Thank you, ${dommeTitle()}.", "ok");
+ return true;
+ }
+ if (n > 0) {
+ present([TITS], [
+ ["Stop!", "Not now!", "Wait!"],
+ ["Hands off!", "Hands by your side."]]);
+ w = (w - 2) + getRandom(8);
+ if (mightCum(w, true, "but it's ruined")) return true;
+ }
}
- }
- return cumChanceDenied(true);
-};
-def edge = { amount, imageSpec ->
- def allowedTime = 128;
- (getRandom(amount) + 2).times {
- if (sessionAborted) return;
- present(imageSpec, [
- ["Stroke to edge now, toy...", "Edge!"],
- ["Don't cum.", "No cumming.", "No accidents though."]]);
- showButtonGT("Edging, ${dommeTitle()}", "edging", allowedTime + 20, 1);
- if (getRandom(2) == 1) {
+ return cumChanceDenied(true);
+ };
+ def edge = { amount, imageSpec ->
+ def allowedTime = 128;
+ (getRandom(amount) + 2).times {
+ if (sessionAborted) return;
present(imageSpec, [
- ["Hold it...", "And hold...", "Keeping going..."]]);
- if (mightCum(getRandom(20) + 5)) return;
- }
- present(imageSpec, [
- ["Hands off!", "Stop!"]]);
- if (mightCum(getRandom(5) + 5)) return;
- allowedTime /= 2;
- };
-};
-def strokes = { amount, imageSpec ->
- def tags = present(imageSpec, [
- ["Stroke to the beat, toy.", "Follow the beat.", "Beat it!"],
- ["No cumming unless I say so...", "Don't cum without my say so,"],
- ["Tell me if you get too close.", "so tell me if you're edging.", "I don't want any messes."]]);
- final BEATS = [
- // bpm:30, len:60 ],
- [ bpm:90, len:45 ],
- [ bpm:165, len:30 ],
- [ bpm:180, len:30 ],
- [ bpm:240, len:20 ],
- ];
- def sto = loadInteger("toy.strokeTeaseOffset");
- def edges = 0;
- def itr = 0;
- (getRandom(amount) + 5).times {
- if (sessionAborted) return;
- switch (itr) {
- case 2:
- final cmt = imageTagsComment(tags);
- if (cmt) {
- show(cmt);
- }
- break;
- case 4:
- present(null, [
- ["Don't stop stroking!", "Keep jerking.", "Keep stroking."]]);
- break;
- }
- itr += 1;
- def beatNo = getRandom(BEATS.size());
- def beat = BEATS[beatNo];
- playBackgroundSound("toy/${beat.bpm}bpm.mp3", 10); // Lots, to cover offset
- def len = getRandom(Math.max(5, beat.len + (sto * beatNo)));
- if (showButtonG("Edging, ${dommeTitle()}", "edging", len) < len) {
- sto -= 1;
- edges += 1;
- itr = 0;
- playBackgroundSound(null);
- switch (getRandom(3)) {
- case 0:
- present(imageSpec, [
- ["Stop!", "Let go!", "Hands off!"]]);
- if (mightCum(getRandom(8) + 10)) return;
- break;
- case 1:
- present(imageSpec, [
- ["Careful now...", "No accidents..."],
- ["slow it down...", "slowly now..."]]);
- playBackgroundSound("toy/30bpm.mp3");
- if (mightCum(getRandom(20) + 5)) {
- playBackgroundSound(null);
- return;
- }
+ ["Stroke to edge now, toy...", "Edge!"],
+ ["Don't cum.", "No cumming.", "No accidents though."]]);
+ showButtonGT("Edging, ${dommeTitle()}", "edging", allowedTime + 20, 1);
+ if (getRandom(2) == 1) {
+ present(imageSpec, [
+ ["Hold it...", "And hold...", "Keeping going..."]]);
+ if (mightCum(getRandom(20) + 5)) return;
+ }
+ present(imageSpec, [
+ ["Hands off!", "Stop!"]]);
+ if (mightCum(getRandom(5) + 5)) return;
+ allowedTime /= 2;
+ };
+ };
+ def strokes = { amount, imageSpec ->
+ def tags = present(imageSpec, [
+ ["Stroke to the beat, toy.", "Follow the beat.", "Beat it!"],
+ ["No cumming unless I say so...", "Don't cum without my say so,"],
+ ["Tell me if you get too close.", "so tell me if you're edging.", "I don't want any messes."]]);
+ final BEATS = [
+ // bpm:30, len:60 ],
+ [ bpm:90, len:45 ],
+ [ bpm:165, len:30 ],
+ [ bpm:180, len:30 ],
+ [ bpm:240, len:20 ],
+ ];
+ def sto = loadInteger("toy.strokeTeaseOffset");
+ def edges = 0;
+ def itr = 0;
+ (getRandom(amount) + 5).times {
+ if (sessionAborted) return;
+ switch (itr) {
case 2:
- switch(getSelectedValue("Would you like to cum, toy?", [
- gagText("Please, ${dommeTitle()}, may I cum!?", "yes"),
- gagText("No, ${dommeTitle()}, please torment me more!", "no")
- ])) {
- case 0:
- if (can(CUM)) {
- present(imageSpec, [
- ["Maybe...", "Perhaps.", "We'll see."]]);
- }
- else {
- present(imageSpec, [
- ["No you may not!", "Nope.", "Not a chance."]]);
- adjustPunish(5);
- }
- break;
- case 1:
- present(imageSpec, [
- ["Good boy.", "Very well.", "OK then!"]]);
- adjustPunish(-5);
- break;
+ final cmt = imageTagsComment(tags);
+ if (cmt) {
+ show(cmt);
}
- if (mightCum(getRandom(8) + 5)) {
+ break;
+ case 4:
+ present(null, [
+ ["Don't stop stroking!", "Keep jerking.", "Keep stroking."]]);
+ break;
+ }
+ itr += 1;
+ def beatNo = getRandom(BEATS.size());
+ def beat = BEATS[beatNo];
+ playBackgroundSound("toy/${beat.bpm}bpm.mp3", 10); // Lots, to cover offset
+ def len = getRandom(Math.max(5, beat.len + (sto * beatNo)));
+ if (showButtonG("Edging, ${dommeTitle()}", "edging", len) < len) {
+ sto -= 1;
+ edges += 1;
+ itr = 0;
+ playBackgroundSound(null);
+ switch (getRandom(3)) {
+ case 0:
+ present(imageSpec, [
+ ["Stop!", "Let go!", "Hands off!"]]);
+ if (mightCum(getRandom(8) + 10)) return;
+ break;
+ case 1:
+ present(imageSpec, [
+ ["Careful now...", "No accidents..."],
+ ["slow it down...", "slowly now..."]]);
+ playBackgroundSound("toy/30bpm.mp3");
+ if (mightCum(getRandom(20) + 5)) {
+ playBackgroundSound(null);
+ return;
+ }
+ case 2:
+ switch(getSelectedValue("Would you like to cum, toy?", [
+ gagText("Please, ${dommeTitle()}, may I cum!?", "yes"),
+ gagText("No, ${dommeTitle()}, please torment me more!", "no")
+ ])) {
+ case 0:
+ if (can(CUM)) {
+ present(imageSpec, [
+ ["Maybe...", "Perhaps.", "We'll see."]]);
+ }
+ else {
+ present(imageSpec, [
+ ["No you may not!", "Nope.", "Not a chance."]]);
+ adjustPunish(5);
+ }
+ break;
+ case 1:
+ present(imageSpec, [
+ ["Good boy.", "Very well.", "OK then!"]]);
+ adjustPunish(-5);
+ break;
+ }
+ if (mightCum(getRandom(8) + 5)) {
+ playBackgroundSound(null);
+ return;
+ }
playBackgroundSound(null);
- return;
- }
- playBackgroundSound(null);
+ }
+ tags = present(imageSpec, [
+ ["Back to stroking, toy...", "Get to it again...."],
+ ["follow the beat..."],
+ ["no accidents.", "and concentrate."]]);
+ }
+ else {
+ playBackgroundSound(null);
}
- tags = present(imageSpec, [
- ["Back to stroking, toy...", "Get to it again...."],
- ["follow the beat..."],
- ["no accidents.", "and concentrate."]]);
}
- else {
- playBackgroundSound(null);
+ if (edges == 0) {
+ sto += 1;
}
+ save("toy.strokeTeaseOffset", sto);
}
- if (edges == 0) {
- sto += 1;
- }
- save("toy.strokeTeaseOffset", sto);
-}
-def clampPulls = { amount ->
- getRandom(1 + amount).times {
- if (getRandom(2)) {
- present([DRESSED], [
- ["Take them off.", "Remove them."]]);
- wait(6 + getRandom(8));
+ def clampPulls = { amount ->
+ getRandom(1 + amount).times {
if (getRandom(2)) {
present([DRESSED], [
- ["And put them back on", "Put them back"],
- ["right where they came from.", "where they were."]]);
+ ["Take them off.", "Remove them."]]);
+ wait(6 + getRandom(8));
+ if (getRandom(2)) {
+ present([DRESSED], [
+ ["And put them back on", "Put them back"],
+ ["right where they came from.", "where they were."]]);
+ }
+ else {
+ present([DRESSED], [
+ ["Flip them", "Turn them"],
+ ["90 degrees", "around"],
+ ["and put them back.", "and replace them."]]);
+ }
+ wait(10 + getRandom(8));
}
- else {
+ else if (getRandom(2)) {
present([DRESSED], [
- ["Flip them", "Turn them"],
- ["90 degrees", "around"],
- ["and put them back.", "and replace them."]]);
+ ["Twist them"],
+ ["for me.", "... twist those nipples."]]);
+ wait(6 + getRandom(5));
+ if (getRandom(2)) {
+ present(null, [
+ ["More!", "A little more!", "Further!"]]);
+ wait(getRandom(10) + 2);
+ }
}
- wait(10 + getRandom(8));
- }
- else if (getRandom(2)) {
present([DRESSED], [
- ["Twist them"],
- ["for me.", "... twist those nipples."]]);
- wait(6 + getRandom(5));
- if (getRandom(2)) {
+ ["Pull them tight.", "Pull them!"]]);
+ wait(getRandom(10) + 5);
+ if (getRandom(5) == 0) {
present(null, [
- ["More!", "A little more!", "Further!"]]);
+ ["Tighter!", "Harder!", "Further!"]]);
wait(getRandom(10) + 2);
+ present(null, [
+ ["Haha!", "Ooo, they must hurt.", "Do they hurt?"]]);
+ wait(3);
}
- }
- present([DRESSED], [
- ["Pull them tight.", "Pull them!"]]);
- wait(getRandom(10) + 5);
- if (getRandom(5) == 0) {
- present(null, [
- ["Tighter!", "Harder!", "Further!"]]);
- wait(getRandom(10) + 2);
present(null, [
- ["Haha!", "Ooo, they must hurt.", "Do they hurt?"]]);
- wait(3);
+ ["Release them.", "Let them go."]]);
+ wait(getRandom(5) + 3);
+ };
+ return amount;
+ };
+ // Pre-tease
+ def preRelease = {
+ if (!is(CHASTE)) return;
+ if (!is(NAKED)) {
+ present([DRESSED], [
+ ["Reach down... and through your clothes...", "Stay clothed,"],
+ ["rub that chastity device...", "run your hand around that locked cock..."],
+ ["imagine if that was me doing it.", "that looks frustrating."]]);
+ wait(15);
+ present(null, [["Show me.", "Let me see it."]]);
+ wait(10);
+ }
+ else {
+ present([DRESSED], [
+ ["Look what we have here.", "Hnmm, look at that."],
+ ["Locked away and useless.", "Under lock and key as it should be."],
+ ["Too bad I have the keys.", "And I have the keys somewhere safe."]]);
+ wait(10);
}
- present(null, [
- ["Release them.", "Let them go."]]);
- wait(getRandom(5) + 3);
- };
- return amount;
-};
-// Pre-tease
-def preRelease = {
- if (!is(CHASTE)) return;
- if (!is(NAKED)) {
present([DRESSED], [
- ["Reach down... and through your clothes...", "Stay clothed,"],
- ["rub that chastity device...", "run your hand around that locked cock..."],
- ["imagine if that was me doing it.", "that looks frustrating."]]);
+ ["Play with your balls,", "Tease those balls a little,"],
+ ["I want to see how horny you are", "see how hard you can get"],
+ ["before I let you out.", "before I hand over the keys."],
+ ["You should be", "When you're"],
+ ["practically breaking out,", "about to break it for me,"],
+ ["we'll continue.", "then I'll see about letting it out."]]);
+ showButtonG("Hard, ${dommeTitle()}, please let me out", "hard");
+ present([DRESSED,TEASE], [
+ ["OK then.", "Fine, fine."],
+ ["I'm feeling generous, toy...", "Well, it's no good to me like that..."],
+ ["I have the keys right here,", "I have the keys here somewhere... OK,"],
+ ["unlock yourself and", "take your chastity device off"],
+ ["let me see my cock.", "let's see it."]]);
+ showButtonG("Yes, ${dommeTitle()}", "ok");
wait(15);
- present(null, [["Show me.", "Let me see it."]]);
+ set(CHASTE, false);
+ showButtonGT("Thank you, ${dommeTitle()}", "ok", 80, 1);
+ };
+ def preEdge = {
+ if (is(CHASTE)) return;
+ expose([DRESSED]);
+ harden([DRESSED]);
+ edge(4, [DRESSED]);
+ present([DRESSED], [
+ ["And relax...", "Hands off..."],
+ ["cool down a little.", "but keep it hard for me!", "for now!"]]);
+ wait(getRandom(5) + 5);
+ };
+ def preGag = {
+ if (is(GAGGED)) return 1.2;
+ if (!has(BALLGAG)) return;
+ present([DRESSED], [
+ ["Go fetch your gag, toy...", "Bring me your gag, toy..."],
+ ["Quickly!", "Hurry back!"]]);
+ showButton("Yes, ${dommeTitle()}");
+ show(null);
wait(10);
- }
- else {
+ showButtonGT("Back, ${dommeTitle()}", "back", 50, 2);
present([DRESSED], [
- ["Look what we have here.", "Hnmm, look at that."],
- ["Locked away and useless.", "Under lock and key as it should be."],
- ["Too bad I have the keys.", "And I have the keys somewhere safe."]]);
+ ["Good boy.", "Very good."],
+ ["Put it on..."],
+ ["Nice and tight.", "Tight!"],
+ ["I don't want to a hear a word from you.", "A quiet toy is a good toy."]]);
+ set(GAGGED, true);
+ showButtonGT("Gagged, ${dommeTitle()}", "gagged", 20, 2);
+ sessionToys[BALLGAG] = getTime();
+ return 1.2;
+ };
+ def clamps = {
+ if (is(CLAMPED)) return;
+ if (!has(CLAMPS)) return;
+ present([DRESSED],
+ likes(PAIN) ? [
+ ["We both like to see you suffer.", "Pain is fun."],
+ ["Isn't that right, toy?", "Don't you agree?"]]
+ : [
+ ["I'm sorry, toy,"],
+ ["but seeing you suffer is too much fun.", "but I need to find my amusement somewhere."]]);
wait(10);
- }
- present([DRESSED], [
- ["Play with your balls,", "Tease those balls a little,"],
- ["I want to see how horny you are", "see how hard you can get"],
- ["before I let you out.", "before I hand over the keys."],
- ["You should be", "When you're"],
- ["practically breaking out,", "about to break it for me,"],
- ["we'll continue.", "then I'll see about letting it out."]]);
- showButtonG("Hard, ${dommeTitle()}, please let me out", "hard");
- present([DRESSED,TEASE], [
- ["OK then.", "Fine, fine."],
- ["I'm feeling generous, toy...", "Well, it's no good to me like that..."],
- ["I have the keys right here,", "I have the keys here somewhere... OK,"],
- ["unlock yourself and", "take your chastity device off"],
- ["let me see my cock.", "let's see it."]]);
- showButtonG("Yes, ${dommeTitle()}", "ok");
- wait(15);
- set(CHASTE, false);
- showButtonGT("Thank you, ${dommeTitle()}", "ok", 80, 1);
-};
-def preEdge = {
- if (is(CHASTE)) return;
- expose([DRESSED]);
- harden([DRESSED]);
- edge(4, [DRESSED]);
- present([DRESSED], [
- ["And relax...", "Hands off..."],
- ["cool down a little.", "but keep it hard for me!", "for now!"]]);
- wait(getRandom(5) + 5);
-};
-def preGag = {
- if (is(GAGGED)) return 1.2;
- if (!has(BALLGAG)) return;
- present([DRESSED], [
- ["Go fetch your gag, toy...", "Bring me your gag, toy..."],
- ["Quickly!", "Hurry back!"]]);
- showButton("Yes, ${dommeTitle()}");
- show(null);
- wait(10);
- showButtonGT("Back, ${dommeTitle()}", "back", 50, 2);
- present([DRESSED], [
- ["Good boy.", "Very good."],
- ["Put it on..."],
- ["Nice and tight.", "Tight!"],
- ["I don't want to a hear a word from you.", "A quiet toy is a good toy."]]);
- set(GAGGED, true);
- showButtonGT("Gagged, ${dommeTitle()}", "gagged", 20, 2);
- sessionToys[BALLGAG] = getTime();
- return 1.2;
-};
-def clamps = {
- if (is(CLAMPED)) return;
- if (!has(CLAMPS)) return;
- present([DRESSED],
- likes(PAIN) ? [
- ["We both like to see you suffer.", "Pain is fun."],
- ["Isn't that right, toy?", "Don't you agree?"]]
- : [
- ["I'm sorry, toy,"],
- ["but seeing you suffer is too much fun.", "but I need to find my amusement somewhere."]]);
- wait(10);
- present([DRESSED],[
- ["Go put your nipple clamps on...", "I want those nipples clamped..."],
- ["but on your way back...", "no walking though..."],
- ["crawl, down on all fours.", "on your knees."]]);
- showButtonG("Yes, ${dommeTitle()}", "ok");
- show(null);
- wait(10);
- set(CLAMPED, true);
- showButtonGT("Back, ${dommeTitle()}", "back", 60, 1);
- sessionToys[CLAMPS] = getTime();
- present([DRESSED], [
- ["On your knees,", "Kneel before me"],
- ["let me see.", "hands behind your back."]]);
- wait(getRandom(10) + 5);
-};
-def clampsShow = {
- present([DRESSED,TEASE], [
- ["Let me see", "Show me"],
- ["those nipple clamps,", "those nasty clamps,"],
- ["they look painful.", "and jiggle them about for me!"]]);
- wait(10);
-};
-def preClamps = {
- if (!has(CLAMPS)) return;
- if (is(CLAMPED)) {
- clampsShow();
- }
- else {
- clamps();
- }
- clampPulls(getRandom(4));
- return 1.8;
-};
-def preCollar = {
- if (is(COLLARED)) return 1.1;
- if (!has(COLLAR)) return;
- present([DRESSED], [
- ["You look underdressed, toy.", "A toy without a collar doesn't look right."],
- ["Go put your collar on", "I want a collar around your neck"],
- ["and crawl back like the slutty puppy dog you are.", "and kneel before me."]]);
- showButtonG("Yes, ${dommeTitle()}", "ok");
- show(null);
- wait(10);
- set(COLLARED, true);
- showButtonGT("Back, ${dommeTitle()}", "back", 60, 1);
- sessionToys[COLLAR] = getTime();
- return 1.1;
-};
-def preStrip = { imageSpec = [DRESSED] ->
- if (is(NAKED)) return 1.1;
- present(imageSpec, [
- ["Clothes off!", "Get naked, slut!"]]);
- wait(10);
- present(imageSpec, [
- ["All of them off!", "And the rest!", "Keep going."]]);
- set(NAKED, true);
- showButtonGT("Naked, ${dommeTitle()}", "naked", 60, 5);
- present(null, [
- ["Very good. Now...", "I see..."],
- ["on your knees before me,", "kneel,", "stand up straight,", "on your feet,"],
- ["hands behind your head,", "arms up,", "hands high up,"],
- ["let me see you properly.", "let's see what we have.", "I want a good view."]]);
- wait(10);
- return 1.1;
-};
-
-// Post
-def postEdge = {
- if (is(CHASTE)) return;
- if (!can(EDGE)) return;
- edge(6, [TEASE]);
-};
-def postCum = {
- if (is(CHASTE)) return;
- present([TEASE], [
- ["How about I let you cum?", "Maybe I should let you cum."],
- ["Would you like that?", "Let some of that frustration out?"]]);
- wait(getRandom(5) + 5);
- def ways = [cumChanceRuin, cumChanceWindow, cumChanceCountdown];
- if (ways[getRandom(ways.size())]()) {
- // Once toy has cum, revoke permission for a while
- revokePermission(CUM);
- }
-};
-def chastity = { pre ->
- if (is(CHASTE)) return;
- if (!has(CHASTITY)) return;
- if (pre) {
- present([DRESSED,TEASE], [
- ["Fun time is over for you.", "You'd have enough pleasure lately, my turn."]]);
- }
- else {
- present([TEASE], [
- ["I can't keep an eye on you all time.", "It's not that I don't trust you."],
- ["But...", "I just like to be sure."]]);
- }
- wait(getRandom(5) + 10);
- if (sessionToys.containsKey(CHASTITY)) {
- present([DRESSED,TEASE], [
- ["Time to", "Get your chastity device and"],
- ["lock my cock away again now.", "get that cock back in its cage."],
- ["And of course", "And then"],
- ["hand over the key.", "give me the key back."]]);
- }
- else {
- present([DRESSED,TEASE], [
- ["Go to your room,", "Run along now,"],
- ["get your chastity device and"],
- ["lock it on.", "get that cock secured away."],
- ["Bring back the key.", "I want the key of course."]]);
- }
- wait(10);
- show(null);
- showButtonGT("Locked, ${dommeTitle()}. Here's the key.", "locked", 180, 1);
- set(CHASTE, true);
- present([DRESSED,TEASE], [
- ["Good boy.", "Thank you, toy."]]);
- wait(5);
-}
-def preChastity = {
- chastity(true);
-}
-def postChastity = {
- chastity(false);
- if (is(CHASTE) && (getPermission(PERM_CHASTE) == null ||
- (getPermission(PERM_CHASTE) == false && getProp(PERM_CHASTE_ASK, loadI, 0) < getTime() - (DAY * 30)))) {
+ present([DRESSED],[
+ ["Go put your nipple clamps on...", "I want those nipples clamped..."],
+ ["but on your way back...", "no walking though..."],
+ ["crawl, down on all fours.", "on your knees."]]);
+ showButtonG("Yes, ${dommeTitle()}", "ok");
+ show(null);
+ wait(10);
+ set(CLAMPED, true);
+ showButtonGT("Back, ${dommeTitle()}", "back", 60, 1);
+ sessionToys[CLAMPS] = getTime();
+ present([DRESSED], [
+ ["On your knees,", "Kneel before me"],
+ ["let me see.", "hands behind your back."]]);
+ wait(getRandom(10) + 5);
+ };
+ def clampsShow = {
present([DRESSED,TEASE], [
- ["Now I have you locked up,", "Now my cock is secured away,"],
- ["would you let me", "can I"],
- ["keep you like that"],
- ["all the time?", "permanently?"]]);
- def sh = getSelectedValue(null, [
- gagText("Yes, ${dommeTitle()}", "yes"), gagText("Please, ${dommeTitle()}, no", "no")]);
- if (sh == 0) {
- present([DRESSED,TEASE], [
- ["Good boy.", "Thank you, toy."]]);
- setPermission(PERM_CHASTE, true);
- setProp(PERM_CHASTE_ASK, null);
+ ["Let me see", "Show me"],
+ ["those nipple clamps,", "those nasty clamps,"],
+ ["they look painful.", "and jiggle them about for me!"]]);
+ wait(10);
+ };
+ def preClamps = {
+ if (!has(CLAMPS)) return;
+ if (is(CLAMPED)) {
+ clampsShow();
}
else {
- present([DRESSED,nTEASE], [
- ["Awwww.", "Shame."],
- ["One day..."]]);
- setPermission(PERM_CHASTE, false);
- setProp(PERM_CHASTE_ASK, getTime());
+ clamps();
}
- wait(5);
- }
-};
-
-// Play
-def playStrokes = {
- preRelease();
- harden([TITS]);
- strokes(15, [TITS]);
-};
-def playEdges = {
- preRelease();
- harden([TITS]);
- edge(6, [TITS]);
-};
-def playNothing = {
- (getRandom(3) + 2).times {
- show(imageTagsComment(showImage([TITS])));
- wait(getRandom(10) + 10);
+ clampPulls(getRandom(4));
+ return 1.8;
};
-};
-def getSpoon = {
- if (sessionToys.containsKey(SPOON)) {
+ def preCollar = {
+ if (is(COLLARED)) return 1.1;
+ if (!has(COLLAR)) return;
present([DRESSED], [
- ["Pick up", "Grab"],
- ["your", "that"],
- ["wooden spoon"],
- ["again."]]);
- wait(10);
- }
- else {
- present([DRESSED], [
- ["Go to the kitchen...", "From the kitchen..."],
- ["bring me", "get yourself"],
- ["a wooden spoon or similar."]]);
+ ["You look underdressed, toy.", "A toy without a collar doesn't look right."],
+ ["Go put your collar on", "I want a collar around your neck"],
+ ["and crawl back like the slutty puppy dog you are.", "and kneel before me."]]);
showButtonG("Yes, ${dommeTitle()}", "ok");
+ show(null);
+ wait(10);
+ set(COLLARED, true);
+ showButtonGT("Back, ${dommeTitle()}", "back", 60, 1);
+ sessionToys[COLLAR] = getTime();
+ return 1.1;
+ };
+ def preStrip = { imageSpec = [DRESSED] ->
+ if (is(NAKED)) return 1.1;
+ present(imageSpec, [
+ ["Clothes off!", "Get naked, slut!"]]);
+ wait(10);
+ present(imageSpec, [
+ ["All of them off!", "And the rest!", "Keep going."]]);
+ set(NAKED, true);
+ showButtonGT("Naked, ${dommeTitle()}", "naked", 60, 5);
+ present(null, [
+ ["Very good. Now...", "I see..."],
+ ["on your knees before me,", "kneel,", "stand up straight,", "on your feet,"],
+ ["hands behind your head,", "arms up,", "hands high up,"],
+ ["let me see you properly.", "let's see what we have.", "I want a good view."]]);
+ wait(10);
+ return 1.1;
+ };
+
+ // Post
+ def postEdge = {
+ if (is(CHASTE)) return;
+ if (!can(EDGE)) return;
+ edge(6, [TEASE]);
+ };
+ def postCum = {
+ if (is(CHASTE)) return;
+ present([TEASE], [
+ ["How about I let you cum?", "Maybe I should let you cum."],
+ ["Would you like that?", "Let some of that frustration out?"]]);
+ wait(getRandom(5) + 5);
+ def ways = [cumChanceRuin, cumChanceWindow, cumChanceCountdown];
+ if (ways[getRandom(ways.size())]()) {
+ // Once toy has cum, revoke permission for a while
+ revokePermission(CUM);
+ }
+ };
+ def chastity = { pre ->
+ if (is(CHASTE)) return;
+ if (!has(CHASTITY)) return;
+ if (pre) {
+ present([DRESSED,TEASE], [
+ ["Fun time is over for you.", "You'd have enough pleasure lately, my turn."]]);
+ }
+ else {
+ present([TEASE], [
+ ["I can't keep an eye on you all time.", "It's not that I don't trust you."],
+ ["But...", "I just like to be sure."]]);
+ }
+ wait(getRandom(5) + 10);
+ if (sessionToys.containsKey(CHASTITY)) {
+ present([DRESSED,TEASE], [
+ ["Time to", "Get your chastity device and"],
+ ["lock my cock away again now.", "get that cock back in its cage."],
+ ["And of course", "And then"],
+ ["hand over the key.", "give me the key back."]]);
+ }
+ else {
+ present([DRESSED,TEASE], [
+ ["Go to your room,", "Run along now,"],
+ ["get your chastity device and"],
+ ["lock it on.", "get that cock secured away."],
+ ["Bring back the key.", "I want the key of course."]]);
+ }
+ wait(10);
+ show(null);
+ showButtonGT("Locked, ${dommeTitle()}. Here's the key.", "locked", 180, 1);
+ set(CHASTE, true);
+ present([DRESSED,TEASE], [
+ ["Good boy.", "Thank you, toy."]]);
wait(5);
- showButtonGT("Back, ${dommeTitle()}", "back", 20, 1);
- sessionToys[SPOON] = getTime();
}
-};
-def playBeatBalls = {
- final BEATS = [
- // bpm:30, len:60 ],
- [ bpm:90, len:45 ],
- [ bpm:165, len:30 ],
- [ bpm:180, len:30 ],
- [ bpm:240, len:20 ],
- ];
- getSpoon();
- present([DRESSED], [
- ["Good.", "Right."],
- ["Take those balls in one hand", "In one hand, hold your balls"],
- ["and in the other, get ready to beat them.", "and get ready to beat them with other."]]);
- showButtonGT("Yes, ${dommeTitle()}", "ok", 10, 1);
- present([DRESSED], [
- ["You concentrate on beating,", "Don't worry,"],
- ["I'll be keeping count.", "I'll count them for you."]]);
- wait(3);
- present(null, [["Ready"]]);
- wait(1);
- present(null, [["Set"]]);
- wait(1);
- present(null, [["Go!"]]);
- def beats = 0;
- (4 + getRandom(7)).times({
- def beatNo = getRandom(BEATS.size());
- def beat = BEATS[beatNo];
- def len = getRandom(beat.len - 5) + 5;
- playBackgroundSound("toy/${beat.bpm}bpm.mp3");
- wait(len);
- playBackgroundSound(null);
- beats += (int)((beat.bpm * len) / 60.0);
- present(null, [
- ["$beats.", "That's $beats.", "$beats so far."],
- ["Keep going.", "Don't stop!", "Just a few more.", "Harder!"]]);
- });
- present([DRESSED], [
- ["Stop!", "Ok, you can stop now."],
- ["They look a little sore.", "Is that a nice tingly feeling?"]]);
- showButtonG("Thank you, ${dommeTitle()}.", "ok");
- show(null);
- wait(5);
- return beats / 10.0;
-};
-def playBeatCock = {
- preRelease();
- harden([DRESSED,nTITS]);
- getSpoon();
- present([DRESSED], [
- ["Good.", "Right."],
- ["When I crack my whip... you beat the head my little cock."],
- ["Don't hold back,", "Be brave for me,"],
- ["it's meant to hurt!", "it's fun for me to watch."]]);
- wait(5);
- def count = 0;
- def n = (2 + getRandom((int)(getPunish() / 150)));
- n.times({
- randRange(10, 20).times({
- playBackgroundSound("shortwhip.wav");
- count += 1;
- wait(randRange(3, 5));
- });
- if (it < n - 1) {
- def sh = getSelectedValue("Still hard?", [
- gagText("Yes, ${dommeTitle()}", "yes"), gagText("No, ${dommeTitle()}", "no")]);
- if (sh == 1) {
- harden([DRESSED, nTITS]);
+ def preChastity = {
+ chastity(true);
+ }
+ def postChastity = {
+ chastity(false);
+ if (is(CHASTE) && (getPermission(PERM_CHASTE) == null ||
+ (getPermission(PERM_CHASTE) == false && getProp(PERM_CHASTE_ASK, loadI, 0) < getTime() - (DAY * 30)))) {
+ present([DRESSED,TEASE], [
+ ["Now I have you locked up,", "Now my cock is secured away,"],
+ ["would you let me", "can I"],
+ ["keep you like that"],
+ ["all the time?", "permanently?"]]);
+ def sh = getSelectedValue(null, [
+ gagText("Yes, ${dommeTitle()}", "yes"), gagText("Please, ${dommeTitle()}, no", "no")]);
+ if (sh == 0) {
+ present([DRESSED,TEASE], [
+ ["Good boy.", "Thank you, toy."]]);
+ setPermission(PERM_CHASTE, true);
+ setProp(PERM_CHASTE_ASK, null);
}
else {
- present([DRESSED], [
- ["Good", "Good boy", "Excellent"]]);
- wait(randRange(3, 5));
+ present([DRESSED,nTEASE], [
+ ["Awwww.", "Shame."],
+ ["One day..."]]);
+ setPermission(PERM_CHASTE, false);
+ setProp(PERM_CHASTE_ASK, getTime());
}
- present([DRESSED], [
- ["Again!", "More!"]]);
- wait(1);
- }
- })
- return count * 5;
-};
-def playKneel = {
- present([DRESSED], [
- ["Right, slut.", "Come here, toy."],
- ["On the floor, right there.", "Kneel at my feet."]]);
- showButtonGT("Yes, ${dommeTitle()}.", "ok", 20, 1);
- present([DRESSED], [
- ["When I say go,", "In a moment,"],
- ["you'll crawl", "turn and crawl"],
- ["away until I ring my bell."],
- ["You'll stay there,", "And then you won't move,"],
- ["head bowed", "face down"],
- ["until I call you back.", "until you're summoned."]]);
- showButtonG("Yes, ${dommeTitle()}.", "ok");
- present(null, [["Wait..."]]);
- wait(getRandom(10) + 10);
- present([DRESSED], [["Ok, go!", "Now! Off you go."]]);
- wait(getRandom(5) + 5);
- playBackgroundSound("bell.wav");
- show(null);
- def kneelTime = 60 + getRandom(240);
- wait(kneelTime);
- while (playBackgroundSound("bell.wav") || true) {
- if (showButtonG("Back, ${dommeTitle()}", "back", 20) != 20) break;
- }
- present([DRESSED], [
- ["Good boy.", "Very good."],
- ["Stay down there.", "Don't move."]]);
- wait(getRandom(5) + 5);
- return kneelTime / 20.0;
-};
-def playBondage = {
- if (!has(HANDCUFFS)) return;
- def prep = [ preStrip, preCollar, preClamps, preGag ];
- Collections.shuffle(prep);
- prep.collect { p -> p(); };
- present([DRESSED, nTEASE], [
- ["Go fetch your handcuffs"]]);
- showButtonG("Yes, ${dommeTitle()}", "ok");
- wait(10);
- showButtonGT("Back, ${dommeTitle()}", "back", 60, 1);
- sessionToys[HANDCUFFS] = getTime();
- present([DRESSED, nTEASE], [
- ["Good."],
- ["Down on the floor.", "On your knees.", "Down there, where you are."]]);
- wait(15);
- present([DRESSED, nTEASE], [
- ["You know what's next.", "Take your cuffs."],
- ["Cuff yourself,", "Hands cuffed,"],
- ["behind your back of course.", "behind you."]]);
- wait(15);
- present([DRESSED, TEASE], [
- ["Don't go anywhere!", "Do not move!"]]);
- wait(15);
- present([STOOD], [
- ["I'll be back for you soon.", "I won't leave you too long."]]);
- wait(15);
- setImage(null);
- show(null);
- def waitTime = 300 + getRandom(Math.min(1500, 1 + getPunish() * 10));
- wait(waitTime);
- playBackgroundSound("bell.wav");
- present([STOOD], [
- ["Hi slave!", "Hello again."],
- ["You don't look very comfortable.", "That looks quite awkward."],
- ["Maybe you've been there long enough.", "It's been a while now."]]);
- wait(20);
- present([DRESSED, TEASE], [
- ["OK,", "Mmmm,"],
- ["soon.", "just a while longer."]]);
- wait(60 + getRandom(60));
- playBackgroundSound("bell.wav");
- present([DRESSED, TEASE], [
- ["Go find the keys,", "Very well,"],
- ["let yourself out,", "unlock the cuffs,"],
- ["and come back.", "and hurry back."]]);
- wait(10);
- setImage(null);
- showButtonGT("Freed, ${dommeTitle()}", "freed", 120, 1);
- return waitTime;
-};
-def playSuck = {
- def playWait = { file, time ->
- playBackgroundSound(file);
- wait(time);
- playBackgroundSound(null);
+ wait(5);
+ }
};
- def suck = { file, n, delay ->
- n.times {
- playWait(file, delay);
+
+ // Play
+ def playStrokes = {
+ preRelease();
+ harden([TITS]);
+ strokes(15, [TITS]);
+ };
+ def playEdges = {
+ preRelease();
+ harden([TITS]);
+ edge(6, [TITS]);
+ };
+ def playNothing = {
+ (getRandom(3) + 2).times {
+ show(imageTagsComment(showImage([TITS])));
+ wait(getRandom(10) + 10);
};
};
- def suckBeat = { beat, n ->
- suck("toy/${beat}bpm.mp3", n, 2 * (60 / beat));
+ def getSpoon = {
+ if (sessionToys.containsKey(SPOON)) {
+ present([DRESSED], [
+ ["Pick up", "Grab"],
+ ["your", "that"],
+ ["wooden spoon"],
+ ["again."]]);
+ wait(10);
+ }
+ else {
+ present([DRESSED], [
+ ["Go to the kitchen...", "From the kitchen..."],
+ ["bring me", "get yourself"],
+ ["a wooden spoon or similar."]]);
+ showButtonG("Yes, ${dommeTitle()}", "ok");
+ wait(5);
+ showButtonGT("Back, ${dommeTitle()}", "back", 20, 1);
+ sessionToys[SPOON] = getTime();
+ }
};
- if (sessionToys.containsKey(DILDO)) {
+ def playBeatBalls = {
+ final BEATS = [
+ // bpm:30, len:60 ],
+ [ bpm:90, len:45 ],
+ [ bpm:165, len:30 ],
+ [ bpm:180, len:30 ],
+ [ bpm:240, len:20 ],
+ ];
+ getSpoon();
present([DRESSED], [
- ["Back to your dildo.", "Amuse me some more with that dildo."],
- ["Same as before, listen for my bell, slut."]]);
- showButtonG("Yes, ${dommeTitle()}", "ok");
- }
- else {
+ ["Good.", "Right."],
+ ["Take those balls in one hand", "In one hand, hold your balls"],
+ ["and in the other, get ready to beat them.", "and get ready to beat them with other."]]);
+ showButtonGT("Yes, ${dommeTitle()}", "ok", 10, 1);
present([DRESSED], [
- ["Time for you to amuse me, you little slut."],
- ["Get your dildo and secure it somewhere nearby, about eye level when kneeling."]]);
- wait(10);
- showButtonGT("Done, ${dommeTitle()}", "done", 60, 1);
- sessionToys[DILDO] = getTime();
+ ["You concentrate on beating,", "Don't worry,"],
+ ["I'll be keeping count.", "I'll count them for you."]]);
+ wait(3);
+ present(null, [["Ready"]]);
+ wait(1);
+ present(null, [["Set"]]);
+ wait(1);
+ present(null, [["Go!"]]);
+ def beats = 0;
+ (4 + getRandom(7)).times({
+ def beatNo = getRandom(BEATS.size());
+ def beat = BEATS[beatNo];
+ def len = getRandom(beat.len - 5) + 5;
+ playBackgroundSound("toy/${beat.bpm}bpm.mp3");
+ wait(len);
+ playBackgroundSound(null);
+ beats += (int)((beat.bpm * len) / 60.0);
+ present(null, [
+ ["$beats.", "That's $beats.", "$beats so far."],
+ ["Keep going.", "Don't stop!", "Just a few more.", "Harder!"]]);
+ });
present([DRESSED], [
- ["The rules are simple:\n"],
- ["On my first bell, you take the head in your mouth and start to pleasure it.\n"],
- ["When you hear the beat, you suck the shaft, one beat in, one beat out again.\n"],
- ["Lastly, on the crack of my whip, you take the whole thing in and suck from the base.\n"],
- ["I know you'll enjoy it, don't be shy.\n"],
- ["One more thing..."],
- ["That cock doesn't doesn't leave your mouth until I say so, listen for second bell and then return to me."]]);
- showButtonGT("Understood, ${dommeTitle()}", "understood", 30, 1);
- present([TEASE], [
- ["Get ready"]]);
- showButtonGT("Ready, ${dommeTitle()}", "ready", 10, 1);
- }
- show(null);
-
- final target = loadInteger("toy.deepthroat.goal") ?: 5;
- def completed = loadInteger("toy.deepthroat.completed") ?: 0;
- def session = 0;
-
- wait(randRange(10, 20));
- playWait("bell.wav", randRange(10, 40)); // Head
- while (session < target) {
- suckBeat(30, randRange(5, 15)); // Slow
- suckBeat(90, randRange(10, 30)); // Quick
- wait(0.5);
- final deep = randRange(target / 4, target / 2);
- suck("shortwhip.wav", deep, 2.5); // Deep
- session += deep;
- }
- suckBeat(30, randRange(5, 15)); // Slow
- wait(randRange(10, 20)); // Head
- playBackgroundSound("bell.wav"); // End
-
- showButtonGT("Back, ${dommeTitle()}", "back", 15, 1);
- if (getBoolean("Did you perform as ordered?", "Yes, ${dommeTitle()}", "No, ${dommeTitle()}")) {
+ ["Stop!", "Ok, you can stop now."],
+ ["They look a little sore.", "Is that a nice tingly feeling?"]]);
+ showButtonG("Thank you, ${dommeTitle()}.", "ok");
+ show(null);
+ wait(5);
+ return beats / 10.0;
+ };
+ def playBeatCock = {
+ preRelease();
+ harden([DRESSED,nTITS]);
+ getSpoon();
+ present([DRESSED], [
+ ["Good.", "Right."],
+ ["When I crack my whip... you beat the head my little cock."],
+ ["Don't hold back,", "Be brave for me,"],
+ ["it's meant to hurt!", "it's fun for me to watch."]]);
+ wait(5);
+ def count = 0;
+ def n = (2 + getRandom((int)(getPunish() / 150)));
+ n.times({
+ randRange(10, 20).times({
+ playBackgroundSound("shortwhip.wav");
+ count += 1;
+ wait(randRange(3, 5));
+ });
+ if (it < n - 1) {
+ def sh = getSelectedValue("Still hard?", [
+ gagText("Yes, ${dommeTitle()}", "yes"), gagText("No, ${dommeTitle()}", "no")]);
+ if (sh == 1) {
+ harden([DRESSED, nTITS]);
+ }
+ else {
+ present([DRESSED], [
+ ["Good", "Good boy", "Excellent"]]);
+ wait(randRange(3, 5));
+ }
+ present([DRESSED], [
+ ["Again!", "More!"]]);
+ wait(1);
+ }
+ })
+ return count * 5;
+ };
+ def playKneel = {
+ present([DRESSED], [
+ ["Right, slut.", "Come here, toy."],
+ ["On the floor, right there.", "Kneel at my feet."]]);
+ showButtonGT("Yes, ${dommeTitle()}.", "ok", 20, 1);
present([DRESSED], [
- ["Good boy"]]);
- adjustPunish(-4 * target);
- completed += 1;
- if (completed >= 5) {
- save("toy.deepthroat.goal", target + 1);
- completed = 0;
+ ["When I say go,", "In a moment,"],
+ ["you'll crawl", "turn and crawl"],
+ ["away until I ring my bell."],
+ ["You'll stay there,", "And then you won't move,"],
+ ["head bowed", "face down"],
+ ["until I call you back.", "until you're summoned."]]);
+ showButtonG("Yes, ${dommeTitle()}.", "ok");
+ present(null, [["Wait..."]]);
+ wait(getRandom(10) + 10);
+ present([DRESSED], [["Ok, go!", "Now! Off you go."]]);
+ wait(getRandom(5) + 5);
+ playBackgroundSound("bell.wav");
+ show(null);
+ def kneelTime = 60 + getRandom(240);
+ wait(kneelTime);
+ while (playBackgroundSound("bell.wav") || true) {
+ if (showButtonG("Back, ${dommeTitle()}", "back", 20) != 20) break;
}
- }
- else {
- final missed = getInteger("How many deep sucks did you miss?", 1);
- if (missed > 5) {
+ present([DRESSED], [
+ ["Good boy.", "Very good."],
+ ["Stay down there.", "Don't move."]]);
+ wait(getRandom(5) + 5);
+ return kneelTime / 20.0;
+ };
+ def playBondage = {
+ if (!has(HANDCUFFS)) return;
+ def prep = [ preStrip, preCollar, preClamps, preGag ];
+ Collections.shuffle(prep);
+ prep.collect { p -> p(); };
+ present([DRESSED, nTEASE], [
+ ["Go fetch your handcuffs"]]);
+ showButtonG("Yes, ${dommeTitle()}", "ok");
+ wait(10);
+ showButtonGT("Back, ${dommeTitle()}", "back", 60, 1);
+ sessionToys[HANDCUFFS] = getTime();
+ present([DRESSED, nTEASE], [
+ ["Good."],
+ ["Down on the floor.", "On your knees.", "Down there, where you are."]]);
+ wait(15);
+ present([DRESSED, nTEASE], [
+ ["You know what's next.", "Take your cuffs."],
+ ["Cuff yourself,", "Hands cuffed,"],
+ ["behind your back of course.", "behind you."]]);
+ wait(15);
+ present([DRESSED, TEASE], [
+ ["Don't go anywhere!", "Do not move!"]]);
+ wait(15);
+ present([STOOD], [
+ ["I'll be back for you soon.", "I won't leave you too long."]]);
+ wait(15);
+ setImage(null);
+ show(null);
+ def waitTime = 300 + getRandom(Math.min(1500, 1 + getPunish() * 10));
+ wait(waitTime);
+ playBackgroundSound("bell.wav");
+ present([STOOD], [
+ ["Hi slave!", "Hello again."],
+ ["You don't look very comfortable.", "That looks quite awkward."],
+ ["Maybe you've been there long enough.", "It's been a while now."]]);
+ wait(20);
+ present([DRESSED, TEASE], [
+ ["OK,", "Mmmm,"],
+ ["soon.", "just a while longer."]]);
+ wait(60 + getRandom(60));
+ playBackgroundSound("bell.wav");
+ present([DRESSED, TEASE], [
+ ["Go find the keys,", "Very well,"],
+ ["let yourself out,", "unlock the cuffs,"],
+ ["and come back.", "and hurry back."]]);
+ wait(10);
+ setImage(null);
+ showButtonGT("Freed, ${dommeTitle()}", "freed", 120, 1);
+ return waitTime;
+ };
+ def playSuck = {
+ def playWait = { file, time ->
+ playBackgroundSound(file);
+ wait(time);
+ playBackgroundSound(null);
+ };
+ def suck = { file, n, delay ->
+ n.times {
+ playWait(file, delay);
+ };
+ };
+ def suckBeat = { beat, n ->
+ suck("toy/${beat}bpm.mp3", n, 2 * (60 / beat));
+ };
+ if (sessionToys.containsKey(DILDO)) {
present([DRESSED], [
- ["Very disappointing."]]);
+ ["Back to your dildo.", "Amuse me some more with that dildo."],
+ ["Same as before, listen for my bell, slut."]]);
+ showButtonG("Yes, ${dommeTitle()}", "ok");
}
else {
present([DRESSED], [
- ["Mmm"],
- ["More practice required."]]);
+ ["Time for you to amuse me, you little slut."],
+ ["Get your dildo and secure it somewhere nearby, about eye level when kneeling."]]);
+ wait(10);
+ showButtonGT("Done, ${dommeTitle()}", "done", 60, 1);
+ sessionToys[DILDO] = getTime();
+ present([DRESSED], [
+ ["The rules are simple:\n"],
+ ["On my first bell, you take the head in your mouth and start to pleasure it.\n"],
+ ["When you hear the beat, you suck the shaft, one beat in, one beat out again.\n"],
+ ["Lastly, on the crack of my whip, you take the whole thing in and suck from the base.\n"],
+ ["I know you'll enjoy it, don't be shy.\n"],
+ ["One more thing..."],
+ ["That cock doesn't doesn't leave your mouth until I say so, listen for second bell and then return to me."]]);
+ showButtonGT("Understood, ${dommeTitle()}", "understood", 30, 1);
+ present([TEASE], [
+ ["Get ready"]]);
+ showButtonGT("Ready, ${dommeTitle()}", "ready", 10, 1);
}
- adjustPunish(10 * missed);
- completed -= 1;
- if (completed <= -5) {
- save("toy.deepthroat.goal", target - 1);
- completed = 0;
+ show(null);
+
+ final target = loadInteger("toy.deepthroat.goal") ?: 5;
+ def completed = loadInteger("toy.deepthroat.completed") ?: 0;
+ def session = 0;
+
+ wait(randRange(10, 20));
+ playWait("bell.wav", randRange(10, 40)); // Head
+ while (session < target) {
+ suckBeat(30, randRange(5, 15)); // Slow
+ suckBeat(90, randRange(10, 30)); // Quick
+ wait(0.5);
+ final deep = randRange(target / 4, target / 2);
+ suck("shortwhip.wav", deep, 2.5); // Deep
+ session += deep;
}
- }
- save("toy.deepthroat.completed", completed);
- wait(10);
-};
-def playClamps = {
- if (!has(CLAMPS)) return;
- if (!is(CLAMPED)) clamps();
- clampsShow();
- return clampPulls(3 + getRandom(10));
-};
-def intClamps = {
- if (!has(CLAMPS)) return;
- if (!is(CLAMPED)) return;
- clampsShow();
- return clampPulls(getRandom(5));
-};
-def intSqueeze = {
- (2 + getRandom(4)).times { n ->
- if (n > 0) {
- present([DRESSED,TEASE], [
- ["And again,", "Again,", "Once more,"],
- ["harder!", "tighter!"]]);
+ suckBeat(30, randRange(5, 15)); // Slow
+ wait(randRange(10, 20)); // Head
+ playBackgroundSound("bell.wav"); // End
+
+ showButtonGT("Back, ${dommeTitle()}", "back", 15, 1);
+ if (getBoolean("Did you perform as ordered?", "Yes, ${dommeTitle()}", "No, ${dommeTitle()}")) {
+ present([DRESSED], [
+ ["Good boy"]]);
+ adjustPunish(-4 * target);
+ completed += 1;
+ if (completed >= 5) {
+ save("toy.deepthroat.goal", target + 1);
+ completed = 0;
+ }
}
else {
- present([DRESSED,TEASE], [
- ["Squeeze yours balls", "Grab your balls and squeeze them"],
- ["good and tight", "firm and hard"],
- ["until they hurt a little.", "as if I was doing it."]]);
- }
- wait(3 + getRandom(6));
- present(null, [
- ["Let them go.", "Hands off."]]);
- wait(3 + getRandom(6));
- };
-};
-def stateToyName = { state ->
- switch (state) {
- case CUFFED:
- return "cuffs";
- case COLLARED:
- return "collar";
- case CLAMPED:
- return "nipple clamps";
- case GAGGED:
- return "gag";
- }
- return null;
-};
-def removeToy = { toy, imageSpec ->
- if (!is(toy)) return;
- def toyName = stateToyName(toy);
- present(imageSpec, [
- ["OK,"],
- ["you may remove your $toyName.", "the $toyName can come off.", "take the $toyName off."]]);
- showButtonG("Thank you, ${dommeTitle()}", "ok");
- wait(5);
- set(toy, false);
- removeEvent("$RELEASEFROM-$toy");
- showButtonGT("Removed, ${dommeTitle()}", "removed", 20, 1);
-};
-// Session
-def sessionSummon = { imageSpec ->
- final limit = 5;
- final timeMax = 10;
-
- for (def n = 1; n <= limit; n++) {
- switch (n) {
- case limit:
- present(imageSpec, [
- ["TOY!", "SLAVE!", "SLUT!"],
- ["Last chance!", "Final warning!"]]);
- adjustPunish(5);
- break;
- case limit - 1:
- case limit - 2:
- present(imageSpec, [
- ["Toy!", "Slave!", "Slut!"],
- ["Where are you!?", "Get yourself here, now!"]]);
- break;
- default:
- present(imageSpec, [
- ["Toy!", "Slave!", "Slut!"]]);
- break;
+ final missed = getInteger("How many deep sucks did you miss?", 1);
+ if (missed > 5) {
+ present([DRESSED], [
+ ["Very disappointing."]]);
+ }
+ else {
+ present([DRESSED], [
+ ["Mmm"],
+ ["More practice required."]]);
+ }
+ adjustPunish(10 * missed);
+ completed -= 1;
+ if (completed <= -5) {
+ save("toy.deepthroat.goal", target - 1);
+ completed = 0;
+ }
}
- playBackgroundSound(n == limit ? "shortwhip.wav" : "bell.wav");
- if (showButton("Yes, ${dommeTitle()}?", timeMax) < timeMax) {
- return true;
+ save("toy.deepthroat.completed", completed);
+ wait(10);
+ };
+ def playClamps = {
+ if (!has(CLAMPS)) return;
+ if (!is(CLAMPED)) clamps();
+ clampsShow();
+ return clampPulls(3 + getRandom(10));
+ };
+ def intClamps = {
+ if (!has(CLAMPS)) return;
+ if (!is(CLAMPED)) return;
+ clampsShow();
+ return clampPulls(getRandom(5));
+ };
+ def intSqueeze = {
+ (2 + getRandom(4)).times { n ->
+ if (n > 0) {
+ present([DRESSED,TEASE], [
+ ["And again,", "Again,", "Once more,"],
+ ["harder!", "tighter!"]]);
+ }
+ else {
+ present([DRESSED,TEASE], [
+ ["Squeeze yours balls", "Grab your balls and squeeze them"],
+ ["good and tight", "firm and hard"],
+ ["until they hurt a little.", "as if I was doing it."]]);
+ }
+ wait(3 + getRandom(6));
+ present(null, [
+ ["Let them go.", "Hands off."]]);
+ wait(3 + getRandom(6));
};
- }
- showLounge();
- show(null);
- adjustPunish(5);
- return false;
-};
-final activityList = [
- 'intSqueeze': intSqueeze,
- 'intClamps': intClamps,
- 'preRelease': preRelease,
- 'preChastity': preChastity,
- 'preEdge': preEdge,
- 'preGag': preGag,
- 'preStrip': preStrip,
- 'preCollar': preCollar,
- 'preClamps': preClamps,
- 'playStrokes': playStrokes,
- 'playEdges': playEdges,
- 'playKneel': playKneel,
- 'playBeatBalls': playBeatBalls,
- 'playBeatCock': playBeatCock,
- 'playClamps': playClamps,
- 'playNothing': playNothing,
- 'playBondage': playBondage,
- 'playSuck': playSuck,
- 'postCum': postCum,
- 'postPermitCum': {
- addEventIfMissing(CUM, getTime() + (DAY * 2) + getRandom(DAY * 2), PERMIT, CUM); // 2 - 4 days from now
- },
- 'postChastity': postChastity
- ];
-def sessionPlay = {
- if (is(CHASTE)) sessionToys[CHASTITY] = getTime();
- def playScope = [
- 'randRange': randRange,
- 'currentPunishment': getPunish,
- 'sessionAborted': { return sessionAborted },
- 'can': can,
- 'has': has,
- 'is': is,
- 'likes': likes,
- 'punishMultiple': (float)1.0,
- 'prop': load('toy') ?: [:]
- ];
- def apply = { activitity, use = null ->
- if (!activitity) return;
- def val = activitity();
- playBackgroundSound(null);
- if (use && val instanceof Number) {
- use(val);
+ };
+ def stateToyName = { state ->
+ switch (state) {
+ case CUFFED:
+ return "cuffs";
+ case COLLARED:
+ return "collar";
+ case CLAMPED:
+ return "nipple clamps";
+ case GAGGED:
+ return "gag";
}
+ return null;
};
- def interval = { activities ->
- if (activities) {
- apply(activities[getRandom(activities.size())], null);
+ def removeToy = { toy, imageSpec ->
+ if (!is(toy)) return;
+ def toyName = stateToyName(toy);
+ present(imageSpec, [
+ ["OK,"],
+ ["you may remove your $toyName.", "the $toyName can come off.", "take the $toyName off."]]);
+ showButtonG("Thank you, ${dommeTitle()}", "ok");
+ wait(5);
+ set(toy, false);
+ removeEvent("$RELEASEFROM-$toy");
+ showButtonGT("Removed, ${dommeTitle()}", "removed", 20, 1);
+ };
+ // Session
+ def sessionSummon = { imageSpec ->
+ final limit = 5;
+ final timeMax = 10;
+
+ for (def n = 1; n <= limit; n++) {
+ switch (n) {
+ case limit:
+ present(imageSpec, [
+ ["TOY!", "SLAVE!", "SLUT!"],
+ ["Last chance!", "Final warning!"]]);
+ adjustPunish(5);
+ break;
+ case limit - 1:
+ case limit - 2:
+ present(imageSpec, [
+ ["Toy!", "Slave!", "Slut!"],
+ ["Where are you!?", "Get yourself here, now!"]]);
+ break;
+ default:
+ present(imageSpec, [
+ ["Toy!", "Slave!", "Slut!"]]);
+ break;
+ }
+ playBackgroundSound(n == limit ? "shortwhip.wav" : "bell.wav");
+ if (showButton("Yes, ${dommeTitle()}?", timeMax) < timeMax) {
+ return true;
+ };
}
+ showLounge();
+ show(null);
+ adjustPunish(5);
+ return false;
};
- def funcMap = [
- 'use': [
- 'punishMultiply': { val ->
- if (val) {
- playScope.punishMultiple *= val;
+ final activityList = [
+ 'intSqueeze': intSqueeze,
+ 'intClamps': intClamps,
+ 'preRelease': preRelease,
+ 'preChastity': preChastity,
+ 'preEdge': preEdge,
+ 'preGag': preGag,
+ 'preStrip': preStrip,
+ 'preCollar': preCollar,
+ 'preClamps': preClamps,
+ 'playStrokes': playStrokes,
+ 'playEdges': playEdges,
+ 'playKneel': playKneel,
+ 'playBeatBalls': playBeatBalls,
+ 'playBeatCock': playBeatCock,
+ 'playClamps': playClamps,
+ 'playNothing': playNothing,
+ 'playBondage': playBondage,
+ 'playSuck': playSuck,
+ 'postCum': postCum,
+ 'postPermitCum': {
+ addEventIfMissing(CUM, getTime() + (DAY * 2) + getRandom(DAY * 2), PERMIT, CUM); // 2 - 4 days from now
+ },
+ 'postChastity': postChastity
+ ];
+ def sessionPlay = {
+ if (is(CHASTE)) sessionToys[CHASTITY] = getTime();
+ def playScope = [
+ 'randRange': randRange,
+ 'currentPunishment': getPunish,
+ 'sessionAborted': { return sessionAborted },
+ 'can': can,
+ 'has': has,
+ 'is': is,
+ 'likes': likes,
+ 'punishMultiple': (float)1.0,
+ 'prop': load('toy') ?: [:]
+ ];
+ def apply = { activitity, use = null ->
+ if (!activitity) return;
+ def val = activitity();
+ playBackgroundSound(null);
+ if (use && val instanceof Number) {
+ use(val);
+ }
+ };
+ def interval = { activities ->
+ if (activities) {
+ apply(activities[getRandom(activities.size())], null);
+ }
+ };
+ def funcMap = [
+ 'use': [
+ 'punishMultiply': { val ->
+ if (val) {
+ playScope.punishMultiple *= val;
+ }
+ },
+ 'punishApply': { val ->
+ if (val) {
+ adjustPunish(-val * playScope.punishMultiple);
+ }
+ }
+ ],
+ 'select': [
+ 'repeat': { amount, activities, intervals, use = null ->
+ amount.times {
+ if (!sessionAborted) {
+ apply(activities[getRandom(activities.size())], use);
+ interval(intervals);
+ }
+ };
+ },
+ 'take': { amount, activities, intervals, use = null ->
+ Collections.shuffle(activities);
+ activities.take(amount).each {
+ if (!sessionAborted) {
+ apply(it, use);
+ interval(intervals);
+ }
+ };
}
- },
- 'punishApply': { val ->
- if (val) {
- adjustPunish(-val * playScope.punishMultiple);
+ ],
+ 'activities': activityList
+ ];
+ final eval = { expr -> Eval.me('toy', playScope, expr.toString()) };
+ if (is("DEBUG")) {
+ // Check everything in DOMME evaluates and resolves
+ final checkIsFunc = { group, name ->
+ if (!name) return;
+ show("checking $group:$name is a function");
+ if (!(funcMap[group][name] instanceof Closure)) {
+ showPopup("$group:$name is not a function");
}
}
- ],
- 'select': [
- 'repeat': { amount, activities, intervals, use = null ->
- amount.times {
- if (!sessionAborted) {
- apply(activities[getRandom(activities.size())], use);
- interval(intervals);
+ final checkEval = { expr ->
+ show("checking $expr evaluates");
+ eval(expr);
+ };
+ DOMME.sessions.forEach { session ->
+ checkEval(session.require ?: true);
+ checkEval(session.probability);
+ session.phases.forEach { phase ->
+ checkEval(phase.require ?: true);
+ checkIsFunc("select", phase.select);
+ checkEval(phase.number ?: 1);
+ phase.activities.forEach { a ->
+ checkIsFunc("activities", a);
}
- };
- },
- 'take': { amount, activities, intervals, use = null ->
- Collections.shuffle(activities);
- activities.take(amount).each {
- if (!sessionAborted) {
- apply(it, use);
- interval(intervals);
+ (phase.intervals ?: []).forEach { i ->
+ checkIsFunc("activities", i);
}
+ checkIsFunc("use", phase.use);
};
- }
- ],
- 'activities': activityList
- ];
- final eval = { expr -> Eval.me('toy', playScope, expr.toString()) };
- if (is("DEBUG")) {
- // Check everything in DOMME evaluates and resolves
- final checkIsFunc = { group, name ->
- if (!name) return;
- show("checking $group:$name is a function");
- if (!(funcMap[group][name] instanceof Closure)) {
- showPopup("$group:$name is not a function");
- }
+ };
}
- final checkEval = { expr ->
- show("checking $expr evaluates");
- eval(expr);
+ final sessions = DOMME.sessions.findAll { s -> eval(s.require ?: true) };
+ final probabilities = sessions.withIndex().collect { s, idx -> [idx] * s.probability }.sum();
+ final sessionIdx = probabilities[getRandom(probabilities.size)];
+ sessions[sessionIdx].phases.forEach { phase ->
+ if (eval(phase.require ?: true)) {
+ funcMap.select[phase.select ?: 'take'](eval(phase.number ?: 1),
+ (phase.activities ?: []).collect { f -> funcMap.activities[f] },
+ (phase.intervals ?: []).collect { f -> funcMap.activities[f] },
+ funcMap.use[phase.use]);
+ }
};
- DOMME.sessions.forEach { session ->
- checkEval(session.require ?: true);
- checkEval(session.probability);
- session.phases.forEach { phase ->
- checkEval(phase.require ?: true);
- checkIsFunc("select", phase.select);
- checkEval(phase.number ?: 1);
- phase.activities.forEach { a ->
- checkIsFunc("activities", a);
+ };
+ def sessionRelease = { goodToy ->
+ if (goodToy) {
+ present([DRESSED], [
+ ["Ahhh,", "OK,"],
+ ["I'm done with you for now.", "That was fun... for me at least."]]);
+ }
+ else {
+ present([DRESSED], [
+ ["I don't ask much of you, toy."]]);
+ wait(getRandom(10) + 5);
+ postChastity();
+ }
+ wait(getRandom(10) + 5);
+ def toys = TOYTOYS.findAll { t -> is(t) };
+ Collections.shuffle(toys);
+ if (toys) {
+ if (!goodToy) {
+ present([DRESSED], [
+ ["I should leave you like that.", "I suppose you still want letting free?"],
+ ["Maybe.", "Let me ponder on it."]]);
+ wait(getRandom(20) + 20);
+ }
+ toys.each { toy ->
+ if (getRandom(100) > ((goodToy && (getPunish() < 100)) ? 10 : 80)) {
+ removeToy(toy, [DRESSED]);
}
- (phase.intervals ?: []).forEach { i ->
- checkIsFunc("activities", i);
+ else {
+ addEvent("$RELEASEFROM-$toy", getTime() + 100 + getRandom(10 * (getPunish() + 1)),
+ RELEASEFROM, toy);
+ adjustPunish(-5);
}
- checkIsFunc("use", phase.use);
};
- };
- }
- final sessions = DOMME.sessions.findAll { s -> eval(s.require ?: true) };
- final probabilities = sessions.withIndex().collect { s, idx -> [idx] * s.probability }.sum();
- final sessionIdx = probabilities[getRandom(probabilities.size)];
- sessions[sessionIdx].phases.forEach { phase ->
- if (eval(phase.require ?: true)) {
- funcMap.select[phase.select ?: 'take'](eval(phase.number ?: 1),
- (phase.activities ?: []).collect { f -> funcMap.activities[f] },
- (phase.intervals ?: []).collect { f -> funcMap.activities[f] },
- funcMap.use[phase.use]);
- }
- };
-};
-def sessionRelease = { goodToy ->
- if (goodToy) {
- present([DRESSED], [
- ["Ahhh,", "OK,"],
- ["I'm done with you for now.", "That was fun... for me at least."]]);
- }
- else {
- present([DRESSED], [
- ["I don't ask much of you, toy."]]);
- wait(getRandom(10) + 5);
- postChastity();
- }
- wait(getRandom(10) + 5);
- def toys = TOYTOYS.findAll { t -> is(t) };
- Collections.shuffle(toys);
- if (toys) {
- if (!goodToy) {
- present([DRESSED], [
- ["I should leave you like that.", "I suppose you still want letting free?"],
- ["Maybe.", "Let me ponder on it."]]);
- wait(getRandom(20) + 20);
}
- toys.each { toy ->
- if (getRandom(100) > ((goodToy && (getPunish() < 100)) ? 10 : 80)) {
- removeToy(toy, [DRESSED]);
+ if (is(NAKED)) {
+ if (goodToy && getRandom(1)) {
+ present([DRESSED], [
+ ["Put some clothes back on.", "Cover yourself up!"]]);
+ wait(getRandom(10) + 15);
+ set(NAKED, false);
}
else {
- addEvent("$RELEASEFROM-$toy", getTime() + 100 + getRandom(10 * (getPunish() + 1)),
- RELEASEFROM, toy);
- adjustPunish(-5);
+ present([DRESSED], [
+ ["No clothes now for a while,", "Keep those clothes off,"],
+ ["you don't get clothes until I say.", "I like seeing you naked."]]);
+ addEvent(REDRESS, getTime() + 600 + getRandom(1200), "redress");
+ showButtonG("Yes, ${dommeTitle()}", "ok");
}
- };
- }
- if (is(NAKED)) {
- if (goodToy && getRandom(1)) {
+ }
+ if (goodToy) {
present([DRESSED], [
- ["Put some clothes back on.", "Cover yourself up!"]]);
- wait(getRandom(10) + 15);
- set(NAKED, false);
+ ["Off you go.", "You may leave."]]);
}
else {
present([DRESSED], [
- ["No clothes now for a while,", "Keep those clothes off,"],
- ["you don't get clothes until I say.", "I like seeing you naked."]]);
- addEvent(REDRESS, getTime() + 600 + getRandom(1200), "redress");
- showButtonG("Yes, ${dommeTitle()}", "ok");
+ ["Get out of my sight.", "Go!"]]);
+ removeEvent(CUM);
+ revokePermission(CUM);
}
- }
- if (goodToy) {
- present([DRESSED], [
- ["Off you go.", "You may leave."]]);
- }
- else {
- present([DRESSED], [
- ["Get out of my sight.", "Go!"]]);
- removeEvent(CUM);
- revokePermission(CUM);
- }
- wait(10);
- save("toy.lastPlay", getTime());
- showLounge();
- sessionAborted = null;
- sessionToys = [:];
- if (goodToy) {
- adjustPunish(-20);
- }
- show(null);
-};
-def playActivity = {
- final keys = new ArrayList<?>(activityList.keySet());
- final act = getSelectedValue("Choose activity", keys);
- activityList[keys[act]]();
-};
-def playWait = {
- present([DRESSED,nTEASE], [
- ["Hello,", "Hi,", "Hey there,"],
- ["toy.", "slut.", "slave."],
- ["On your knees,", "On the floor,", "Down... at my feet,",],
- ["wait there.", "wait patiently.", "don't move."],
- ["I'll be with you shortly.", "I won't be a moment."]]);
- showButtonGT("Yes, ${dommeTitle()}", "ok", 10, 1);
- showLounge();
- show(null);
- wait(20 + getRandom(20));
-};
-def playSchedule = {
- if (getAway()) return;
- final lastPlay = loadInteger("toy.lastPlay") ?: 0;
- if (lastPlay < getTime() - (4 * HOUR)) {
- addEventIfMissing(PLAY, getTime() + 120 + getRandom(480), PLAY, true); // 2-10mins
- }
- else {
- addEventIfMissing(PLAY, getTime() + 1200 + getRandom(5400), PLAY, false); // 20-90mins
- }
-};
-def playEvent = { rt = true, first = true ->
- if (!rt || getAway()) return;
- dress([[DRESSED,nTEASE],[DRESSED,TEASE],[TITS],[STOOD]]);
- if (sessionSummon([DRESSED,nTEASE])) {
- if (first.asBoolean()) {
- playWait();
- }
- sessionPlay();
- sessionRelease(sessionAborted == null);
- }
- else {
- adjustPunish(25);
- }
- playSchedule();
- showLounge();
-}
-def sleepSchedule = {
- def t = (int)(getDay() - localTimeOffset() + (25.1 * HOUR) + getRandom((int)HOUR));
- addEventIfMissing(SLEEPING, t, BEDTIME);
-};
-def bedtime = { rt, schedTime ->
- dress([[LINGERIE,nTITS]]);
- if (rt && sessionSummon([LINGERIE,nTITS])) {
- preStrip([LINGERIE,nTITS]);
- def toys = TOYTOYS.findAll { t -> is(t) };
- Collections.shuffle(toys);
- toys.each { removeToy(it, [LINGERIE,nTITS]) };
- present([LINGERIE,nTITS], [
- ["Very good, toy.", "OK."],
- ["Bedtime for you!", "Off to bed with you!", "Bed! Now!"]]);
- showButtonG("Good night, ${dommeTitle()}", "night");
- addEvent(BEDTIMECHECK, getTime() + 300 + getRandom(600), BEDTIMECHECK);
+ wait(10);
+ save("toy.lastPlay", getTime());
showLounge();
- }
- // Assume toy will return dressed tomorrow
- removeEvent(REDRESS);
- set(NAKED, false);
- // Assume toy will release himself
- TOYTOYS.findAll { t -> is(t) }.each {
- removeEvent("$RELEASEFROM-$it");
- set(it, false);
- };
- setAway(SLEEPING);
- def t = schedTime + (6 * (int)HOUR) + getRandom(2 * (int)HOUR);
- addEvent(SLEEPING, t, WAKEUP);
- removeEvent(PLAY);
-};
-def bedtimeCheck = { rt ->
- dress([[LINGERIE,nTITS]]);
- if (rt && sessionSummon([LINGERIE,nTITS])) {
- present([LINGERIE,nTITS], [
- ["Hey!", "Ah ha!"],
- ["What are you doing still up?", "Didn't I send you to bed?"]]);
- showButtonG("Sorry, ${dommeTitle()}", "sorry");
- present([LINGERIE,nTITS], [
- ["Get yourself to bed", "In bed"],
- ["right now!", "this instant!"],
- ["I'll deal with you later."]]);
- showButtonG("Yes, ${dommeTitle()}", "ok");
- adjustPunish(75);
+ sessionAborted = null;
+ sessionToys = [:];
+ if (goodToy) {
+ adjustPunish(-20);
+ }
+ show(null);
+ };
+ def playActivity = {
+ final keys = new ArrayList<?>(activityList.keySet());
+ final act = getSelectedValue("Choose activity", keys);
+ activityList[keys[act]]();
+ };
+ def playWait = {
+ present([DRESSED,nTEASE], [
+ ["Hello,", "Hi,", "Hey there,"],
+ ["toy.", "slut.", "slave."],
+ ["On your knees,", "On the floor,", "Down... at my feet,",],
+ ["wait there.", "wait patiently.", "don't move."],
+ ["I'll be with you shortly.", "I won't be a moment."]]);
+ showButtonGT("Yes, ${dommeTitle()}", "ok", 10, 1);
showLounge();
- }
-};
-def wakeup = { rt ->
- // Unset outfit, stops bedtime wear always being selected first
- save("toy.owner.outfit", null);
- dress([]);
- setAway(null);
- playSchedule();
- sleepSchedule();
-};
-def redress = { rt ->
- if (!rt || !sessionSummon([DRESSED])) {
- addEvent(REDRESS, getTime() + 300, "redress");
- return;
- }
- present([DRESSED], [
- ["OK, toy,"],
- ["you can put some clothes back on now.", "get yourself covered up."]]);
- wait(getRandom(10) + 15);
- showButtonG("Thank you, ${dommeTitle()}", "ok");
- set(NAKED, false);
- showLounge();
-};
-def releaseFrom = { rt, arg, name ->
- if (!rt || !sessionSummon([DRESSED])) {
- addEvent(name, getTime() + 300, RELEASEFROM, arg);
- return;
- }
- removeToy(arg, [DRESSED]);
- showLounge();
-};
-def requestClothes = {
- adjustPunish(5);
- present([DRESSED], [
- ["Really?", "Disappointing."],
- ["You want to clothes back on?", "You wish to cover up?"]]);
- if (getBoolean(null)) {
- present([DRESSED], [["Hmm, very well.", "If you must."]]);
- adjustPunish(50);
- set(NAKED, false);
- removeEvent(REDRESS);
- }
- else {
- present([DRESSED], [["Good boy."]]);
- }
- showButtonG("Thank you, ${dommeTitle()}", "ok");
- showLounge();
-};
-def requestRelease = { toy ->
- adjustPunish(5);
- present([DRESSED], [
- ["Really?", "Disappointing."],
- ["You wish to be un-$toy?"]]);
- if (getBoolean(null)) {
- adjustPunish(10);
- if (getRandom(100) > getPunish()) {
- present([DRESSED], [["No.", "You may not."],
- ["Not yet.", "Not until later."]]);
+ show(null);
+ wait(20 + getRandom(20));
+ };
+ def playSchedule = {
+ if (getAway()) return;
+ final lastPlay = loadInteger("toy.lastPlay") ?: 0;
+ if (lastPlay < getTime() - (4 * HOUR)) {
+ addEventIfMissing(PLAY, getTime() + 120 + getRandom(480), PLAY, true); // 2-10mins
}
else {
- present([DRESSED], [["Hmm, very well.", "If you must."]]);
- set(toy, false);
- removeEvent("$RELEASEFROM-$toy");
+ addEventIfMissing(PLAY, getTime() + 1200 + getRandom(5400), PLAY, false); // 20-90mins
}
- }
- else {
- present([DRESSED], [["Good boy."]]);
- }
- showButtonG("Thank you, ${dommeTitle()}", "ok");
- showLounge();
-};
-// Confession
-def confessChastityRelease = {
- adjustPunish(75);
- present([DRESSED, nTEASE], [
- ["Bad toy!", "Naughty little slut."],
- ["I don't keep it locked for nothing.", "It's locked for a reason."],
- ["It better have been a good reason.", "I'll presume you had a valid excuse."],
- ["Is it locked again now?", "Are you back in chastity now?"]]);
- if (getBoolean(null)) {
- present([DRESSED, nTEASE], [
- ["Good!", "There's that at least."]]);
- showButtonG("Yes, ${dommeTitle()}", "ok");
- }
- else {
- adjustPunish(300);
- present([DRESSED, nTEASE], [
- ["disobedient", "dirty", "cheeky"],
- ["little"],
- ["slut!", "whore!", "brat!"],
- ["Get it locked back up", "Back in chastity"],
- ["right now!", "this instant!"]]);
- showButtonGT("Locked, ${dommeTitle()}. Here's the key.", "locked", 180, 1);
- }
- if (getBoolean("Did you get erect whilst out?")) {
- adjustPunish(50);
- if (getBoolean("Did you cum!?")) {
- adjustPunish(200);
+ };
+ def playEvent = { rt = true, first = true ->
+ if (!rt || getAway()) return;
+ dress([[DRESSED,nTEASE],[DRESSED,TEASE],[TITS],[STOOD]]);
+ if (sessionSummon([DRESSED,nTEASE])) {
+ if (first.asBoolean()) {
+ playWait();
+ }
+ sessionPlay();
+ sessionRelease(sessionAborted == null);
}
- }
- adjustPunish(getInteger("How many hours were you out?", 1) * 10);
-};
-def confessStroked = {
- adjustPunish(40);
- present([DRESSED,nTEASE], [
- ["Awww, poor little toy.", "Naught little toy!"],
- ["You know you aren't allowed.", "You get to stroke only when I say."]]);
- showButtonG("Sorry, ${dommeTitle()}", "sorry");
- if (getBoolean("Did you get to the edge?")) {
- adjustPunish(40);
- adjustPunish(getInteger("How many times?", 1) * 5);
- if (getBoolean("Did you cum!?")) {
- adjustPunish(200);
+ else {
+ adjustPunish(25);
}
+ playSchedule();
+ showLounge();
}
-};
-def confess = {
- // 5 points just for feeling the need to confess
- def op = getPunish();
- adjustPunish(5);
- dress([[DRESSED,nTEASE], [MEAN]]);
- while (true) {
- present([DRESSED, nTEASE], [
- ["I'm not going to like this, am I?", "There is no way this ends well for you."],
- ["Out with it.", "Let me hear it."]]);
- def opts = [ ];
- if (is(CHASTE)) {
- opts.push([lbl: "Freed from chastity", act: confessChastityRelease]);
- }
- if (!is(CHASTE)) {
- opts.push([lbl: "Stroked", act: confessStroked]);
- }
- opts.push([ lbl: "Nothing listed (phew!)", act: null ]);
- def opt = getSelectedValue(null, opts.collect { it.lbl });
- def act = opts[opt].act;
- if (!act) {
+ def sleepSchedule = {
+ def t = (int)(getDay() - localTimeOffset() + (25.1 * HOUR) + getRandom((int)HOUR));
+ addEventIfMissing(SLEEPING, t, BEDTIME);
+ };
+ def bedtime = { rt, schedTime ->
+ dress([[LINGERIE,nTITS]]);
+ if (rt && sessionSummon([LINGERIE,nTITS])) {
+ preStrip([LINGERIE,nTITS]);
+ def toys = TOYTOYS.findAll { t -> is(t) };
+ Collections.shuffle(toys);
+ toys.each { removeToy(it, [LINGERIE,nTITS]) };
+ present([LINGERIE,nTITS], [
+ ["Very good, toy.", "OK."],
+ ["Bedtime for you!", "Off to bed with you!", "Bed! Now!"]]);
+ showButtonG("Good night, ${dommeTitle()}", "night");
+ addEvent(BEDTIMECHECK, getTime() + 300 + getRandom(600), BEDTIMECHECK);
showLounge();
- return;
}
- act();
- if (!getBoolean("Anything else?")) break;
- }
- // If sufficient points accrued, punish immediately.. with a bonus
- if (getPunish() > 150 + op) {
- present([MEAN], [
- ["I'm very disappointed in you.", "You've been a very bad toy!"],
- ["Immediate punishment!", "So you will suffer... right now!"]]);
- adjustPunish(100);
- showButtonG("Yes, ${dommeTitle()}", "ok");
+ // Assume toy will return dressed tomorrow
+ removeEvent(REDRESS);
+ set(NAKED, false);
+ // Assume toy will release himself
+ TOYTOYS.findAll { t -> is(t) }.each {
+ removeEvent("$RELEASEFROM-$it");
+ set(it, false);
+ };
+ setAway(SLEEPING);
+ def t = schedTime + (6 * (int)HOUR) + getRandom(2 * (int)HOUR);
+ addEvent(SLEEPING, t, WAKEUP);
removeEvent(PLAY);
- sessionPlay();
- sessionRelease(sessionAborted == null);
+ };
+ def bedtimeCheck = { rt ->
+ dress([[LINGERIE,nTITS]]);
+ if (rt && sessionSummon([LINGERIE,nTITS])) {
+ present([LINGERIE,nTITS], [
+ ["Hey!", "Ah ha!"],
+ ["What are you doing still up?", "Didn't I send you to bed?"]]);
+ showButtonG("Sorry, ${dommeTitle()}", "sorry");
+ present([LINGERIE,nTITS], [
+ ["Get yourself to bed", "In bed"],
+ ["right now!", "this instant!"],
+ ["I'll deal with you later."]]);
+ showButtonG("Yes, ${dommeTitle()}", "ok");
+ adjustPunish(75);
+ showLounge();
+ }
+ };
+ def wakeup = { rt ->
+ // Unset outfit, stops bedtime wear always being selected first
+ save("toy.owner.outfit", null);
+ dress([]);
+ setAway(null);
playSchedule();
- }
- else {
- present([DRESSED, nTEASE], [
- ["Good!", "There better not be!"]]);
- showButtonG("Yes, ${dommeTitle()}", "ok");
+ sleepSchedule();
+ };
+ def redress = { rt ->
+ if (!rt || !sessionSummon([DRESSED])) {
+ addEvent(REDRESS, getTime() + 300, "redress");
+ return;
+ }
+ present([DRESSED], [
+ ["OK, toy,"],
+ ["you can put some clothes back on now.", "get yourself covered up."]]);
+ wait(getRandom(10) + 15);
+ showButtonG("Thank you, ${dommeTitle()}", "ok");
+ set(NAKED, false);
showLounge();
- }
-};
-
-// Setup
-// Plans - cannot overlap
-def setupPlan = { plan, float startmin, float startmax, float endmin, float endmax ->
- def timeWindow = { float min, float max -> (int)((min * HOUR) - localTimeOffset() + getRandom((int)((max - min) * HOUR))) };
- final friendName = FRIENDS[getRandom(FRIENDS.size())];
- def day = getDay() + ((getRandom(3) + 1) * DAY);
- addEventIfMissing(plan, day + timeWindow(startmin, startmax), BEGINPLAN,
- [friendName: friendName, returnTime: day + timeWindow(endmin, endmax)]);
-}
-def setupPlans = {
- save("toy.plan", null);
- setupPlan(LUNCH, 11.5, 12.5, 13.0, 14.0)
- setupPlan(SHOPPING, 14.5, 15.5, 16.0, 18.0)
- setupPlan(PARTY, 19, 20, 22.0, 25.0)
-};
-def setupEvents = {
- playSchedule();
- sleepSchedule();
- setupPlans();
-};
-def setDefault = { prop, val ->
- if (loadString(prop) == null) {
- save(prop, val);
- }
-};
-def leaveNote = { msg, instr ->
- save("toy.note", msg);
- save("toy.noteInstr", instr);
-};
-def readNote = {
- leaveNote(null, null);
-};
-def plannedCheck = { plan ->
- return (getTime() > loadInteger("toy.plan.${plan}.${START}") && getTime() < loadInteger("toy.plan.${plan}.${END}"));
-}
-def beginPlan = { rt, plan, args ->
- addEvent(plan, args.returnTime, ENDPLAN, args.friendName);
- dress([[DRESSED,nTEASE], [DRESSED,TEASE]]);
- if (rt && sessionSummon([DRESSED,nTEASE])) {
- present([DRESSED,nTEASE], [
- [ "I'm going out now, toy.", "$plan time!" ],
- [ "Will you be good while I'm gone?", "You will behave as I expect?" ]]);
- wait(10);
- postChastity();
- def toys = TOYTOYS.findAll { t -> is(t) };
- Collections.shuffle(toys);
- toys.each { removeToy(it, [DRESSED,nTEASE]) };
- present([DRESSED,TEASE], [
- [ "Back later!", "See you soon, toy" ]]);
- wait(5);
- }
- else if (has(CHASTITY) && !is(CHASTE)) {
- leaveNote("I want you in chastity until I return!", CHASTE);
- }
- DOMME = loadDomme(OWNER);
- setAway(plan);
- removeEvent(PLAY);
- showLounge();
-};
-def endPlan = { rt, plan ->
- save("toy.owner.outfitTime", getTime());
- setAway(null);
- if (rt && sessionSummon([DRESSED])) {
- present([DRESSED], [["Hello, toy!"], ["I'm back home now."]]);
- wait(10);
+ };
+ def releaseFrom = { rt, arg, name ->
+ if (!rt || !sessionSummon([DRESSED])) {
+ addEvent(name, getTime() + 300, RELEASEFROM, arg);
+ return;
+ }
+ removeToy(arg, [DRESSED]);
showLounge();
- }
- readNote();
- playSchedule();
- setupPlans();
-};
-// Initial - basic checks and defaults
-namedEvents = [
- bedtime: { name, arg, schedTime, rt -> bedtime(rt, schedTime) },
- bedtimeCheck: { name, arg, schedTime, rt -> bedtimeCheck(rt) },
- wakeup: { name, arg, schedTime, rt -> wakeup(rt) },
- beginPlan: { name, arg, schedTime, rt -> beginPlan(rt, name, arg) },
- endPlan: { name, arg, schedTime, rt -> endPlan(rt, name) },
- play: { name, arg, schedTime, rt -> playEvent(rt, arg) },
- releaseFrom: { name, arg, schedTime, rt -> releaseFrom(rt, arg, name) },
- redress: { name, arg, schedTime, rt -> redress(rt) },
- permit: { name, arg, schedTime, rt -> givePermission(arg) }
-];
-def setupInitial = {
- if (loadInteger("toy.version") == null) {
- // Welcome
- dress([[DRESSED,nTEASE], [DRESSED,TEASE], [TITS]]);
- def name = loadString("intro.name");
- present([DRESSED,nTEASE], [
- ["Welcome, $name, to your new life as my plaything, my toy."]]);
- showButton("Thank you, ${dommeTitle()}");
- present([DRESSED,nTEASE], [
- ["My rules are simple, do what I say, when I say, and you'll be rewarded... eventually."]]);
- showButton("Thank you, ${dommeTitle()}");
- present([DRESSED,nTEASE], [
- ["But if you disappointment me, disobey me or disrespect me, then you'll be punished."]]);
- showButton("Yes, ${dommeTitle()}");
- present([DRESSED,TEASE], [
- ["I will tease you... and I will torment you..."]]);
- showButton("Yes, ${dommeTitle()}");
- present([TITS], [
- ["... and I will break... and then you will suffer!"]]);
- showButton("Thank you, ${dommeTitle()}");
- present([TITS], [
- ["Now, your devotion is important to me."],
- ["I have expectations my toy be available to play with as much as possible."]]);
- showButton("Yes, ${dommeTitle()}");
- present([TITS], [
- ["You can indicate your availability by running this script."],
- ["I will summon you when I wish to play."]]);
- showButton("Understood, ${dommeTitle()}");
- present([DRESSED,TEASE], [
- ["Would you like to set this script as default?"]]);
+ };
+ def requestClothes = {
+ adjustPunish(5);
+ present([DRESSED], [
+ ["Really?", "Disappointing."],
+ ["You want to clothes back on?", "You wish to cover up?"]]);
if (getBoolean(null)) {
- save("intro.start_script", "toy");
- present([DRESSED,nTEASE], [
- ["Good boy."]]);
- showButton("Thank you, ${dommeTitle()}");
+ present([DRESSED], [["Hmm, very well.", "If you must."]]);
+ adjustPunish(50);
+ set(NAKED, false);
+ removeEvent(REDRESS);
+ }
+ else {
+ present([DRESSED], [["Good boy."]]);
+ }
+ showButtonG("Thank you, ${dommeTitle()}", "ok");
+ showLounge();
+ };
+ def requestRelease = { toy ->
+ adjustPunish(5);
+ present([DRESSED], [
+ ["Really?", "Disappointing."],
+ ["You wish to be un-$toy?"]]);
+ if (getBoolean(null)) {
+ adjustPunish(10);
+ if (getRandom(100) > getPunish()) {
+ present([DRESSED], [["No.", "You may not."],
+ ["Not yet.", "Not until later."]]);
+ }
+ else {
+ present([DRESSED], [["Hmm, very well.", "If you must."]]);
+ set(toy, false);
+ removeEvent("$RELEASEFROM-$toy");
+ }
+ }
+ else {
+ present([DRESSED], [["Good boy."]]);
}
+ showButtonG("Thank you, ${dommeTitle()}", "ok");
+ showLounge();
+ };
+ // Confession
+ def confessChastityRelease = {
+ adjustPunish(75);
+ present([DRESSED, nTEASE], [
+ ["Bad toy!", "Naughty little slut."],
+ ["I don't keep it locked for nothing.", "It's locked for a reason."],
+ ["It better have been a good reason.", "I'll presume you had a valid excuse."],
+ ["Is it locked again now?", "Are you back in chastity now?"]]);
+ if (getBoolean(null)) {
+ present([DRESSED, nTEASE], [
+ ["Good!", "There's that at least."]]);
+ showButtonG("Yes, ${dommeTitle()}", "ok");
+ }
+ else {
+ adjustPunish(300);
+ present([DRESSED, nTEASE], [
+ ["disobedient", "dirty", "cheeky"],
+ ["little"],
+ ["slut!", "whore!", "brat!"],
+ ["Get it locked back up", "Back in chastity"],
+ ["right now!", "this instant!"]]);
+ showButtonGT("Locked, ${dommeTitle()}. Here's the key.", "locked", 180, 1);
+ }
+ if (getBoolean("Did you get erect whilst out?")) {
+ adjustPunish(50);
+ if (getBoolean("Did you cum!?")) {
+ adjustPunish(200);
+ }
+ }
+ adjustPunish(getInteger("How many hours were you out?", 1) * 10);
+ };
+ def confessStroked = {
+ adjustPunish(40);
present([DRESSED,nTEASE], [
- ["Run along now, toy."],
- ["I'll summon you with a bell when I want you."],
- ["Lisen carefully!"]]);
- showButton("Yes, ${dommeTitle()}");
- present(null, [
- ["All images are the property of their respective owners, see watermarks (OnlyTease, ForeverVamp).\n"],
- ["Don't do anything you aren't 100% comfortable doing.\n"],
- ["Be sure to have configured your toys!"]]);
- showButton("OK");
- }
- save("toy.version", VERSION);
- setDefault("toy.strokeTeaseOffset", 0);
- setDefault("toy.punishment", 0);
- execEvents(false);
- setupEvents();
-};
-def setupShowState = {
- show(
- [CHASTE, COLLARED, CUFFED, CLAMPED, GAGGED, NAKED].collect {
- def v = is(it);
- return "$it: $v\n".capitalize()
- }.join());
- showButton("OK");
- show(
- [BALLGAG, COLLAR, CLAMPS, CHASTITY, HANDCUFFS, DILDO].collect {
- def v = has(it);
- return "$it: $v\n".capitalize()
- }.join());
- showButton("OK");
- show(
- [BONDAGE, CBT, CHORES, PAIN].collect {
- def v = likes(it);
- return "$it: $v\n".capitalize()
- }.join());
- showButton("OK");
-};
-def showFaq = {
- useUrl("http://toy.randomdan.homeip.net/");
-};
-def setupShowCalendar = {
- final events = loadEvents();
- show(
- [LUNCH, SHOPPING, PARTY].collect {
- final event = events[it];
- if (!event) return "";
- def s = event.time;
- def f = event.arg.friendName;
- def timeStr = localTimeOf(s).format(soonFormatter);
- return "$it with $f on $timeStr.\n".capitalize();
- }.join());
- showButton("OK");
-};
-
-// GO!
-setDefault("toy.owner", "ancilla");
-OWNER = loadString("toy.owner");
-DOMME = loadDomme(OWNER);
-def getDayNum = { Math.floorDiv(getTime() - localTimeOffset() - 14400, 86400) };
-def getAvail = { dayNum -> loadInteger("toy.availability.$dayNum") ?: 0 };
-def addAvail = { amount ->
- def dayNum = getDayNum();
- save("toy.availability.$dayNum", (int)(getAvail(dayNum) + amount));
-};
-def tidyAvail = {
- def p = load("toy.availability");
- if (!p) return;
- def p2 = [:];
- final firstDay = getDayNum() - 20;
- p.eachWithIndex{ avail, day ->
- if (day >= firstDay && avail > 0) {
- p2["$day"] = avail;
+ ["Awww, poor little toy.", "Naught little toy!"],
+ ["You know you aren't allowed.", "You get to stroke only when I say."]]);
+ showButtonG("Sorry, ${dommeTitle()}", "sorry");
+ if (getBoolean("Did you get to the edge?")) {
+ adjustPunish(40);
+ adjustPunish(getInteger("How many times?", 1) * 5);
+ if (getBoolean("Did you cum!?")) {
+ adjustPunish(200);
+ }
}
- }
- save("toy.availability", p2);
-};
-setupInitial();
-tidyAvail();
-
-final cycleTime = 60;
-showLounge();
-while (true) {
- def away = getAway();
- def e = nextEvent(loadEvents());
- if (!e) return "toy"; // Force restart, should create some events
-
- if (away) {
- def note = loadString("toy.note");
- def noteInstr = loadString("toy.noteInstr");
- if (note) {
- show("${dommeTitle()} ${dommeName()} is away ($away)... but you find a note:\n$note");
- showButton("OK");
- if (noteInstr) {
- set(noteInstr, true);
+ };
+ def confess = {
+ // 5 points just for feeling the need to confess
+ def op = getPunish();
+ adjustPunish(5);
+ dress([[DRESSED,nTEASE], [MEAN]]);
+ while (true) {
+ present([DRESSED, nTEASE], [
+ ["I'm not going to like this, am I?", "There is no way this ends well for you."],
+ ["Out with it.", "Let me hear it."]]);
+ def opts = [ ];
+ if (is(CHASTE)) {
+ opts.push([lbl: "Freed from chastity", act: confessChastityRelease]);
}
- readNote();
+ if (!is(CHASTE)) {
+ opts.push([lbl: "Stroked", act: confessStroked]);
+ }
+ opts.push([ lbl: "Nothing listed (phew!)", act: null ]);
+ def opt = getSelectedValue(null, opts.collect { it.lbl });
+ def act = opts[opt].act;
+ if (!act) {
+ showLounge();
+ return;
+ }
+ act();
+ if (!getBoolean("Anything else?")) break;
+ }
+ // If sufficient points accrued, punish immediately.. with a bonus
+ if (getPunish() > 150 + op) {
+ present([MEAN], [
+ ["I'm very disappointed in you.", "You've been a very bad toy!"],
+ ["Immediate punishment!", "So you will suffer... right now!"]]);
+ adjustPunish(100);
+ showButtonG("Yes, ${dommeTitle()}", "ok");
+ removeEvent(PLAY);
+ sessionPlay();
+ sessionRelease(sessionAborted == null);
+ playSchedule();
}
else {
- show("${dommeTitle()} ${dommeName()} is away ($away)...");
+ present([DRESSED, nTEASE], [
+ ["Good!", "There better not be!"]]);
+ showButtonG("Yes, ${dommeTitle()}", "ok");
+ showLounge();
}
- if (e && e.event && e.event.time > getTime()) {
- wait(e.event.time - getTime());
+ };
+
+ // Setup
+ // Plans - cannot overlap
+ def setupPlan = { plan, float startmin, float startmax, float endmin, float endmax ->
+ def timeWindow = { float min, float max -> (int)((min * HOUR) - localTimeOffset() + getRandom((int)((max - min) * HOUR))) };
+ final friendName = FRIENDS[getRandom(FRIENDS.size())];
+ def day = getDay() + ((getRandom(3) + 1) * DAY);
+ addEventIfMissing(plan, day + timeWindow(startmin, startmax), BEGINPLAN,
+ [friendName: friendName, returnTime: day + timeWindow(endmin, endmax)]);
+ }
+ def setupPlans = {
+ save("toy.plan", null);
+ setupPlan(LUNCH, 11.5, 12.5, 13.0, 14.0)
+ setupPlan(SHOPPING, 14.5, 15.5, 16.0, 18.0)
+ setupPlan(PARTY, 19, 20, 22.0, 25.0)
+ };
+ def setupEvents = {
+ playSchedule();
+ sleepSchedule();
+ setupPlans();
+ };
+ def setDefault = { prop, val ->
+ if (loadString(prop) == null) {
+ save(prop, val);
}
+ };
+ def leaveNote = { msg, instr ->
+ save("toy.note", msg);
+ save("toy.noteInstr", instr);
+ };
+ def readNote = {
+ leaveNote(null, null);
+ };
+ def plannedCheck = { plan ->
+ return (getTime() > loadInteger("toy.plan.${plan}.${START}") && getTime() < loadInteger("toy.plan.${plan}.${END}"));
}
- else {
- if (is("DEBUG")) {
- def timeStr = localTimeOf(e.event.time).format(soonFormatter);
- show("$e.name: $timeStr -> ${e.event.func}(${e.event.arg})");
+ def beginPlan = { rt, plan, args ->
+ addEvent(plan, args.returnTime, ENDPLAN, args.friendName);
+ dress([[DRESSED,nTEASE], [DRESSED,TEASE]]);
+ if (rt && sessionSummon([DRESSED,nTEASE])) {
+ present([DRESSED,nTEASE], [
+ [ "I'm going out now, toy.", "$plan time!" ],
+ [ "Will you be good while I'm gone?", "You will behave as I expect?" ]]);
+ wait(10);
+ postChastity();
+ def toys = TOYTOYS.findAll { t -> is(t) };
+ Collections.shuffle(toys);
+ toys.each { removeToy(it, [DRESSED,nTEASE]) };
+ present([DRESSED,TEASE], [
+ [ "Back later!", "See you soon, toy" ]]);
+ wait(5);
}
- else {
- show("${dommeTitle()} ${dommeName()} will summon you when required.");
- }
- final waitTime = Math.min(cycleTime, e.event.time - getTime());
- final clickTime = showButton("Please, ${dommeTitle()}?", waitTime);
- if (clickTime < waitTime) {
- def opts = [
- [ lbl: "FAQ (webpage)", act: showFaq ],
- [ lbl: "Calendar", act: setupShowCalendar ],
- [ lbl: "Confess", act: confess ],
- ];
- if (is("DEBUG")) {
- opts.push([ lbl: "Status", act: setupShowState ]);
- opts.push([ lbl: "Play", act: playEvent, arg: true ]);
- opts.push([ lbl: "Activity", act: playActivity ]);
+ else if (has(CHASTITY) && !is(CHASTE)) {
+ leaveNote("I want you in chastity until I return!", CHASTE);
+ }
+ DOMME = loadDomme(OWNER);
+ setAway(plan);
+ removeEvent(PLAY);
+ showLounge();
+ };
+ def endPlan = { rt, plan ->
+ save("toy.owner.outfitTime", getTime());
+ setAway(null);
+ if (rt && sessionSummon([DRESSED])) {
+ present([DRESSED], [["Hello, toy!"], ["I'm back home now."]]);
+ wait(10);
+ showLounge();
+ }
+ readNote();
+ playSchedule();
+ setupPlans();
+ };
+ // Initial - basic checks and defaults
+ def namedEvents = [
+ bedtime: { name, arg, schedTime, rt -> bedtime(rt, schedTime) },
+ bedtimeCheck: { name, arg, schedTime, rt -> bedtimeCheck(rt) },
+ wakeup: { name, arg, schedTime, rt -> wakeup(rt) },
+ beginPlan: { name, arg, schedTime, rt -> beginPlan(rt, name, arg) },
+ endPlan: { name, arg, schedTime, rt -> endPlan(rt, name) },
+ play: { name, arg, schedTime, rt -> playEvent(rt, arg) },
+ releaseFrom: { name, arg, schedTime, rt -> releaseFrom(rt, arg, name) },
+ redress: { name, arg, schedTime, rt -> redress(rt) },
+ permit: { name, arg, schedTime, rt -> givePermission(arg) }
+ ];
+ def setupInitial = {
+ if (loadInteger("toy.version") == null) {
+ // Welcome
+ dress([[DRESSED,nTEASE], [DRESSED,TEASE], [TITS]]);
+ def name = loadString("intro.name");
+ present([DRESSED,nTEASE], [
+ ["Welcome, $name, to your new life as my plaything, my toy."]]);
+ showButton("Thank you, ${dommeTitle()}");
+ present([DRESSED,nTEASE], [
+ ["My rules are simple, do what I say, when I say, and you'll be rewarded... eventually."]]);
+ showButton("Thank you, ${dommeTitle()}");
+ present([DRESSED,nTEASE], [
+ ["But if you disappointment me, disobey me or disrespect me, then you'll be punished."]]);
+ showButton("Yes, ${dommeTitle()}");
+ present([DRESSED,TEASE], [
+ ["I will tease you... and I will torment you..."]]);
+ showButton("Yes, ${dommeTitle()}");
+ present([TITS], [
+ ["... and I will break... and then you will suffer!"]]);
+ showButton("Thank you, ${dommeTitle()}");
+ present([TITS], [
+ ["Now, your devotion is important to me."],
+ ["I have expectations my toy be available to play with as much as possible."]]);
+ showButton("Yes, ${dommeTitle()}");
+ present([TITS], [
+ ["You can indicate your availability by running this script."],
+ ["I will summon you when I wish to play."]]);
+ showButton("Understood, ${dommeTitle()}");
+ present([DRESSED,TEASE], [
+ ["Would you like to set this script as default?"]]);
+ if (getBoolean(null)) {
+ save("intro.start_script", "toy");
+ present([DRESSED,nTEASE], [
+ ["Good boy."]]);
+ showButton("Thank you, ${dommeTitle()}");
+ }
+ present([DRESSED,nTEASE], [
+ ["Run along now, toy."],
+ ["I'll summon you with a bell when I want you."],
+ ["Lisen carefully!"]]);
+ showButton("Yes, ${dommeTitle()}");
+ present(null, [
+ ["All images are the property of their respective owners, see watermarks (OnlyTease, ForeverVamp).\n"],
+ ["Don't do anything you aren't 100% comfortable doing.\n"],
+ ["Be sure to have configured your toys!"]]);
+ showButton("OK");
+ }
+ save("toy.version", VERSION);
+ setDefault("toy.strokeTeaseOffset", 0);
+ setDefault("toy.punishment", 0);
+ execEvents(false);
+ setupEvents();
+ };
+ def setupShowState = {
+ show(
+ [CHASTE, COLLARED, CUFFED, CLAMPED, GAGGED, NAKED].collect {
+ def v = is(it);
+ return "$it: $v\n".capitalize()
+ }.join());
+ showButton("OK");
+ show(
+ [BALLGAG, COLLAR, CLAMPS, CHASTITY, HANDCUFFS, DILDO].collect {
+ def v = has(it);
+ return "$it: $v\n".capitalize()
+ }.join());
+ showButton("OK");
+ show(
+ [BONDAGE, CBT, CHORES, PAIN].collect {
+ def v = likes(it);
+ return "$it: $v\n".capitalize()
+ }.join());
+ showButton("OK");
+ };
+ def showFaq = {
+ useUrl("http://toy.randomdan.homeip.net/");
+ };
+ def setupShowCalendar = {
+ final events = loadEvents();
+ show(
+ [LUNCH, SHOPPING, PARTY].collect {
+ final event = events[it];
+ if (!event) return "";
+ def s = event.time;
+ def f = event.arg.friendName;
+ def timeStr = localTimeOf(s).format(soonFormatter);
+ return "$it with $f on $timeStr.\n".capitalize();
+ }.join());
+ showButton("OK");
+ };
+
+ String main()
+ {
+ // GO!
+ setDefault("toy.owner", "ancilla");
+ OWNER = loadString("toy.owner");
+ DOMME = loadDomme(OWNER);
+ def getDayNum = { Math.floorDiv(getTime() - localTimeOffset() - 14400, 86400) };
+ def getAvail = { dayNum -> loadInteger("toy.availability.$dayNum") ?: 0 };
+ def addAvail = { amount ->
+ def dayNum = getDayNum();
+ save("toy.availability.$dayNum", (int)(getAvail(dayNum) + amount));
+ };
+ def tidyAvail = {
+ def p = load("toy.availability");
+ if (!p) return;
+ def p2 = [:];
+ final firstDay = getDayNum() - 20;
+ p.eachWithIndex{ avail, day ->
+ if (day >= firstDay && avail > 0) {
+ p2["$day"] = avail;
+ }
+ }
+ save("toy.availability", p2);
+ };
+ setupInitial();
+ tidyAvail();
+
+ final cycleTime = 60;
+ showLounge();
+ while (true) {
+ def away = getAway();
+ def e = nextEvent(loadEvents());
+ if (!e) return "toy"; // Force restart, should create some events
+
+ if (away) {
+ def note = loadString("toy.note");
+ def noteInstr = loadString("toy.noteInstr");
+ if (note) {
+ show("${dommeTitle()} ${dommeName()} is away ($away)... but you find a note:\n$note");
+ showButton("OK");
+ if (noteInstr) {
+ set(noteInstr, true);
+ }
+ readNote();
+ }
+ else {
+ show("${dommeTitle()} ${dommeName()} is away ($away)...");
+ }
+ if (e && e.event && e.event.time > getTime()) {
+ wait(e.event.time - getTime());
+ }
}
- if (is(NAKED)) {
- opts.push([ lbl: "May I wear clothes", act: requestClothes ]);
+ else {
+ if (is("DEBUG")) {
+ def timeStr = localTimeOf(e.event.time).format(soonFormatter);
+ show("$e.name: $timeStr -> ${e.event.func}(${e.event.arg})");
+ }
+ else {
+ show("${dommeTitle()} ${dommeName()} will summon you when required.");
+ }
+ final waitTime = Math.min(cycleTime, e.event.time - getTime());
+ final clickTime = showButton("Please, ${dommeTitle()}?", waitTime);
+ if (clickTime < waitTime) {
+ def opts = [
+ [ lbl: "FAQ (webpage)", act: showFaq ],
+ [ lbl: "Calendar", act: setupShowCalendar ],
+ [ lbl: "Confess", act: confess ],
+ ];
+ if (is("DEBUG")) {
+ opts.push([ lbl: "Status", act: setupShowState ]);
+ opts.push([ lbl: "Play", act: playEvent, arg: true ]);
+ opts.push([ lbl: "Activity", act: playActivity ]);
+ }
+ if (is(NAKED)) {
+ opts.push([ lbl: "May I wear clothes", act: requestClothes ]);
+ }
+ TOYTOYS.findAll { is(it) }.each {
+ opts.push([ lbl: "May I be un-$it".toString(), act: requestRelease, arg: it ]);
+ };
+ opts.push([ lbl: "Back", act: null ]);
+ def opt = getSelectedValue(is("DEBUG") ? DOMME : "Yes, toy?", opts.collect { it.lbl });
+ def act = opts[opt].act;
+ if (act)
+ act(opts[opt].arg);
+ else if (is("DEBUG"))
+ return "toy";
+ }
+ addAvail(clickTime);
}
- TOYTOYS.findAll { is(it) }.each {
- opts.push([ lbl: "May I be un-$it".toString(), act: requestRelease, arg: it ]);
- };
- opts.push([ lbl: "Back", act: null ]);
- def opt = getSelectedValue(is("DEBUG") ? DOMME : "Yes, toy?", opts.collect { it.lbl });
- def act = opts[opt].act;
- if (act)
- act(opts[opt].arg);
- else if (is("DEBUG"))
- return "toy";
+ def eStart = getTime();
+ execEvents(true);
+ addAvail(getTime() - eStart);
}
- addAvail(clickTime);
}
- def eStart = getTime();
- execEvents(true);
- addAvail(getTime() - eStart);
-}
+}.main();
/*