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) *LargeDialog { 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" }