2020-05-11 12:41:42 +00:00
|
|
|
package tins2020
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"math"
|
|
|
|
"math/rand"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
2020-05-17 08:56:56 +00:00
|
|
|
"opslag.de/schobers/geom"
|
|
|
|
|
|
|
|
"opslag.de/schobers/zntg"
|
|
|
|
"opslag.de/schobers/zntg/ui"
|
2020-05-11 12:41:42 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type Research struct {
|
2020-05-17 08:56:56 +00:00
|
|
|
ui.ContainerBase
|
2020-05-11 12:41:42 +00:00
|
|
|
|
|
|
|
game *Game
|
|
|
|
botanist Specialist
|
|
|
|
farmer Specialist
|
|
|
|
|
|
|
|
typing string
|
|
|
|
digitCount int
|
|
|
|
|
|
|
|
close func()
|
2020-05-17 08:56:56 +00:00
|
|
|
description ui.Paragraph
|
|
|
|
specialists ui.Paragraph
|
|
|
|
input ui.Label
|
2020-05-11 12:41:42 +00:00
|
|
|
digits []Digit
|
2020-05-17 08:56:56 +00:00
|
|
|
animate zntg.Animation
|
2020-05-11 12:41:42 +00:00
|
|
|
}
|
|
|
|
|
2020-05-17 08:56:56 +00:00
|
|
|
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])
|
2020-05-11 12:41:42 +00:00
|
|
|
}
|
2020-05-17 08:56:56 +00:00
|
|
|
dialog := NewLargeDialog("Research", research)
|
|
|
|
// dialog.OnShow().RegisterItf(func(state interface{}) {
|
|
|
|
// research.onShow(state.(ui.Context))
|
|
|
|
// })
|
|
|
|
// research.close = func() { dialog.CloseDialog() }
|
2020-05-11 12:41:42 +00:00
|
|
|
return dialog
|
|
|
|
}
|
|
|
|
|
|
|
|
type Digit struct {
|
2020-05-17 08:56:56 +00:00
|
|
|
ui.ControlBase
|
2020-05-11 12:41:42 +00:00
|
|
|
|
|
|
|
Value string
|
|
|
|
|
|
|
|
highlight int
|
|
|
|
}
|
|
|
|
|
2020-05-14 10:59:11 +00:00
|
|
|
func (d *Digit) Blink() {
|
|
|
|
d.highlight = 4
|
|
|
|
}
|
|
|
|
|
2020-05-17 08:56:56 +00:00
|
|
|
func (d *Digit) Render(ctx ui.Context) {
|
|
|
|
color := zntg.MustHexColor(`#FFFFFF`)
|
2020-05-11 12:41:42 +00:00
|
|
|
if d.highlight > 0 {
|
2020-05-17 08:56:56 +00:00
|
|
|
color = zntg.MustHexColor(`#15569F`)
|
2020-05-11 12:41:42 +00:00
|
|
|
}
|
2020-05-17 08:56:56 +00:00
|
|
|
bounds := d.Bounds()
|
|
|
|
ctx.Fonts().TextAlign("title", geom.PtF32(bounds.Center().X, bounds.Min.Y), color, d.Value, ui.AlignCenter)
|
2020-05-11 12:41:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (d *Digit) Tick() {
|
|
|
|
if d.highlight > 0 {
|
|
|
|
d.highlight--
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type Specialist struct {
|
|
|
|
Cost int
|
|
|
|
Number string
|
|
|
|
}
|
|
|
|
|
2020-05-17 08:56:56 +00:00
|
|
|
func (r *Research) Arrange(ctx ui.Context, bounds geom.RectangleF32, offset geom.PointF32, parent ui.Control) {
|
|
|
|
r.ContainerBase.Arrange(ctx, bounds, offset, parent)
|
2020-05-11 12:41:42 +00:00
|
|
|
|
2020-05-17 08:56:56 +00:00
|
|
|
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
|
2020-05-11 12:41:42 +00:00
|
|
|
|
2020-05-17 08:56:56 +00:00
|
|
|
center := bounds.Center()
|
2020-05-11 12:41:42 +00:00
|
|
|
|
2020-05-17 08:56:56 +00:00
|
|
|
distance := size.Y * .3
|
2020-05-11 12:41:42 +00:00
|
|
|
for i := range r.digits {
|
2020-05-17 08:56:56 +00:00
|
|
|
angle := (float32((10-i)%10)*0.16 + .2) * math.Pi
|
|
|
|
pos := geom.PtF32(distance*geom.Cos32(angle), .8*distance*geom.Sin32(angle))
|
2020-05-11 12:41:42 +00:00
|
|
|
digitCenter := center.Add(pos)
|
2020-05-17 08:56:56 +00:00
|
|
|
r.digits[i].Arrange(ctx, geom.RectRelF32(digitCenter.X-24, digitCenter.Y-24, 48, 48), offset, r)
|
2020-05-11 12:41:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-17 08:56:56 +00:00
|
|
|
func (r *Research) userTyped(ctx ui.Context, i int) {
|
2020-05-11 12:41:42 +00:00
|
|
|
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
|
2020-05-11 13:52:43 +00:00
|
|
|
r.typing = ""
|
|
|
|
r.digitCount = 0
|
2020-05-11 12:41:42 +00:00
|
|
|
|
|
|
|
if r.input.Text == r.botanist.Number {
|
2020-05-17 08:56:56 +00:00
|
|
|
r.game.UnlockNextFlower(ctx)
|
2020-05-11 12:41:42 +00:00
|
|
|
r.close()
|
|
|
|
r.input.Text = ""
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-17 08:56:56 +00:00
|
|
|
func (r *Research) Handle(ctx ui.Context, event ui.Event) bool {
|
|
|
|
if r.ContainerBase.Handle(ctx, event) {
|
2020-05-14 10:59:11 +00:00
|
|
|
return true
|
|
|
|
}
|
2020-05-11 12:41:42 +00:00
|
|
|
switch e := event.(type) {
|
2020-05-17 08:56:56 +00:00
|
|
|
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)
|
2020-05-11 12:41:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2020-05-17 08:56:56 +00:00
|
|
|
func (r *Research) Render(ctx ui.Context) {
|
2020-05-11 12:41:42 +00:00
|
|
|
for i := range r.digits {
|
|
|
|
r.digits[i].Tick()
|
|
|
|
}
|
2020-05-17 08:56:56 +00:00
|
|
|
r.ContainerBase.Render(ctx)
|
2020-05-11 12:41:42 +00:00
|
|
|
}
|
|
|
|
|
2020-05-17 08:56:56 +00:00
|
|
|
func (r *Research) onShow(ctx ui.Context) {
|
2020-05-11 12:41:42 +00:00
|
|
|
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"
|
|
|
|
}
|