From ac4c6b7785faa443e83f785a40a8130d6dc03596 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 6 Apr 2019 13:40:12 +0100 Subject: Strongly type helper functions --- scripts/toy.groovy | 93 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 52 insertions(+), 41 deletions(-) diff --git a/scripts/toy.groovy b/scripts/toy.groovy index 246dd63..3bef835 100644 --- a/scripts/toy.groovy +++ b/scripts/toy.groovy @@ -152,59 +152,70 @@ return new Object() { save("toy.owner.outfitTime", getTime()); DOMME = loadDomme(OWNER, outfit.set); }; + // Utils - def localTimeOffset = { + int 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 = { + + java.time.LocalDateTime localTimeOf(int s) { + return java.time.LocalDateTime.ofInstant( + java.time.Instant.ofEpochSecond(s), java.time.ZoneId.systemDefault()); + } + + float 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()); + } + + int getDay() { + return (getTime() / DAY) * DAY; + } + + public T getProp(String i, java.util.function.Function f, T d = null) { + final T v = f("toy.$i".toString()); if (v == null) return d; return v; - }; - def getDommeProp = { i, d = null -> + } + + Object getDommeProp = { String i, Object 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)) } + } + + String dommeTitle() { getDommeProp("title", "Mistress") } + String dommeName() { getDommeProp("name", "") } + boolean loadB(String p) { loadBoolean(p) } + int loadI(String p) { loadInteger(p) } + String loadS(String p ) { loadString(p) } + void setProp(String i, Object v) { save("toy.$i".toString(), v) } + boolean has(String i) { loadBoolean("toys.$i") == true } + boolean likes(String i) { loadBoolean("fetish.$i") == true } + boolean can(String i) { loadBoolean("toy.permission.$i") == true } + boolean perm(String i) { can(it) } + boolean getPermission(String i) { getProp("permission.$i", loadB) } + void setPermission(String i, boolean v) { setProp("permission.$i", v) } + void givePermission(String i) { setPermission(i, true) } + void revokePermission(String i) { setPermission(i, false) } + boolean is(String i) { loadBoolean("toy.state.$i") == true } + void set(String i, boolean s) { save("toy.state.$i", s) } + boolean positioned(String i) { ("toy.position") == i } + int getPunish() { loadInteger("toy.punishment") ?: 0 } + void adjustPunish(int p) { save("toy.punishment", Math.max(getPunish() + p, 0)) } + void adjustPunish(double p) { adjustPunish((int)p) } + String getAway() { loadString("toy.owner.away") } + void setAway(String a) { save("toy.owner.away", a) } + int randRange(int min, int max) { min + getRandom(1 + max - min) } + int randRange(double min, double max) { randRange((int)min, (int)max) } def loadEvents = { return (loadMap("toy.events") ?: [:]); } @@ -1292,13 +1303,13 @@ return new Object() { def sessionPlay = { if (is(CHASTE)) sessionToys[CHASTITY] = getTime(); def playScope = [ - 'randRange': randRange, - 'currentPunishment': getPunish, + 'randRange': { min, max -> randRange(min, max) }, + 'currentPunishment': { getPunish() }, 'sessionAborted': { return sessionAborted }, - 'can': can, - 'has': has, - 'is': is, - 'likes': likes, + 'can': { return can(it) }, + 'has': { return has(it) }, + 'is': { return is(it) }, + 'likes': { return likes(it) }, 'punishMultiple': (float)1.0, 'prop': load('toy') ?: [:] ]; -- cgit v1.2.3 From d1b759d3ed8bddefb5748f00d7133de321d943c6 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 7 Apr 2019 13:45:04 +0100 Subject: Rename is helper function Prevents groovy evaluating something else --- scripts/toy.groovy | 78 +++++++++++++++++++++++++++--------------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/scripts/toy.groovy b/scripts/toy.groovy index 3bef835..6c54368 100644 --- a/scripts/toy.groovy +++ b/scripts/toy.groovy @@ -206,7 +206,7 @@ return new Object() { void setPermission(String i, boolean v) { setProp("permission.$i", v) } void givePermission(String i) { setPermission(i, true) } void revokePermission(String i) { setPermission(i, false) } - boolean is(String i) { loadBoolean("toy.state.$i") == true } + boolean stateIs(String i) { loadBoolean("toy.state.$i") == true } void set(String i, boolean s) { save("toy.state.$i", s) } boolean positioned(String i) { ("toy.position") == i } int getPunish() { loadInteger("toy.punishment") ?: 0 } @@ -273,7 +273,7 @@ return new Object() { def sessionAborted = null; def sessionToys = [:]; def gagText = { t, p -> - if (!is(GAGGED)) return t.toString(); + if (!stateIs(GAGGED)) return t.toString(); return t.split(/\s+/) .collect { 'm' * getRandom((int)Math.max(1.0, it.length() * 1.0)) + @@ -319,7 +319,7 @@ return new Object() { Collections.shuffle(tags); switch (tags[0]) { case ASS: - if (!is(GAGGED)) + if (!stateIs(GAGGED)) return compose([ ["Come closer,", "Don't be shy,"], ["kiss it!", "two kisses on each cheek."]]); @@ -332,14 +332,14 @@ return new Object() { ["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)) + if (stateIs(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)) + if (stateIs(GAGGED)) return compose([ ["I know you'd like to pleasure me.", "Too bad that tongue can't be put to good use."]]); else @@ -382,7 +382,7 @@ return new Object() { playBackgroundSound(null); }; def expose = { imageSpec -> - if (!is(NAKED)) { + if (!stateIs(NAKED)) { present(imageSpec, [ ["Get that cock out, toy;", "Let's see that cock of mine."], ["I want to torment it.", "It's playtime!"]]); @@ -669,8 +669,8 @@ return new Object() { }; // Pre-tease def preRelease = { - if (!is(CHASTE)) return; - if (!is(NAKED)) { + if (!stateIs(CHASTE)) return; + if (!stateIs(NAKED)) { present([DRESSED], [ ["Reach down... and through your clothes...", "Stay clothed,"], ["rub that chastity device...", "run your hand around that locked cock..."], @@ -706,7 +706,7 @@ return new Object() { showButtonGT("Thank you, ${dommeTitle()}", "ok", 80, 1); }; def preEdge = { - if (is(CHASTE)) return; + if (stateIs(CHASTE)) return; expose([DRESSED]); harden([DRESSED]); edge(4, [DRESSED]); @@ -716,7 +716,7 @@ return new Object() { wait(getRandom(5) + 5); }; def preGag = { - if (is(GAGGED)) return 1.2; + if (stateIs(GAGGED)) return 1.2; if (!has(BALLGAG)) return; present([DRESSED], [ ["Go fetch your gag, toy...", "Bring me your gag, toy..."], @@ -736,7 +736,7 @@ return new Object() { return 1.2; }; def clamps = { - if (is(CLAMPED)) return; + if (stateIs(CLAMPED)) return; if (!has(CLAMPS)) return; present([DRESSED], likes(PAIN) ? [ @@ -770,7 +770,7 @@ return new Object() { }; def preClamps = { if (!has(CLAMPS)) return; - if (is(CLAMPED)) { + if (stateIs(CLAMPED)) { clampsShow(); } else { @@ -780,7 +780,7 @@ return new Object() { return 1.8; }; def preCollar = { - if (is(COLLARED)) return 1.1; + if (stateIs(COLLARED)) return 1.1; if (!has(COLLAR)) return; present([DRESSED], [ ["You look underdressed, toy.", "A toy without a collar doesn't look right."], @@ -795,7 +795,7 @@ return new Object() { return 1.1; }; def preStrip = { imageSpec = [DRESSED] -> - if (is(NAKED)) return 1.1; + if (stateIs(NAKED)) return 1.1; present(imageSpec, [ ["Clothes off!", "Get naked, slut!"]]); wait(10); @@ -814,12 +814,12 @@ return new Object() { // Post def postEdge = { - if (is(CHASTE)) return; + if (stateIs(CHASTE)) return; if (!can(EDGE)) return; edge(6, [TEASE]); }; def postCum = { - if (is(CHASTE)) return; + if (stateIs(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?"]]); @@ -831,7 +831,7 @@ return new Object() { } }; def chastity = { pre -> - if (is(CHASTE)) return; + if (stateIs(CHASTE)) return; if (!has(CHASTITY)) return; if (pre) { present([DRESSED,TEASE], [ @@ -870,7 +870,7 @@ return new Object() { } def postChastity = { chastity(false); - if (is(CHASTE) && (getPermission(PERM_CHASTE) == null || + if (stateIs(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,"], @@ -1187,13 +1187,13 @@ return new Object() { }; def playClamps = { if (!has(CLAMPS)) return; - if (!is(CLAMPED)) clamps(); + if (!stateIs(CLAMPED)) clamps(); clampsShow(); return clampPulls(3 + getRandom(10)); }; def intClamps = { if (!has(CLAMPS)) return; - if (!is(CLAMPED)) return; + if (!stateIs(CLAMPED)) return; clampsShow(); return clampPulls(getRandom(5)); }; @@ -1230,7 +1230,7 @@ return new Object() { return null; }; def removeToy = { toy, imageSpec -> - if (!is(toy)) return; + if (!stateIs(toy)) return; def toyName = stateToyName(toy); present(imageSpec, [ ["OK,"], @@ -1301,14 +1301,14 @@ return new Object() { 'postChastity': postChastity ]; def sessionPlay = { - if (is(CHASTE)) sessionToys[CHASTITY] = getTime(); + 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 is(it) }, + 'is': { return stateIs(it) }, 'likes': { return likes(it) }, 'punishMultiple': (float)1.0, 'prop': load('toy') ?: [:] @@ -1361,7 +1361,7 @@ return new Object() { 'activities': activityList ]; final eval = { expr -> Eval.me('toy', playScope, expr.toString()) }; - if (is("DEBUG")) { + if (stateIs("DEBUG")) { // Check everything in DOMME evaluates and resolves final checkIsFunc = { group, name -> if (!name) return; @@ -1416,7 +1416,7 @@ return new Object() { postChastity(); } wait(getRandom(10) + 5); - def toys = TOYTOYS.findAll { t -> is(t) }; + def toys = TOYTOYS.findAll { t -> stateIs(t) }; Collections.shuffle(toys); if (toys) { if (!goodToy) { @@ -1436,7 +1436,7 @@ return new Object() { } }; } - if (is(NAKED)) { + if (stateIs(NAKED)) { if (goodToy && getRandom(1)) { present([DRESSED], [ ["Put some clothes back on.", "Cover yourself up!"]]); @@ -1522,7 +1522,7 @@ return new Object() { dress([[LINGERIE,nTITS]]); if (rt && sessionSummon([LINGERIE,nTITS])) { preStrip([LINGERIE,nTITS]); - def toys = TOYTOYS.findAll { t -> is(t) }; + def toys = TOYTOYS.findAll { t -> stateIs(t) }; Collections.shuffle(toys); toys.each { removeToy(it, [LINGERIE,nTITS]) }; present([LINGERIE,nTITS], [ @@ -1536,7 +1536,7 @@ return new Object() { removeEvent(REDRESS); set(NAKED, false); // Assume toy will release himself - TOYTOYS.findAll { t -> is(t) }.each { + TOYTOYS.findAll { t -> stateIs(t) }.each { removeEvent("$RELEASEFROM-$it"); set(it, false); }; @@ -1685,10 +1685,10 @@ return new Object() { ["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)) { + if (stateIs(CHASTE)) { opts.push([lbl: "Freed from chastity", act: confessChastityRelease]); } - if (!is(CHASTE)) { + if (!stateIs(CHASTE)) { opts.push([lbl: "Stroked", act: confessStroked]); } opts.push([ lbl: "Nothing listed (phew!)", act: null ]); @@ -1765,14 +1765,14 @@ return new Object() { [ "Will you be good while I'm gone?", "You will behave as I expect?" ]]); wait(10); postChastity(); - def toys = TOYTOYS.findAll { t -> is(t) }; + def toys = TOYTOYS.findAll { t -> stateIs(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)) { + else if (has(CHASTITY) && !stateIs(CHASTE)) { leaveNote("I want you in chastity until I return!", CHASTE); } DOMME = loadDomme(OWNER); @@ -1860,7 +1860,7 @@ return new Object() { def setupShowState = { show( [CHASTE, COLLARED, CUFFED, CLAMPED, GAGGED, NAKED].collect { - def v = is(it); + def v = stateIs(it); return "$it: $v\n".capitalize() }.join()); showButton("OK"); @@ -1947,7 +1947,7 @@ return new Object() { } } else { - if (is("DEBUG")) { + if (stateIs("DEBUG")) { def timeStr = localTimeOf(e.event.time).format(soonFormatter); show("$e.name: $timeStr -> ${e.event.func}(${e.event.arg})"); } @@ -1962,23 +1962,23 @@ return new Object() { [ lbl: "Calendar", act: setupShowCalendar ], [ lbl: "Confess", act: confess ], ]; - if (is("DEBUG")) { + if (stateIs("DEBUG")) { opts.push([ lbl: "Status", act: setupShowState ]); opts.push([ lbl: "Play", act: playEvent, arg: true ]); opts.push([ lbl: "Activity", act: playActivity ]); } - if (is(NAKED)) { + if (stateIs(NAKED)) { opts.push([ lbl: "May I wear clothes", act: requestClothes ]); } - TOYTOYS.findAll { is(it) }.each { + TOYTOYS.findAll { stateIs(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 opt = getSelectedValue(stateIs("DEBUG") ? DOMME : "Yes, toy?", opts.collect { it.lbl }); def act = opts[opt].act; if (act) act(opts[opt].arg); - else if (is("DEBUG")) + else if (stateIs("DEBUG")) return "toy"; } addAvail(clickTime); -- cgit v1.2.3 From d44f8ea4c1df4fca2dced0bedeff3612d9dfc486 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 8 Apr 2019 13:14:59 +0100 Subject: Fix up type-safe property helpers --- scripts/toy.groovy | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/toy.groovy b/scripts/toy.groovy index 6c54368..e85b83e 100644 --- a/scripts/toy.groovy +++ b/scripts/toy.groovy @@ -180,7 +180,7 @@ return new Object() { } public T getProp(String i, java.util.function.Function f, T d = null) { - final T v = f("toy.$i".toString()); + final T v = f.apply("toy.$i".toString()); if (v == null) return d; return v; } @@ -194,9 +194,9 @@ return new Object() { String dommeTitle() { getDommeProp("title", "Mistress") } String dommeName() { getDommeProp("name", "") } - boolean loadB(String p) { loadBoolean(p) } - int loadI(String p) { loadInteger(p) } - String loadS(String p ) { loadString(p) } + final java.util.function.Function loadB = this.&loadBoolean; + final java.util.function.Function loadI = this.&loadInteger; + final java.util.function.Function loadS = this.&loadString; void setProp(String i, Object v) { save("toy.$i".toString(), v) } boolean has(String i) { loadBoolean("toys.$i") == true } boolean likes(String i) { loadBoolean("fetish.$i") == true } -- cgit v1.2.3 From 6315f32f1b4853c8463d42748d341e8ab42e8c5e Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 11 Apr 2019 19:24:04 +0100 Subject: Typesafe events --- scripts/toy.groovy | 70 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/scripts/toy.groovy b/scripts/toy.groovy index e85b83e..00e7652 100644 --- a/scripts/toy.groovy +++ b/scripts/toy.groovy @@ -216,28 +216,52 @@ return new Object() { void setAway(String a) { save("toy.owner.away", a) } int randRange(int min, int max) { min + getRandom(1 + max - min) } int randRange(double min, double max) { randRange((int)min, (int)max) } - def loadEvents = { - return (loadMap("toy.events") ?: [:]); + + // Events + static class Event { + int time; + String func; + Object arg; + def map = { + [ + time: time, + func: func, + arg: arg + ] + } + } + + static class NamedEvent { + String name; + Event event; } - def saveEvents = { events -> - save("toy.events", events); + + Map loadEvents() { + return (loadMap("toy.events") ?: [:]) + .collectEntries { k, v -> [ k, new Event(v) ] }; } - def nextEvent = { events -> - def first = null; - events.each{ k, v -> + + void saveEvents(Map events) { + save("toy.events", events.collectEntries { k, v -> [ k, v.map() ] }); + } + + NamedEvent nextEvent(Map events) { + NamedEvent first = null; + events.each{ String k, Event v -> if (!first || first.event.time > v.time) { - first = [ name: k, event: v ]; + first = new NamedEvent(name: k, event: v); } }; return first; - }; - def setEvent = { events, name, time, func, arg = null -> + } + + boolean setEvent(Map events, String name, int time, String func, Object arg = null) { if (namedEvents.containsKey(func)) { - events[name] = [ + events[name] = new Event( time: time, func: func, arg: arg - ]; + ); saveEvents(events); return true; } @@ -245,23 +269,28 @@ return new Object() { showPopup("No such event $func"); return false; } - }; - def addEvent = { name, time, func, arg = null -> + } + + boolean addEvent(String name, int time, String func, Object arg = null) { def events = loadEvents(); return setEvent(events, name, time, func, arg); } - def addEventIfMissing = { name, time, func, arg = null -> + + boolean addEventIfMissing(String name, int time, String func, Object arg = null) { def events = loadEvents(); if (!events.containsKey(name)) { return setEvent(events, name, time, func, arg); } - }; - def removeEvent = { name -> + return false; + } + + void removeEvent(String name) { def events = loadEvents(); events.remove(name); saveEvents(events); - }; - def execEvents = { rt -> + } + + void execEvents(boolean rt) { for (def e = nextEvent(loadEvents()); e && e.event.time <= getTime(); e = nextEvent(loadEvents())) { def f = namedEvents[e.event.func]; removeEvent(e.name); @@ -269,7 +298,8 @@ return new Object() { f(e.name, e.event.arg, e.event.time, rt); } } - }; + } + def sessionAborted = null; def sessionToys = [:]; def gagText = { t, p -> -- cgit v1.2.3