aboutsummaryrefslogtreecommitdiff
path: root/liust-50/cmd/liustatus/kaomoji.go
diff options
context:
space:
mode:
authorPřemysl Eric Janouch <p@janouch.name>2025-10-05 17:02:02 +0200
committerPřemysl Eric Janouch <p@janouch.name>2025-11-17 15:16:21 +0100
commitde4379ca2c3a85615237e7a51f9283b740e0c91e (patch)
tree52114a333eb4b7b1f46c3e541af55f6f9e02f0bc /liust-50/cmd/liustatus/kaomoji.go
parentf26cfd3bb51023cf4c4ff23acd192125ed04881e (diff)
downloaddesktop-tools-de4379ca2c3a85615237e7a51f9283b740e0c91e.tar.gz
desktop-tools-de4379ca2c3a85615237e7a51f9283b740e0c91e.tar.xz
desktop-tools-de4379ca2c3a85615237e7a51f9283b740e0c91e.zip
Add Toshiba Tec LIUST-A00 utilitiesHEADorigin/masterorigin/HEADmaster
Diffstat (limited to 'liust-50/cmd/liustatus/kaomoji.go')
-rw-r--r--liust-50/cmd/liustatus/kaomoji.go242
1 files changed, 242 insertions, 0 deletions
diff --git a/liust-50/cmd/liustatus/kaomoji.go b/liust-50/cmd/liustatus/kaomoji.go
new file mode 100644
index 0000000..dee0ed9
--- /dev/null
+++ b/liust-50/cmd/liustatus/kaomoji.go
@@ -0,0 +1,242 @@
+package main
+
+import (
+ "math/rand"
+ "strings"
+ "time"
+)
+
+type kaomojiKind int
+
+const (
+ kaomojiKindAwake kaomojiKind = iota
+ kaomojiKindBlink
+ kaomojiKindFace
+ kaomojiKindChase
+ kaomojiKindHappy
+ kaomojiKindSleep
+ kaomojiKindSnore
+ kaomojiKindPeek
+)
+
+type kaomojiState struct {
+ kind kaomojiKind
+ face string
+ message string
+ delay int
+}
+
+func (ks *kaomojiState) Format() string {
+ line := []rune(strings.Repeat(" ", displayWidth))
+
+ face := []rune(ks.face)
+ if x := (len(line) - len(face) + 1) / 2; x < 0 {
+ copy(line, face)
+ } else {
+ copy(line[x:], face)
+ }
+
+ if ks.message != "" {
+ copy(line[14:], []rune(ks.message))
+ }
+ return string(line)
+}
+
+func (ks *kaomojiState) Duration() time.Duration {
+ return time.Millisecond * time.Duration(ks.delay)
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+func kaomojiNewAwake() kaomojiState {
+ return kaomojiState{
+ kind: kaomojiKindAwake,
+ face: "(o_o)",
+ message: "",
+ delay: 2_000 + rand.Intn(4_000),
+ }
+}
+
+func kaomojiNewBlink() kaomojiState {
+ return kaomojiState{
+ kind: kaomojiKindBlink,
+ face: "(-_-)",
+ message: "",
+ delay: 100 + rand.Intn(50),
+ }
+}
+
+func kaomojiNewFace() kaomojiState {
+ faces := []struct {
+ face, message string
+ }{
+ {"(x_x)", "ズキズキ"},
+ {"(T_T)", "ズーン"},
+ {"=^.^=", "ニャー"},
+ {"(>_<)", "ゲップ"},
+ {"(O_O)", "ジー"},
+ }
+
+ x := faces[rand.Intn(len(faces))]
+ return kaomojiState{
+ kind: kaomojiKindFace,
+ face: x.face,
+ message: x.message,
+ delay: 10_000,
+ }
+}
+
+func kaomojiNewChase() kaomojiState {
+ faces := []string{"(゚ロ゚)", "(゚∩゚)"}
+ return kaomojiState{
+ kind: kaomojiKindChase,
+ face: faces[rand.Intn(len(faces))],
+ message: "",
+ delay: 125,
+ }
+}
+
+func kaomojiNewHappy() kaomojiState {
+ return kaomojiState{
+ kind: kaomojiKindHappy,
+ face: "(^_^)",
+ message: "",
+ delay: 500,
+ }
+}
+
+func kaomojiNewSleep() kaomojiState {
+ return kaomojiState{
+ kind: kaomojiKindSleep,
+ face: "(-_-)",
+ message: "",
+ delay: 10_000,
+ }
+}
+
+func kaomojiNewSnore() kaomojiState {
+ return kaomojiState{
+ kind: kaomojiKindSnore,
+ face: "(-_-)",
+ message: "グーグー",
+ delay: 10_000,
+ }
+}
+
+func kaomojiNewPeek() kaomojiState {
+ faces := []string{"(o_-)", "(-_o)"}
+ return kaomojiState{
+ kind: kaomojiKindPeek,
+ face: faces[rand.Intn(len(faces))],
+ message: "",
+ delay: 3_000,
+ }
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+func kaomojiAnimateChase(state kaomojiState) (lines []string) {
+ // The main character is fixed and of fixed width.
+ var (
+ normal = []rune("(o_o)")
+ alert = []rune("(O_O)")
+ centre = (displayWidth - 4) / 2
+ chaserLen = len([]rune(state.face))
+ )
+
+ // For simplicity, let the animation run off-screen.
+ for chaserX := chaserLen + displayWidth; chaserX >= 0; chaserX-- {
+ line := []rune(strings.Repeat(" ", chaserLen+displayWidth))
+
+ chased, chasedX := normal, chaserLen+centre
+ if chasedX > chaserX-7 {
+ chased, chasedX = alert, chaserX-7
+ }
+ if chasedX >= 0 {
+ copy(line[chasedX:], chased)
+ }
+
+ copy(line[chaserX:], []rune(state.face))
+ lines = append(lines, string(line[chaserLen:]))
+ }
+
+ // Return our main character back.
+ for chasedX := displayWidth; chasedX >= centre; chasedX-- {
+ line := []rune(strings.Repeat(" ", displayWidth))
+ copy(line[chasedX:], normal)
+ lines = append(lines, string(line))
+ }
+ return
+}
+
+func kaomojiProducer(lines chan<- string) {
+ state := kaomojiNewAwake()
+ execute := func() {
+ lines <- state.Format()
+ time.Sleep(state.Duration())
+ }
+
+ for {
+ switch state.kind {
+ case kaomojiKindAwake:
+ execute()
+ switch f := rand.Float32(); {
+ case f < 0.025:
+ state = kaomojiNewFace()
+ case f < 0.050:
+ state = kaomojiNewChase()
+ case f < 0.075:
+ state = kaomojiNewHappy()
+ case f < 0.100:
+ state = kaomojiNewSleep()
+ default:
+ state = kaomojiNewBlink()
+ }
+
+ case kaomojiKindBlink, kaomojiKindFace:
+ execute()
+ state = kaomojiNewAwake()
+
+ case kaomojiKindHappy:
+ face := state.face
+ execute()
+ state.face = " " + face
+ execute()
+ state.face = face
+ execute()
+ state.face = face + " "
+ execute()
+ state.face = face
+ execute()
+ state = kaomojiNewAwake()
+
+ case kaomojiKindChase:
+ for _, line := range kaomojiAnimateChase(state) {
+ lines <- line
+ time.Sleep(state.Duration())
+ }
+ state = kaomojiNewAwake()
+
+ case kaomojiKindSleep:
+ execute()
+ switch f := rand.Float32(); {
+ case f < 0.10:
+ state = kaomojiNewAwake()
+ case f < 0.20:
+ state = kaomojiNewPeek()
+ case f < 0.60:
+ state = kaomojiNewSnore()
+ default:
+ state = kaomojiNewSleep()
+ }
+
+ case kaomojiKindSnore:
+ execute()
+ state = kaomojiNewSleep()
+
+ case kaomojiKindPeek:
+ execute()
+ state = kaomojiNewSleep()
+ }
+ }
+}