248 lines
5.1 KiB
Go
248 lines
5.1 KiB
Go
|
package tins2020
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"math"
|
||
|
"math/rand"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
"time"
|
||
|
|
||
|
"github.com/veandco/go-sdl2/sdl"
|
||
|
)
|
||
|
|
||
|
type Research struct {
|
||
|
Container
|
||
|
|
||
|
game *Game
|
||
|
botanist Specialist
|
||
|
farmer Specialist
|
||
|
|
||
|
typing string
|
||
|
digitCount int
|
||
|
|
||
|
close func()
|
||
|
description Paragraph
|
||
|
specialists Paragraph
|
||
|
input Label
|
||
|
digits []Digit
|
||
|
animate Animation
|
||
|
}
|
||
|
|
||
|
func NewResearch(game *Game) Control {
|
||
|
research := &Research{
|
||
|
game: game,
|
||
|
animate: NewAnimation(20 * time.Millisecond),
|
||
|
}
|
||
|
dialog := &LargeDialog{}
|
||
|
dialog.SetCaption("Research")
|
||
|
dialog.SetContent(research)
|
||
|
dialog.OnShow().RegisterItf(func(state interface{}) {
|
||
|
research.onShow(state.(*Context))
|
||
|
})
|
||
|
research.close = func() { dialog.CloseDialog() }
|
||
|
return dialog
|
||
|
}
|
||
|
|
||
|
type Digit struct {
|
||
|
ControlBase
|
||
|
|
||
|
Value string
|
||
|
|
||
|
highlight int
|
||
|
}
|
||
|
|
||
|
func (d *Digit) Render(ctx *Context) {
|
||
|
font := ctx.Fonts.Font("title")
|
||
|
color := White
|
||
|
if d.highlight > 0 {
|
||
|
color = MustHexColor("#356DAD")
|
||
|
}
|
||
|
font.RenderCopyAlign(ctx.Renderer, d.Value, Pt(d.Bounds.X+d.Bounds.W/2, d.Bounds.Y+int32(font.Height())), color, TextAlignmentCenter)
|
||
|
}
|
||
|
|
||
|
func (d *Digit) Blink() {
|
||
|
d.highlight = 10
|
||
|
}
|
||
|
|
||
|
func (d *Digit) Tick() {
|
||
|
if d.highlight > 0 {
|
||
|
d.highlight--
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type Specialist struct {
|
||
|
Cost int
|
||
|
Number string
|
||
|
}
|
||
|
|
||
|
func (r *Research) Init(ctx *Context) error {
|
||
|
r.AddChild(&r.description)
|
||
|
r.AddChild(&r.specialists)
|
||
|
r.AddChild(&r.input)
|
||
|
r.description.Text = "Call a specialist to conduct research with."
|
||
|
r.digits = make([]Digit, 10)
|
||
|
for i := range r.digits {
|
||
|
r.digits[i].Value = strconv.Itoa(i)
|
||
|
r.AddChild(&r.digits[i])
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (r *Research) lastAvailableFlower() *FlowerDescriptor {
|
||
|
var desc *FlowerDescriptor
|
||
|
for _, id := range r.game.Herbarium.Flowers() {
|
||
|
flower, _ := r.game.Herbarium.Find(id)
|
||
|
if !flower.Unlocked {
|
||
|
return desc
|
||
|
}
|
||
|
desc = &flower
|
||
|
}
|
||
|
return desc
|
||
|
|
||
|
}
|
||
|
|
||
|
func (r *Research) firstLockedFlower() *FlowerDescriptor {
|
||
|
for _, id := range r.game.Herbarium.Flowers() {
|
||
|
flower, _ := r.game.Herbarium.Find(id)
|
||
|
if !flower.Unlocked {
|
||
|
return &flower
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (r *Research) Arrange(ctx *Context, bounds Rectangle) {
|
||
|
r.Container.Arrange(ctx, bounds)
|
||
|
r.specialists.Arrange(ctx, RectSize(r.Bounds.X, r.Bounds.Y+40, r.Bounds.W, r.Bounds.H-40))
|
||
|
r.input.Arrange(ctx, RectSize(r.Bounds.X, r.Bounds.X+r.Bounds.H-24, r.Bounds.W, 24))
|
||
|
r.input.Alignment = TextAlignmentCenter
|
||
|
|
||
|
center := Pt(r.Bounds.X+r.Bounds.W/2, r.Bounds.Y+r.Bounds.H/2)
|
||
|
|
||
|
distance := float64(bounds.H) * .3
|
||
|
for i := range r.digits {
|
||
|
angle := (float64((10-i)%10)*0.16 + .2) * math.Pi
|
||
|
pos := Pt(int32(distance*math.Cos(angle)), int32(.8*distance*math.Sin(angle)))
|
||
|
digitCenter := center.Add(pos)
|
||
|
r.digits[i].Arrange(ctx, RectSize(digitCenter.X-24, digitCenter.Y-24, 48, 48))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (r *Research) userTyped(i int) {
|
||
|
r.digits[i].Blink()
|
||
|
digit := strconv.Itoa(i)
|
||
|
if len(r.typing) == 0 {
|
||
|
r.typing = digit
|
||
|
r.digitCount = 1
|
||
|
} else if digit != r.typing {
|
||
|
r.typing = ""
|
||
|
r.digitCount = 0
|
||
|
} else {
|
||
|
r.digitCount++
|
||
|
}
|
||
|
if r.digitCount == i || r.digitCount == 10 {
|
||
|
r.input.Text += digit
|
||
|
r.typing = ""
|
||
|
r.digitCount = 0
|
||
|
|
||
|
if !strings.HasPrefix(r.input.Text, r.botanist.Number) {
|
||
|
r.input.Text = ""
|
||
|
} else if r.input.Text == r.botanist.Number {
|
||
|
r.game.UnlockNextFlower()
|
||
|
r.close()
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (r *Research) Handle(ctx *Context, event sdl.Event) bool {
|
||
|
switch e := event.(type) {
|
||
|
case *sdl.KeyboardEvent:
|
||
|
switch e.Keysym.Sym {
|
||
|
case sdl.K_0:
|
||
|
r.userTyped(0)
|
||
|
case sdl.K_KP_0:
|
||
|
r.userTyped(0)
|
||
|
case sdl.K_1:
|
||
|
r.userTyped(1)
|
||
|
case sdl.K_KP_1:
|
||
|
r.userTyped(1)
|
||
|
case sdl.K_2:
|
||
|
r.userTyped(2)
|
||
|
case sdl.K_KP_2:
|
||
|
r.userTyped(2)
|
||
|
case sdl.K_3:
|
||
|
r.userTyped(3)
|
||
|
case sdl.K_KP_3:
|
||
|
r.userTyped(3)
|
||
|
case sdl.K_4:
|
||
|
r.userTyped(4)
|
||
|
case sdl.K_KP_4:
|
||
|
r.userTyped(4)
|
||
|
case sdl.K_5:
|
||
|
r.userTyped(5)
|
||
|
case sdl.K_KP_5:
|
||
|
r.userTyped(5)
|
||
|
case sdl.K_6:
|
||
|
r.userTyped(6)
|
||
|
case sdl.K_KP_6:
|
||
|
r.userTyped(6)
|
||
|
case sdl.K_7:
|
||
|
r.userTyped(7)
|
||
|
case sdl.K_KP_7:
|
||
|
r.userTyped(7)
|
||
|
case sdl.K_8:
|
||
|
r.userTyped(8)
|
||
|
case sdl.K_KP_8:
|
||
|
r.userTyped(8)
|
||
|
case sdl.K_9:
|
||
|
r.userTyped(9)
|
||
|
case sdl.K_KP_9:
|
||
|
r.userTyped(9)
|
||
|
}
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
func (r *Research) Render(ctx *Context) {
|
||
|
for i := range r.digits {
|
||
|
r.digits[i].Tick()
|
||
|
}
|
||
|
r.Container.Render(ctx)
|
||
|
}
|
||
|
|
||
|
func (r *Research) onShow(ctx *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
|
||
|
}()
|
||
|
available := r.lastAvailableFlower()
|
||
|
locked := r.firstLockedFlower()
|
||
|
if locked == nil {
|
||
|
specialists += "Botanist (unlocks next flower; unavailable)\n"
|
||
|
specialists += "Farmer (fertilizes land; unavailable)\n"
|
||
|
return
|
||
|
}
|
||
|
|
||
|
r.botanist.Cost = 2 * available.BuyPrice
|
||
|
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"
|
||
|
}
|