|
@@ -0,0 +1,440 @@
|
|
|
+package door
|
|
|
+
|
|
|
+import (
|
|
|
+ "log"
|
|
|
+ "math/rand"
|
|
|
+ "time"
|
|
|
+ "unicode"
|
|
|
+)
|
|
|
+
|
|
|
+
|
|
|
+No More Secrets - from "Sneakers"
|
|
|
+https:
|
|
|
+
|
|
|
+*/
|
|
|
+
|
|
|
+type NoMoreSecretsConfig struct {
|
|
|
+ Jumble_Sec int
|
|
|
+ Jumble_Loop_Speed int
|
|
|
+ Reveal_Loop_Speed int
|
|
|
+ Max_Time int
|
|
|
+ Color string
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+var NoMoreSecretsDefault NoMoreSecretsConfig
|
|
|
+
|
|
|
+
|
|
|
+func init() {
|
|
|
+ NoMoreSecretsDefault = NoMoreSecretsConfig{
|
|
|
+ Jumble_Sec: 2,
|
|
|
+ Jumble_Loop_Speed: 35,
|
|
|
+ Reveal_Loop_Speed: 50,
|
|
|
+ Max_Time: 5000,
|
|
|
+ Color: ColorText("CYAN ON BLACK"),
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+func getRandom() byte {
|
|
|
+
|
|
|
+ var rb byte = 0x7f
|
|
|
+ for rb == 0x7f {
|
|
|
+ rb = byte(rand.Intn(0xdf-0x21) + 0x21)
|
|
|
+ }
|
|
|
+ return rb
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+NoMoreSecrets - render output as random, then fade in the original text.
|
|
|
+
|
|
|
+Example:
|
|
|
+
|
|
|
+func About_Example_NoMoreSecrets(d *door.Door) {
|
|
|
+ W := 60
|
|
|
+ center_x := (door.Width - W) / 2
|
|
|
+ center_y := (door.Height - 16) / 2
|
|
|
+ about := door.Panel{X: center_x,
|
|
|
+ Y: center_y,
|
|
|
+ Width: W,
|
|
|
+ Style: door.SINGLE_DOUBLE,
|
|
|
+ BorderColor: door.ColorText("BOLD YELLOW ON BLUE"),
|
|
|
+ }
|
|
|
+ about.Lines = append(about.Lines, door.Line{Text: fmt.Sprintf("%*s", -W, "About This Door"),
|
|
|
+ DefaultColor: door.ColorText("BOLD CYAN ON BLUE")})
|
|
|
+ about.Lines = append(about.Lines, about.Spacer())
|
|
|
+
|
|
|
+ about.Lines = append(about.Lines, door.Line{Text: fmt.Sprintf("%*s", -W, "Test Door written in go, using go door.")})
|
|
|
+ var copyright string = "(C) 2022 Bugz, Red Green Software"
|
|
|
+
|
|
|
+ if door.Unicode {
|
|
|
+ copyright = strings.Replace(copyright, "(C)", "\u00a9", -1)
|
|
|
+ }
|
|
|
+
|
|
|
+ about.Lines = append(about.Lines,
|
|
|
+ door.Line{Text: fmt.Sprintf("%*s", -W, copyright),
|
|
|
+ DefaultColor: door.ColorText("BOLD WHITE ON BLUE")})
|
|
|
+ for _, text := range []string{"",
|
|
|
+ "This door was written by Bugz.",
|
|
|
+ "",
|
|
|
+ "It is written in Go, understands CP437 and unicode, adapts",
|
|
|
+ "to screen sizes, uses door32.sys, supports TheDraw Fonts,",
|
|
|
+ "and runs on Linux and Windows."} {
|
|
|
+ about.Lines = append(about.Lines, door.Line{Text: fmt.Sprintf("%*s", -W, text)})
|
|
|
+ }
|
|
|
+
|
|
|
+ better := door.NoMoreSecretsDefault
|
|
|
+ better.Color = door.ColorText("BOLD CYAN ON BLUE")
|
|
|
+
|
|
|
+ door.NoMoreSecrets(about.Output(), d, &better)
|
|
|
+}
|
|
|
+*/
|
|
|
+func NoMoreSecrets(output string, Door *Door, config *NoMoreSecretsConfig) {
|
|
|
+
|
|
|
+
|
|
|
+ rand.Seed(time.Now().UnixNano())
|
|
|
+
|
|
|
+ if Unicode {
|
|
|
+ var original []rune = []rune(output)
|
|
|
+ var work []rune = make([]rune, 0)
|
|
|
+ var workpos int = 0
|
|
|
+ var charpos []int
|
|
|
+ var chartime []int
|
|
|
+ var revealpos map[int]int
|
|
|
+ var colormap map[int]string
|
|
|
+ var coloridx []int
|
|
|
+ var lastcolor []int
|
|
|
+ var currentANSI string
|
|
|
+ var ANSIchar rune
|
|
|
+
|
|
|
+ colormap = make(map[int]string)
|
|
|
+ revealpos = make(map[int]int)
|
|
|
+ coloridx = make([]int, 0)
|
|
|
+
|
|
|
+
|
|
|
+ lastcolor = make([]int, 1)
|
|
|
+ lastcolor[0] = 0
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ for x := 0; x < len(original); x++ {
|
|
|
+ var char rune = original[x]
|
|
|
+ if char == '\x1b' {
|
|
|
+
|
|
|
+ currentANSI = "\x1b["
|
|
|
+
|
|
|
+ if original[x+1] != '[' {
|
|
|
+ log.Println("NoMoreSecrets: Found \\x1b not followed by [!")
|
|
|
+ }
|
|
|
+ x += 2
|
|
|
+ for {
|
|
|
+ currentANSI += string(original[x])
|
|
|
+ if unicode.IsLetter(original[x]) {
|
|
|
+ ANSIchar = original[x]
|
|
|
+ break
|
|
|
+ }
|
|
|
+ x++
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if ANSIchar == 'm' {
|
|
|
+
|
|
|
+
|
|
|
+ Door.UpdateLastColor(currentANSI, &lastcolor)
|
|
|
+ colormap[workpos] = Color(lastcolor...)
|
|
|
+ coloridx = append(coloridx, workpos)
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ var ANSIrunes []rune = []rune(currentANSI)
|
|
|
+ work = append(work, ANSIrunes...)
|
|
|
+ workpos += len(ANSIrunes)
|
|
|
+ }
|
|
|
+ currentANSI = ""
|
|
|
+ } else {
|
|
|
+
|
|
|
+ if unicode.IsPrint(char) {
|
|
|
+
|
|
|
+ if char == ' ' {
|
|
|
+ work = append(work, char)
|
|
|
+ chartime = append(chartime, 0)
|
|
|
+ } else {
|
|
|
+ work = append(work, char)
|
|
|
+ chartime = append(chartime, rand.Intn(config.Max_Time+1))
|
|
|
+ }
|
|
|
+
|
|
|
+ charpos = append(charpos, workpos)
|
|
|
+ revealpos[workpos] = x
|
|
|
+ workpos++
|
|
|
+ } else {
|
|
|
+
|
|
|
+ work = append(work, char)
|
|
|
+ workpos++
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ var renderF func() string = func() string {
|
|
|
+ var result string
|
|
|
+ var lastcolor string
|
|
|
+ var pos int = 0
|
|
|
+
|
|
|
+ for idx, char := range work {
|
|
|
+ _, found := revealpos[idx]
|
|
|
+ if found {
|
|
|
+ for charpos[pos] != idx {
|
|
|
+ pos++
|
|
|
+ }
|
|
|
+
|
|
|
+ if chartime[pos] != 0 && char != ' ' {
|
|
|
+ if lastcolor != config.Color {
|
|
|
+ result += config.Color
|
|
|
+ lastcolor = config.Color
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+
|
|
|
+ var best string
|
|
|
+
|
|
|
+
|
|
|
+ for _, cpos := range coloridx {
|
|
|
+ if cpos > idx {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ best = colormap[cpos]
|
|
|
+ }
|
|
|
+
|
|
|
+ if lastcolor != best {
|
|
|
+ result += best
|
|
|
+ lastcolor = best
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ result += string(char)
|
|
|
+ }
|
|
|
+ return result
|
|
|
+ }
|
|
|
+
|
|
|
+ for i := 0; i < (config.Jumble_Sec*1000)/config.Jumble_Loop_Speed; i++ {
|
|
|
+ for _, pos := range charpos {
|
|
|
+ if work[pos] != ' ' {
|
|
|
+
|
|
|
+
|
|
|
+ var rb byte = getRandom()
|
|
|
+ var safe []byte = []byte{rb}
|
|
|
+ var rndchar string = CP437_to_Unicode(string(safe))
|
|
|
+ work[pos] = []rune(rndchar)[0]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Door.Write(renderF())
|
|
|
+ time.Sleep(time.Millisecond * time.Duration(config.Jumble_Loop_Speed))
|
|
|
+ }
|
|
|
+
|
|
|
+ for {
|
|
|
+ var revealed bool = true
|
|
|
+ for idx, pos := range charpos {
|
|
|
+ if work[pos] != ' ' {
|
|
|
+ if chartime[idx] > 0 {
|
|
|
+ if chartime[idx] < 500 {
|
|
|
+ if rand.Intn(3) == 0 {
|
|
|
+ var safe []byte = []byte{getRandom()}
|
|
|
+ var rndchar string = CP437_to_Unicode(string(safe))
|
|
|
+ work[pos] = []rune(rndchar)[0]
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if rand.Intn(10) == 0 {
|
|
|
+ var safe []byte = []byte{getRandom()}
|
|
|
+ var rndchar string = CP437_to_Unicode(string(safe))
|
|
|
+ work[pos] = []rune(rndchar)[0]
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if chartime[idx] < config.Reveal_Loop_Speed {
|
|
|
+ chartime[idx] = 0
|
|
|
+ } else {
|
|
|
+ chartime[idx] -= config.Reveal_Loop_Speed
|
|
|
+ }
|
|
|
+ revealed = false
|
|
|
+ } else {
|
|
|
+ work[pos] = original[revealpos[pos]]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Door.Write(renderF())
|
|
|
+ time.Sleep(time.Millisecond * time.Duration(config.Reveal_Loop_Speed))
|
|
|
+ if revealed {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ var original []byte = []byte(output)
|
|
|
+ var work []byte
|
|
|
+ var workpos int = 0
|
|
|
+ var charpos []int
|
|
|
+ var chartime []int
|
|
|
+ var revealpos map[int]int
|
|
|
+ var colormap map[int]string
|
|
|
+ var coloridx []int
|
|
|
+ var lastcolor []int
|
|
|
+ var currentANSI string
|
|
|
+ var ANSIchar byte
|
|
|
+
|
|
|
+ work = make([]byte, 0)
|
|
|
+ colormap = make(map[int]string)
|
|
|
+ revealpos = make(map[int]int)
|
|
|
+ coloridx = make([]int, 0)
|
|
|
+
|
|
|
+
|
|
|
+ lastcolor = make([]int, 1)
|
|
|
+ lastcolor[0] = 0
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ for x := 0; x < len(original); x++ {
|
|
|
+ var char byte = original[x]
|
|
|
+ if char == '\x1b' {
|
|
|
+
|
|
|
+ currentANSI = "\x1b["
|
|
|
+
|
|
|
+ if original[x+1] != '[' {
|
|
|
+ log.Println("NoMoreSecrets: Found \\x1b not followed by [!")
|
|
|
+ }
|
|
|
+ x += 2
|
|
|
+ for {
|
|
|
+ currentANSI += string(original[x])
|
|
|
+ if unicode.IsLetter(rune(original[x])) {
|
|
|
+ ANSIchar = original[x]
|
|
|
+ break
|
|
|
+ }
|
|
|
+ x++
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if ANSIchar == 'm' {
|
|
|
+
|
|
|
+ Door.UpdateLastColor(currentANSI, &lastcolor)
|
|
|
+ colormap[workpos] = Color(lastcolor...)
|
|
|
+ coloridx = append(coloridx, workpos)
|
|
|
+ } else {
|
|
|
+
|
|
|
+ work = append(work, []byte(currentANSI)...)
|
|
|
+ workpos += len(currentANSI)
|
|
|
+ }
|
|
|
+ currentANSI = ""
|
|
|
+ } else {
|
|
|
+
|
|
|
+ if unicode.IsPrint(rune(char)) {
|
|
|
+
|
|
|
+ if char == ' ' {
|
|
|
+ work = append(work, char)
|
|
|
+ chartime = append(chartime, 0)
|
|
|
+ } else {
|
|
|
+ work = append(work, char)
|
|
|
+ chartime = append(chartime, rand.Intn(config.Max_Time+1))
|
|
|
+ }
|
|
|
+
|
|
|
+ charpos = append(charpos, workpos)
|
|
|
+ revealpos[workpos] = x
|
|
|
+ workpos++
|
|
|
+ } else {
|
|
|
+
|
|
|
+ work = append(work, char)
|
|
|
+ workpos++
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ var renderF func() string = func() string {
|
|
|
+ var result []byte
|
|
|
+ var lastcolor string
|
|
|
+ var pos int = 0
|
|
|
+
|
|
|
+ for idx, char := range work {
|
|
|
+ _, found := revealpos[idx]
|
|
|
+ if found {
|
|
|
+ for charpos[pos] != idx {
|
|
|
+ pos++
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if chartime[pos] != 0 && char != ' ' {
|
|
|
+ if lastcolor != config.Color {
|
|
|
+ result = append(result, []byte(config.Color)...)
|
|
|
+ lastcolor = config.Color
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+
|
|
|
+ var best string
|
|
|
+
|
|
|
+ for _, cpos := range coloridx {
|
|
|
+ if cpos > idx {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ best = colormap[cpos]
|
|
|
+ }
|
|
|
+
|
|
|
+ if lastcolor != best {
|
|
|
+ result = append(result, []byte(best)...)
|
|
|
+ lastcolor = best
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ result = append(result, char)
|
|
|
+ }
|
|
|
+ return string(result)
|
|
|
+ }
|
|
|
+
|
|
|
+ for i := 0; i < (config.Jumble_Sec*1000)/config.Jumble_Loop_Speed; i++ {
|
|
|
+ for _, pos := range charpos {
|
|
|
+ if work[pos] != ' ' {
|
|
|
+ work[pos] = getRandom()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Door.Write(renderF())
|
|
|
+ time.Sleep(time.Millisecond * time.Duration(config.Jumble_Loop_Speed))
|
|
|
+ }
|
|
|
+
|
|
|
+ for {
|
|
|
+ var revealed bool = true
|
|
|
+ for idx, pos := range charpos {
|
|
|
+ if work[pos] != ' ' {
|
|
|
+ if chartime[idx] > 0 {
|
|
|
+ if chartime[idx] < 500 {
|
|
|
+ if rand.Intn(3) == 0 {
|
|
|
+ work[pos] = getRandom()
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if rand.Intn(10) == 0 {
|
|
|
+ work[pos] = getRandom()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if chartime[idx] < config.Reveal_Loop_Speed {
|
|
|
+ chartime[idx] = 0
|
|
|
+ } else {
|
|
|
+ chartime[idx] -= config.Reveal_Loop_Speed
|
|
|
+ }
|
|
|
+ revealed = false
|
|
|
+ } else {
|
|
|
+ work[pos] = original[revealpos[pos]]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Door.Write(renderF())
|
|
|
+ time.Sleep(time.Millisecond * time.Duration(config.Reveal_Loop_Speed))
|
|
|
+ if revealed {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|