tins2020/research.go

229 lines
5.1 KiB
Go

package tins2020
import (
"fmt"
"math"
"math/rand"
"strconv"
"strings"
"time"
"opslag.de/schobers/geom"
"opslag.de/schobers/zntg"
"opslag.de/schobers/zntg/ui"
)
type Research struct {
ui.ContainerBase
game *Game
botanist Specialist
farmer Specialist
typing string
digitCount int
close func()
description ui.Paragraph
specialists ui.Paragraph
input ui.Label
digits []Digit
animate zntg.Animation
}
func NewResearch(game *Game) ui.Overlay {
research := &Research{game: game}
research.animate.Interval = 20 * time.Millisecond
research.Children = []ui.Control{&research.description, &research.specialists, &research.input}
research.description.Text = "Call a specialist to conduct research with."
research.digits = make([]Digit, 10)
for i := range research.digits {
j := i
research.digits[i].Value = strconv.Itoa(i)
research.digits[i].ControlClicked().AddHandler(func(ctx ui.Context, _ ui.ControlClickedArgs) {
research.userTyped(ctx, j)
})
research.AddChild(&research.digits[i])
}
dialog := NewLargeDialog("Research", research)
// dialog.OnShow().RegisterItf(func(state interface{}) {
// research.onShow(state.(ui.Context))
// })
// research.close = func() { dialog.CloseDialog() }
return dialog
}
type Digit struct {
ui.ControlBase
Value string
highlight int
}
func (d *Digit) Blink() {
d.highlight = 4
}
func (d *Digit) Render(ctx ui.Context) {
color := zntg.MustHexColor(`#FFFFFF`)
if d.highlight > 0 {
color = zntg.MustHexColor(`#15569F`)
}
bounds := d.Bounds()
ctx.Fonts().TextAlign("title", geom.PtF32(bounds.Center().X, bounds.Min.Y), color, d.Value, ui.AlignCenter)
}
func (d *Digit) Tick() {
if d.highlight > 0 {
d.highlight--
}
}
type Specialist struct {
Cost int
Number string
}
func (r *Research) Arrange(ctx ui.Context, bounds geom.RectangleF32, offset geom.PointF32, parent ui.Control) {
r.ContainerBase.Arrange(ctx, bounds, offset, parent)
size := bounds.Size()
r.specialists.Arrange(ctx, geom.RectRelF32(bounds.Min.X, bounds.Min.Y+40, size.X, size.Y-40), offset, r)
r.input.Arrange(ctx, geom.RectRelF32(bounds.Min.X, bounds.Min.X+size.Y-48, size.X, 24), offset, r)
r.input.TextAlignment = ui.AlignCenter
center := bounds.Center()
distance := size.Y * .3
for i := range r.digits {
angle := (float32((10-i)%10)*0.16 + .2) * math.Pi
pos := geom.PtF32(distance*geom.Cos32(angle), .8*distance*geom.Sin32(angle))
digitCenter := center.Add(pos)
r.digits[i].Arrange(ctx, geom.RectRelF32(digitCenter.X-24, digitCenter.Y-24, 48, 48), offset, r)
}
}
func (r *Research) userTyped(ctx ui.Context, i int) {
r.digits[i].Blink()
digit := strconv.Itoa(i)
if len(r.typing) == 0 || digit != r.typing {
r.typing = digit
r.digitCount = 1
} else {
r.digitCount++
}
if !strings.HasPrefix(r.botanist.Number, r.input.Text+r.typing) {
r.input.Text = ""
r.typing = ""
r.digitCount = 0
} else if r.digitCount == i || r.digitCount == 10 {
r.input.Text += digit
r.typing = ""
r.digitCount = 0
if r.input.Text == r.botanist.Number {
r.game.UnlockNextFlower(ctx)
r.close()
r.input.Text = ""
}
}
}
func (r *Research) Handle(ctx ui.Context, event ui.Event) bool {
if r.ContainerBase.Handle(ctx, event) {
return true
}
switch e := event.(type) {
case *ui.KeyDownEvent:
switch e.Key {
case ui.Key0:
r.userTyped(ctx, 0)
case ui.KeyPad0:
r.userTyped(ctx, 0)
case ui.Key1:
r.userTyped(ctx, 1)
case ui.KeyPad1:
r.userTyped(ctx, 1)
case ui.Key2:
r.userTyped(ctx, 2)
case ui.KeyPad2:
r.userTyped(ctx, 2)
case ui.Key3:
r.userTyped(ctx, 3)
case ui.KeyPad3:
r.userTyped(ctx, 3)
case ui.Key4:
r.userTyped(ctx, 4)
case ui.KeyPad4:
r.userTyped(ctx, 4)
case ui.Key5:
r.userTyped(ctx, 5)
case ui.KeyPad5:
r.userTyped(ctx, 5)
case ui.Key6:
r.userTyped(ctx, 6)
case ui.KeyPad6:
r.userTyped(ctx, 6)
case ui.Key7:
r.userTyped(ctx, 7)
case ui.KeyPad7:
r.userTyped(ctx, 7)
case ui.Key8:
r.userTyped(ctx, 8)
case ui.KeyPad8:
r.userTyped(ctx, 8)
case ui.Key9:
r.userTyped(ctx, 9)
case ui.KeyPad9:
r.userTyped(ctx, 9)
}
}
return false
}
func (r *Research) Render(ctx ui.Context) {
for i := range r.digits {
r.digits[i].Tick()
}
r.ContainerBase.Render(ctx)
}
func (r *Research) onShow(ctx ui.Context) {
generateNumber := func() string {
var number string
for i := 0; i < 3; i++ {
number += strconv.Itoa(rand.Intn(9) + 1)
}
return number
}
r.digitCount = 0
r.input.Text = ""
var specialists string
defer func() {
r.specialists.Text = specialists
}()
_, _, price := r.game.Herbarium.NextFlowerToUnlock()
if price == 0 {
specialists += "Botanist (unlocks next flower; unavailable)\n"
specialists += "Farmer (fertilizes land; unavailable)\n"
return
}
r.botanist.Cost = price
if r.game.Balance < r.botanist.Cost {
r.botanist.Number = "**unavailable**"
} else {
r.botanist.Number = generateNumber()
}
specialists += fmt.Sprintf("Botanist: no. %s (unlocks next flower; $ %d)\n", r.botanist.Number, r.botanist.Cost)
specialists += "Farmer: no. **unavailable** (fertilizes land; $ ---)\n"
}