From 2bc802953f0f706c2776370c8221842959ad6b6a Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 23 Jun 2019 20:39:50 +0100 Subject: Extract play into a module --- scripts/toy.groovy | 316 +---------------------------------------------- scripts/toy/play.groovy | 322 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 326 insertions(+), 312 deletions(-) create mode 100644 scripts/toy/play.groovy diff --git a/scripts/toy.groovy b/scripts/toy.groovy index 4e030ae..5c3ab02 100644 --- a/scripts/toy.groovy +++ b/scripts/toy.groovy @@ -25,13 +25,10 @@ return new Object() { // toy.permission. final CUM = "cum", EDGE = "edge" final PERMIT = "permit"; - final PLAY = "play"; final PERM_CHASTE = "perm_chaste", PERM_CHASTE_ASK = "perm_chaste_ask"; // toy.state. 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"; // toy.position final KNEELING = "kneeling", ALLFOURS = "allfours", STANDING = "standing"; def OWNER = null; @@ -259,32 +256,6 @@ return new Object() { return tt; }; - // Play - 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 (!stateIs(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; @@ -323,297 +294,18 @@ return new Object() { final addActivity = { String name, func -> activityList[name] = func; } - def sessionPlay = { - if (stateIs(CHASTE)) sessionToys[CHASTITY] = getTime(); - def playScope = [ - 'randRange': { min, max -> randRange(min, max) }, - 'currentPunishment': { getPunish() }, - 'sessionAborted': { return sessionAborted }, - 'can': { return can(it) }, - 'has': { return has(it) }, - 'is': { return stateIs(it) }, - 'likes': { return likes(it) }, - '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); - } - }; - } - ], - 'activities': activityList - ]; - final eval = { expr -> Eval.me('toy', playScope, expr.toString()) }; - if (stateIs("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); - }; - 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); - } - (phase.intervals ?: []).forEach { i -> - checkIsFunc("activities", i); - } - 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 -> stateIs(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]); - } - else { - addEvent("$RELEASEFROM-$toy", getTime() + 100 + getRandom(10 * (getPunish() + 1)), - RELEASEFROM, toy); - adjustPunish(-5); - } - }; - } - if (stateIs(NAKED)) { - if (goodToy && getRandom(1)) { - present([DRESSED], [ - ["Put some clothes back on.", "Cover yourself up!"]]); - wait(getRandom(10) + 15); - set(NAKED, false); - } - 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"); - } - } - 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); - } - else { - setProp(DISAPPOINT, getProp(DISAPPOINT, loadI, 0) + 1); - } - 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 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."]]); - } - 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(); - }; // Setup - def setupEvents = { - playSchedule(); - }; def setDefault = { prop, val -> if (loadString(prop) == null) { save(prop, val); } }; def namedEvents = [ - 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 setupShowState = { @@ -687,7 +379,6 @@ return new Object() { }; setDefault("toy.punishment", 0); execEvents(false); - setupEvents(); tidyAvail(); final cycleTime = 60; @@ -729,14 +420,14 @@ return new Object() { def opts = requestables.values().toList(); if (stateIs("DEBUG")) { opts.push([ lbl: "Status", act: setupShowState ]); - opts.push([ lbl: "Play", act: playEvent, arg: true ]); + opts.push([ lbl: "Play", act: { playEvent() }, arg: true ]); opts.push([ lbl: "Activity", act: playActivity ]); } if (stateIs(NAKED)) { - opts.push([ lbl: "May I wear clothes", act: requestClothes ]); + opts.push([ lbl: "May I wear clothes", act: { requestClothes() } ]); } TOYTOYS.findAll { stateIs(it) }.each { - opts.push([ lbl: "May I be un-$it".toString(), act: requestRelease, arg: it ]); + opts.push([ lbl: "May I be un-$it".toString(), act: { requestRelease() }, arg: it ]); }; opts.push([ lbl: "Back", act: null ]); def opt = getSelectedValue(stateIs("DEBUG") ? DOMME : "Yes, toy?", opts.collect { it.lbl }); @@ -768,6 +459,7 @@ return new Object() { * scripts/toy/intro.groovy * scripts/toy/misc.groovy * scripts/toy/orgasmControl.groovy + * scripts/toy/play.groovy * scripts/toy/pain.groovy * scripts/toy/sleep.groovy * scripts/toy/social.groovy diff --git a/scripts/toy/play.groovy b/scripts/toy/play.groovy new file mode 100644 index 0000000..a383bef --- /dev/null +++ b/scripts/toy/play.groovy @@ -0,0 +1,322 @@ +{ toy -> + final PLAY = "play"; + final REDRESS = "redress"; + final RELEASEFROM = "releaseFrom"; + + toy.metaClass.stateToyName { state -> + switch (state) { + case CUFFED: + return "cuffs"; + case COLLARED: + return "collar"; + case CLAMPED: + return "nipple clamps"; + case GAGGED: + return "gag"; + } + return null; + }; + + toy.metaClass.removeToy { state, imageSpec -> + if (!stateIs(state)) return; + def toyName = stateToyName(state); + present(imageSpec, [ + ["OK,"], + ["you may remove your $toyName.", "the $toyName can come off.", "take the $toyName off."]]); + showButtonG("Thank you, ${dommeTitle()}", "ok"); + pause(5); + set(state, false); + removeEvent("$RELEASEFROM-$state"); + showButtonGT("Removed, ${dommeTitle()}", "removed", 20, 1); + }; + + toy.metaClass.sessionPlay { + if (stateIs(CHASTE)) sessionToys[CHASTITY] = getTime(); + def playScope = [ + 'randRange': { min, max -> randRange(min, max) }, + 'currentPunishment': { getPunish() }, + 'sessionAborted': { return sessionAborted }, + 'can': { return can(it) }, + 'has': { return has(it) }, + 'is': { return stateIs(it) }, + 'likes': { return likes(it) }, + '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); + } + }; + } + ], + 'activities': activityList + ]; + final eval = { expr -> Eval.me('toy', playScope, expr.toString()) }; + if (stateIs("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); + }; + 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); + } + (phase.intervals ?: []).forEach { i -> + checkIsFunc("activities", i); + } + 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]); + } + }; + }; + + toy.metaClass.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."]]); + pause(getRandom(10) + 5); + postChastity(); + } + pause(getRandom(10) + 5); + def toys = TOYTOYS.findAll { t -> stateIs(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."]]); + pause(getRandom(20) + 20); + } + toys.each { toyState -> + if (getRandom(100) > ((goodToy && (getPunish() < 100)) ? 10 : 80)) { + removeToy(toyState, [DRESSED]); + } + else { + addEvent("$RELEASEFROM-$toyState", getTime() + 100 + getRandom(10 * (getPunish() + 1)), + RELEASEFROM, toyState); + adjustPunish(-5); + } + }; + } + if (stateIs(NAKED)) { + if (goodToy && getRandom(1)) { + present([DRESSED], [ + ["Put some clothes back on.", "Cover yourself up!"]]); + pause(getRandom(10) + 15); + set(NAKED, false); + } + 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"); + } + } + if (goodToy) { + present([DRESSED], [ + ["Off you go.", "You may leave."]]); + } + else { + present([DRESSED], [ + ["Get out of my sight.", "Go!"]]); + removeEvent(CUM); + revokePermission(CUM); + } + pause(10); + save("toy.lastPlay", getTime()); + showLounge(); + sessionAborted = null; + sessionToys = [:]; + if (goodToy) { + adjustPunish(-20); + } + else { + setProp(DISAPPOINT, getProp(DISAPPOINT, loadI, 0) + 1); + } + show(null); + }; + + toy.metaClass.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); + pause(20 + getRandom(20)); + }; + + toy.metaClass.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 + } + }; + + toy.metaClass.playEvent { rt = true, first = true -> + if (!rt || getAway()) { + playSchedule(); + 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(); + } + + toy.metaClass.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."]]); + pause(getRandom(10) + 15); + showButtonG("Thank you, ${dommeTitle()}", "ok"); + set(NAKED, false); + showLounge(); + }; + + toy.metaClass.releaseFrom { rt, arg, name -> + if (!rt || !sessionSummon([DRESSED])) { + addEvent(name, getTime() + 300, RELEASEFROM, arg); + return; + } + removeToy(arg, [DRESSED]); + showLounge(); + }; + + toy.metaClass.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(); + }; + + toy.metaClass.requestRelease { toyState -> + adjustPunish(5); + present([DRESSED], [ + ["Really?", "Disappointing."], + ["You wish to be un-$toyState?"]]); + 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(toyState, false); + removeEvent("$RELEASEFROM-$toyState"); + } + } + else { + present([DRESSED], [["Good boy."]]); + } + showButtonG("Thank you, ${dommeTitle()}", "ok"); + showLounge(); + }; + + toy.addNamedEvent(PLAY, { name, arg, schedTime, rt -> toy.playEvent(rt, arg) }); + toy.addNamedEvent(RELEASEFROM, { name, arg, schedTime, rt -> toy.releaseFrom(rt, arg, name) }); + toy.addNamedEvent(REDRESS, { name, arg, schedTime, rt -> toy.redress(rt) }); + toy.playSchedule(); +} -- cgit v1.2.3