package tins2020 import ( "log" "math/rand" "time" ) type Game struct { Balance int Speed GameSpeed SpeedBeforePause GameSpeed Herbarium Herbarium Terrain *Map tool Tool toolChanged *Events speedChanged *Events simulation Animation } type GameSpeed string const ( GameSpeedNormal GameSpeed = "normal" GameSpeedFast = "fast" GameSpeedPaused = "paused" ) const simulationInterval = 120 * time.Millisecond const fastSimulationInterval = 40 * time.Millisecond 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{}, } herbarium := NewHerbarium() herbarium.Add("anemone", FlowerDescriptor{ Name: "Anemone", Description: "A very generic flower that thrives in a temperate climate.", IconTemplate: "flower-anemone-%s", BuyPrice: 10, SellPrice: 3, Traits: NewPoppyTraits(), Unlocked: true, }) herbarium.Add("loosestrife", FlowerDescriptor{ Name: "Loosestrife", Description: "A simple flower that will spread in temperate and wet climates.", IconTemplate: "flower-loosestrife-%s", BuyPrice: 100, SellPrice: 20, Traits: NewLoosestrifeTraits(), Unlocked: false, }) herbarium.Add("tulip", FlowerDescriptor{ Name: "Tulip", Description: "A lovely flower that prefers a bit humid and colder climates.", IconTemplate: "flower-tulip-%s", BuyPrice: 500, SellPrice: 100, Traits: NewTulipTraits(), Unlocked: false, }) herbarium.Add("coneflower", FlowerDescriptor{ Name: "Coneflower", Description: "A beautifull flower that can withstand hotter climates.", IconTemplate: "flower-coneflower-%s", BuyPrice: 20000, SellPrice: 5000, Traits: NewConeflowerTraits(), Unlocked: false, }) herbarium.Add("ajuga", FlowerDescriptor{ Name: "Ajuga", Description: "A flower that is resitant to cold climates and spreads very easily.", IconTemplate: "flower-ajuga-%s", BuyPrice: 100000, SellPrice: 10000, Traits: NewAjugaTraits(), Unlocked: false, }) return &Game{ Speed: GameSpeedNormal, Balance: 100, Terrain: terrain, Herbarium: herbarium, speedChanged: NewEvents(), toolChanged: NewEvents(), simulation: NewAnimation(time.Millisecond * 10), } } func (g *Game) selectTool(t Tool) { g.tool = t g.toolChanged.Notify(t) } func (g *Game) setSpeed(speed GameSpeed) { if speed == g.Speed { return } if speed == GameSpeedPaused { g.SpeedBeforePause = g.Speed } g.Speed = speed g.speedChanged.Notify(speed) switch speed { case GameSpeedPaused: g.simulation.Pause() case GameSpeedNormal: g.simulation.SetInterval(simulationInterval) g.simulation.Run() case GameSpeedFast: g.simulation.SetInterval(fastSimulationInterval) g.simulation.Run() } } 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.ID, flower.Traits) } } } if Sqr32(rand.Float32()) < flower.Traits.Life*flower.Traits.LifeModifier { flowers[pos] = flower } } g.Terrain.Flowers = flowers } func (g *Game) CancelTool() { g.selectTool(nil) } func (g *Game) Dig(tile Point) { id := g.Terrain.DigFlower(tile) desc, ok := g.Herbarium.Find(id) if !ok { return } g.Balance += desc.SellPrice } func (g *Game) Pause() { g.setSpeed(GameSpeedPaused) } 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.BuyPrice > g.Balance { // TODO: notify user of insufficient balance? return } g.Balance -= flower.BuyPrice g.Terrain.AddFlower(tile, id, flower.Traits) } func (g *Game) Resume() { g.setSpeed(g.SpeedBeforePause) } func (g *Game) Run() { g.setSpeed(GameSpeedNormal) } func (g *Game) RunFast() { g.setSpeed(GameSpeedFast) } func (g *Game) SelectPlantFlowerTool(id string) { g.selectTool(&PlantFlowerTool{FlowerID: id}) } func (g *Game) SelectShovel() { g.selectTool(&ShovelTool{}) } func (g *Game) SelectResearch() { g.Pause() } func (g *Game) SpeedChanged() EventHandler { return g.speedChanged } func (g *Game) TogglePause() { if g.Speed == GameSpeedPaused { g.Resume() } else { g.Pause() } } 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) }