tins2020/game.go

192 lines
3.9 KiB
Go
Raw Normal View History

2020-05-08 16:38:26 +00:00
package tins2020
import (
"log"
2020-05-08 16:38:26 +00:00
"math/rand"
"time"
2020-05-08 16:38:26 +00:00
)
type Game struct {
Balance int
Speed GameSpeed
SpeedBeforePause GameSpeed
Herbarium Herbarium
Terrain *Map
tool Tool
toolChanged *Events
simulation Animation
2020-05-08 16:38:26 +00:00
}
type GameSpeed string
const (
GameSpeedNormal GameSpeed = "normal"
GameSpeedFast = "fast"
GameSpeedPaused = "paused"
)
2020-05-08 16:38:26 +00:00
type Map struct {
Temp NoiseMap
Humid NoiseMap
Variant NoiseMap
PlaceX NoiseMap // displacement map of props
PlaceY NoiseMap
Flowers map[Point]Flower
}
func (m *Map) AddFlower(pos Point, traits FlowerTraits) {
m.Flowers[pos] = m.NewFlower(pos, traits)
2020-05-08 16:38:26 +00:00
}
func (m *Map) NewFlower(pos Point, traits FlowerTraits) Flower {
flower := Flower{
Traits: traits,
}
temp, humid := float32(m.Temp.Value(pos.X, pos.Y)), float32(m.Humid.Value(pos.X, pos.Y))
flower.Traits.UpdateModifier(temp, humid)
return flower
2020-05-08 16:38:26 +00:00
}
const simulationInterval = 120 * time.Millisecond
const fastSimulationInterval = 40 * time.Millisecond
2020-05-08 16:38:26 +00:00
func NewGame() *Game {
terrain := &Map{
Temp: NewNoiseMap(rand.Int63()),
Humid: NewNoiseMap(rand.Int63()),
Variant: NewRandomNoiseMap(rand.Int63()),
PlaceX: NewRandomNoiseMap(rand.Int63()),
PlaceY: NewRandomNoiseMap(rand.Int63()),
Flowers: map[Point]Flower{},
2020-05-08 16:38:26 +00:00
}
herbarium := NewHerbarium()
herbarium.Add("poppy", FlowerDescriptor{
Name: "Poppy",
Description: "A very generic flower that thrives in a moderate climate.",
IconTemplate: "flower-poppy-%s",
Price: 10,
Traits: NewPoppyTraits(),
Unlocked: true,
})
2020-05-08 16:38:26 +00:00
return &Game{
Speed: GameSpeedNormal,
Balance: 100,
Terrain: terrain,
Herbarium: herbarium,
toolChanged: NewEvents(),
simulation: NewAnimation(time.Millisecond * 10),
}
2020-05-08 16:38:26 +00:00
}
func (g *Game) selectTool(t Tool) {
g.tool = t
g.toolChanged.Notify(t)
}
func (g *Game) tick() {
randomNeighbor := func(pos Point) Point {
switch rand.Intn(4) {
case 0:
return Pt(pos.X-1, pos.Y)
case 1:
return Pt(pos.X, pos.Y-1)
case 2:
return Pt(pos.X+1, pos.Y)
case 3:
return Pt(pos.X, pos.Y+1)
}
return pos
}
flowers := map[Point]Flower{}
for pos, flower := range g.Terrain.Flowers {
if rand.Float32() < flower.Traits.Spread {
dst := randomNeighbor(pos)
if _, ok := g.Terrain.Flowers[dst]; !ok {
if _, ok := flowers[dst]; !ok {
flowers[dst] = g.Terrain.NewFlower(dst, flower.Traits)
}
}
}
if rand.Float32() < flower.Traits.Life*flower.Traits.LifeModifier {
flowers[pos] = flower
}
}
g.Terrain.Flowers = flowers
2020-05-08 16:38:26 +00:00
}
func (g *Game) CancelTool() {
g.selectTool(nil)
}
func (g *Game) Dig(tile Point) {
// TODO: implement
}
func (g *Game) Pause() {
if g.Speed == GameSpeedPaused {
return
}
g.SpeedBeforePause = g.Speed
g.Speed = GameSpeedPaused
g.simulation.Pause()
}
func (g *Game) PlantFlower(id string, tile Point) {
flower, ok := g.Herbarium.Find(id)
if !ok {
log.Println("user was able to plant a flower that doesn't exist")
return
}
if flower.Price > g.Balance {
// TODO: notify user of insufficient balance?
return
}
g.Balance -= flower.Price
g.Terrain.AddFlower(tile, flower.Traits)
}
func (g *Game) Resume() {
switch g.SpeedBeforePause {
case GameSpeedNormal:
g.Run()
case GameSpeedFast:
g.RunFast()
}
}
func (g *Game) Run() {
g.Speed = GameSpeedNormal
g.simulation.SetInterval(simulationInterval)
g.simulation.Run()
}
func (g *Game) RunFast() {
g.Speed = GameSpeedFast
g.simulation.SetInterval(fastSimulationInterval)
g.simulation.Run()
}
func (g *Game) SelectPlantFlowerTool(id string) {
g.selectTool(&PlantFlowerTool{FlowerID: id})
}
func (g *Game) Tool() Tool { return g.tool }
func (g *Game) ToolChanged() EventHandler { return g.toolChanged }
func (g *Game) Update() {
for g.simulation.Animate() {
g.tick()
}
}
func (g *Game) UserClickedTile(pos Point) {
if g.tool == nil {
return
}
g.tool.ClickedTile(g, pos)
}