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" }