aboutsummaryrefslogtreecommitdiffstats
path: root/desktop/companion/Mood.js
diff options
context:
space:
mode:
Diffstat (limited to 'desktop/companion/Mood.js')
-rw-r--r--desktop/companion/Mood.js31
1 files changed, 25 insertions, 6 deletions
diff --git a/desktop/companion/Mood.js b/desktop/companion/Mood.js
index a3bc8cb..b59c1ab 100644
--- a/desktop/companion/Mood.js
+++ b/desktop/companion/Mood.js
@@ -23,12 +23,18 @@ var T = {
mockCooldown: 20000,
typingHold: 2000,
waveHold: 3000,
+ singHold: 4000, // her singing reaction to the headphones connecting
+ djHold: 6000, // behind the decks when a track starts or changes
wakeHold: 1500, // the stretch after idling
lineCooldown: 30000,
monologueCooldown: 3600000,
destruct: 1000, // the glow and the flash; the sprite is hidden under it
scorched: 3000,
- skirtless: 60000,
+ goodbye: 2000, // waving goodbye with a line, enough to read it
+ goodbyeSilent: 1000, // waving goodbye with nothing to read
+ admireLook: 1500, // turned to the wallpaper, before the blush
+ admireBlush: 3000,
+ admireCooldown: 180000,
};
function st(state, frame) { return { state: state, frame: frame }; }
@@ -51,6 +57,9 @@ function clickFrame(count) {
// The spec's priority table, top to bottom: the first that applies wins.
// idle is 0 awake, 1 bored, 2 yawning, 3 lying down.
function pick(s) {
+ // The user hid her: the goodbye outranks whatever she was doing. The
+ // frame here is a placeholder; Companion.qml cycles the wave frames.
+ if (s.leaving) return st("bye", "wave");
const since = s.destructAt ? s.now - s.destructAt : Infinity;
if (since < T.destruct) return st("destruct", "base");
if (since < T.destruct + T.scorched) return st("scorched", "scorched");
@@ -60,8 +69,12 @@ function pick(s) {
if (s.recording) return st("listen", "listen");
if (s.busy) return st("think", "think");
if (s.now - s.repliedAt < T.waveHold) return st("wave", "wave");
+ if (s.now - s.singAt < T.singHold) return st("sing", "sing");
+ if (s.now - s.djAt < T.djHold) return st("dj", "dj");
if (s.clicks.count > 0 && s.now - s.clicks.at < T.clickHold)
return st("clicks", clickFrame(s.clicks.count));
+ if (s.now - s.admireAt < T.admireLook + T.admireBlush)
+ return st("admire", s.now - s.admireAt < T.admireLook ? "watch" : "blush3");
if (s.now - s.mockAt < T.mockHold)
return st("mock", s.now - s.mockAt < T.mockHold / 2 ? "point" : "smirk");
if (s.now - s.typingAt < T.typingHold) return st("watch", "watch");
@@ -69,21 +82,27 @@ function pick(s) {
if (s.monologue) return st("muse", "muse");
if (s.idle >= 3) return st("lying", "lying");
if (s.idle === 2) return st("yawn", "yawn");
- if (s.idle === 1) return st("bored", "sleepy");
+ // Music turns boredom into a groove picked by Companion.qml; the
+ // deeper idle stages still win, so music does not keep her awake.
+ if (s.idle === 1) return s.music ? st("groove", s.groove || "whistle") : st("bored", "sleepy");
return st("base", "base");
}
// The self-destruct takes the skirt off once the flash is over, for the
-// scorched moment and the skirtless minute after it. Showing her again
-// sets destructAt back to 0, which restores it early.
-function outfit(destructAt, now) {
+// scorched moment and skirtless ms after it (Prefs.companionSkirtless),
+// or with 0 until she is shown again, which sets destructAt back to 0 and
+// also restores it early.
+function outfit(destructAt, now, skirtless) {
if (!destructAt) return "dress";
const since = now - destructAt;
- return since >= T.destruct && since < T.destruct + T.scorched + T.skirtless ? "leotard" : "dress";
+ if (since < T.destruct) return "dress";
+ return skirtless === 0 || since < T.destruct + T.scorched + skirtless ? "leotard" : "dress";
}
function mockAllowed(lastMockAt, now) { return now - lastMockAt >= T.mockCooldown; }
+function admireAllowed(lastAt, now) { return now - lastAt >= T.admireCooldown; }
+
function canSpeak(lastLineAt, now) { return now - lastLineAt >= T.lineCooldown; }
// Whether the opening monologue plays: a chance per trigger, and never