rove/pkg/rove/worldgen.go

110 lines
2.5 KiB
Go

package rove
import (
"encoding/json"
"log"
"math/rand"
"github.com/mdiluz/rove/pkg/maths"
"github.com/mdiluz/rove/proto/roveapi"
"github.com/ojrac/opensimplex-go"
)
// WorldGen describes a world gen algorythm
type WorldGen interface {
// GetTile generates a tile for a location
GetTile(v maths.Vector) roveapi.Tile
// GetObject generates an object for a location
GetObject(v maths.Vector) Object
}
// NoiseWorldGen returns a noise based world generator
type NoiseWorldGen struct {
// noise describes the noise function
noise opensimplex.Noise
}
// NewNoiseWorldGen creates a new noise based world generator
func NewNoiseWorldGen(seed int64) WorldGen {
return &NoiseWorldGen{
noise: opensimplex.New(seed),
}
}
const (
terrainNoiseScale = 15
rockNoiseScale = 3
partsNoiseScale = 2
)
// GetTile returns the chosen tile at a location
func (g *NoiseWorldGen) GetTile(v maths.Vector) roveapi.Tile {
t := g.noise.Eval2(float64(v.X)/terrainNoiseScale, float64(v.Y)/terrainNoiseScale)
switch {
case t > 0.5:
return roveapi.Tile_Gravel
case t > 0.05:
return roveapi.Tile_Sand
default:
return roveapi.Tile_Rock
}
}
// GetObject returns the chosen object at a location
func (g *NoiseWorldGen) GetObject(v maths.Vector) (obj Object) {
r := g.noise.Eval2(float64(v.X)/rockNoiseScale, float64(v.Y)/rockNoiseScale)
switch {
// Prioritise rocks
case r > 0.6:
obj.Type = roveapi.Object_RockLarge
case r > 0.5:
obj.Type = roveapi.Object_RockSmall
default:
// Otherwise, try some rover parts
p := g.noise.Eval2(float64(v.X)/partsNoiseScale, float64(v.Y)/partsNoiseScale)
switch {
case p > 0.8:
obj.Type = roveapi.Object_RoverParts
}
}
// Very rarely spawn a dormant rover
if obj.Type == roveapi.Object_ObjectUnknown {
// TODO: Make this better, ideally with noise
if v.X%25 == 0 && v.Y%25 == 0 && v.X != 0 && v.Y != 0 {
obj.Type = roveapi.Object_RoverDormant
}
}
// Post process any spawned objects
switch obj.Type {
case roveapi.Object_RoverDormant:
// Create the rover
r := DefaultRover()
// Set the rover variables
r.Pos = v
// Upgrade this rover randomly
r.MaximumCharge += rand.Int() % 3
r.MaximumIntegrity += rand.Int() % 3
r.Capacity += rand.Int() % 3
r.Range += rand.Int() % 3
// For now, mark the log as corrupted
r.AddLogEntryf("log corrupted")
// Marshal the rover data into the object data
b, err := json.Marshal(r)
if err != nil {
log.Fatalf("couldn't marshal rover, should never fail: %s", err)
}
// Store the bytes
obj.Data = b
}
return obj
}