package main import ( "citrons.xyz/talk/tui" "zgo.at/termfo/keys" "math/rand" "log" "os" "strings" "strconv" "fmt" "time" ) type ball struct { x int y int vx int vy int explode int inGoal bool } var username = os.Getenv("USER") var score struct { home int guest int } func main() { s := tui.Size() var balls [50]ball for i := 0; i < len(balls); i++ { balls[i].x = rand.Int() % s.Width - 1 balls[i].y = rand.Int() % s.Height if rand.Int() % 2 == 1 { balls[i].vx = 1 } else { balls[i].vx = -1 } if rand.Int() % 2 == 1 { balls[i].vy = 1 } else { balls[i].vy = -1 } } if username == "" { username = "GUEST" } username = string([]rune(username)[:10]) tui.Start() var ( sb strings.Builder response string lastKey keys.Key mouseButton int mouseHeld bool scrolled int responsesUnlocked = 5 ) t := time.After(time.Second / 15) for { select { case ev := <-tui.Events(): if ev.Err != nil { log.Fatal(ev.Err) } if ev.Key == keys.Escape || ev.Key == 'c' | keys.Ctrl { tui.End() return } if ev.Key == keys.Backspace { sb.Reset() } if ev.Key == keys.Enter && len(sb.String()) > 0 { sb.Reset() var i int if responsesUnlocked < 40 { i = rand.Int() % responsesUnlocked } else { i = 30 + rand.Int() % (responsesUnlocked - 30) } response = platitudes[i] if responsesUnlocked < len(platitudes) && rand.Int() % 3 == 0 { if responsesUnlocked < 12 || score.guest > 0 { responsesUnlocked++ } } } if ev.TextInput != 0 { sb.WriteRune(ev.TextInput) } if ev.Mouse.Pressed { mouseHeld = true mouseButton = ev.Mouse.Button fire(balls[:], ev.Mouse.X, ev.Mouse.Y) } else if ev.Mouse.Released { mouseHeld = false } scrolled += ev.Mouse.Scroll if ev.Key != 0 { lastKey = ev.Key } case <-t: stepFootball(balls[:]) t = time.After(time.Second / 15) } if score.home == len(balls) { response = "wow, you did very poorly." } tui.Clear() drawFootball(balls[:]) tui.Write(1, 9, " DIALOG:", tui.Style {Fg: tui.Red, Bold: true}) tui.Write(1, 10, " ", tui.DefaultStyle) w := tui.Write(2, 10, sb.String(), tui.DefaultStyle) tui.MoveCursor(2 + w, 10) tui.Write(1, 11, " RESPONSE:", tui.Style {Fg: tui.Green, Bold: true}) tui.Write(1, 12, " ", tui.DefaultStyle) tui.Write(2, 12, response, tui.DefaultStyle) tui.Write(1, 14, " TIP: click the mouse", tui.Style {Fg: tui.Yellow, Bold: true}) tui.Write(1, 15, " ", tui.DefaultStyle) tui.Write(2, 15, lastKey.Name(), tui.DefaultStyle) tui.Write(11, 15, " ", tui.DefaultStyle) tui.Write(12, 15, strconv.FormatInt(int64(rune(lastKey)), 16), tui.DefaultStyle) if mouseHeld { tui.Write(1, 18, " ", tui.DefaultStyle) tui.Write(2, 18, strconv.Itoa(mouseButton), tui.DefaultStyle) } tui.Write(1, 19, " ", tui.DefaultStyle) tui.Write(2, 19, strconv.Itoa(scrolled), tui.DefaultStyle) s := tui.Size() tui.Write(s.Width - 26, 1, " ", tui.DefaultStyle) tui.Write(s.Width - 25, 1, "HOME", tui.Style {Bg: tui.Green, Bold: true}) hs := fmt.Sprintf(" %02d", score.home) tui.Write(s.Width - 26, 2, hs, tui.Style {Fg: tui.Yellow, Bold: true}) tui.Write(s.Width - 16, 1, " ", tui.DefaultStyle) tui.Write(s.Width - 15, 1, username, tui.Style {Bg: tui.Red, Bold: true}) gs := fmt.Sprintf(" %02d", score.guest) tui.Write(s.Width - 16, 2, gs, tui.Style {Fg: tui.Yellow, Bold: true}) if err := tui.Present(); err != nil { log.Fatal(err) } } } func stepFootball(balls []ball) { s := tui.Size() gx := s.Width / 2 - 1 for i := 0; i < len(balls); i++ { if balls[i].inGoal { continue } if balls[i].explode > 0 { balls[i].explode-- if balls[i].explode == 0 { balls[i].inGoal = true } continue } balls[i].x += balls[i].vx balls[i].y += balls[i].vy if balls[i].x < 0 { balls[i].x = 0 balls[i].vx = -balls[i].vx } else if balls[i].x >= s.Width - 1 { if balls[i].x - s.Width < 2 { balls[i].x = s.Width - 2 balls[i].vx = -balls[i].vx } else { balls[i].x = rand.Int() % s.Width } } if balls[i].y < 0 { balls[i].y = 0 balls[i].vy = -balls[i].vy } else if balls[i].y >= s.Height { if balls[i].y - s.Height < 2 { balls[i].y = s.Height - 1 balls[i].vy = -balls[i].vy } else { balls[i].y = rand.Int() % s.Height } } if balls[i].x >= gx - 1 && balls[i].x <= gx + 1 && balls[i].y == 0 { balls[i].inGoal = true score.home++ continue } } } func fire(balls []ball, x int, y int) { for i := 0; i < len(balls); i++ { if balls[i].explode > 0 || balls[i].inGoal { continue } if x >= balls[i].x - 2 && x <= balls[i].x + 3 && y >= balls[i].y - 1 && y <= balls[i].y + 1 { balls[i].explode = 5 score.guest++ } } } func drawFootball(balls []ball) { s := tui.Size() for y := 0; y < s.Height; y++ { for x := 0; x < s.Width; x++ { if (x + 66) % 10 == 1 && (y + 2) % 5 == 1 { tui.Write(x, y, "*", tui.Style {Fg: tui.Green}) } } } tui.Write(2, 1, "normal", tui.Style {Fg: tui.Red}) tui.Write(2, 2, "bold", tui.Style {Fg: tui.Yellow, Bold: true}) tui.Write(2, 3, "italic", tui.Style {Fg: tui.Green, Italic: true}) tui.Write(2, 4, "underline", tui.Style {Fg: tui.Blue, Underline: true}) tui.Write(2, 5, "strikethrough", tui.Style {Fg: tui.Magenta, Strikethrough: true}) tui.Write(2, 6, "hooray!", tui.Style {Fg: tui.White, Bold: true, Italic: true, Underline: true, Strikethrough: true}) for _, b := range balls { if b.explode > 0 { tui.Write(b.x, b.y, "💥", tui.DefaultStyle) } else if !b.inGoal { tui.Write(b.x, b.y, "⚽", tui.DefaultStyle) } } gx := s.Width / 2 - 1 tui.Write(gx, 0, "🥅", tui.DefaultStyle) }