2022-05-01 13:29:39 +03:00
|
|
|
package model
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"image"
|
|
|
|
"image/png"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"regexp"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
_ "golang.org/x/image/bmp"
|
|
|
|
)
|
|
|
|
|
|
|
|
func (w *DfWorld) LoadMap() {
|
|
|
|
w.LoadDimensions()
|
|
|
|
|
2022-05-10 10:51:04 +03:00
|
|
|
fmt.Println("")
|
|
|
|
|
2022-05-01 13:29:39 +03:00
|
|
|
path := ""
|
|
|
|
files, err := filepath.Glob(strings.ReplaceAll(w.FilePath, "-legends.xml", "-world_map.*"))
|
|
|
|
if err == nil && len(files) > 0 {
|
|
|
|
path = files[len(files)-1]
|
|
|
|
}
|
|
|
|
files, err = filepath.Glob(strings.ReplaceAll(w.FilePath, "-legends.xml", "-detailed.*"))
|
|
|
|
if err == nil && len(files) > 0 {
|
|
|
|
path = files[len(files)-1]
|
|
|
|
}
|
|
|
|
|
|
|
|
if path == "" {
|
2022-05-10 10:51:04 +03:00
|
|
|
fmt.Println("no world map found")
|
2022-05-01 13:29:39 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
mapImage, err := os.Open(path)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-05-10 10:51:04 +03:00
|
|
|
fmt.Println("found world map", path)
|
2022-05-01 13:29:39 +03:00
|
|
|
img, format, err := image.Decode(mapImage)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
return
|
|
|
|
}
|
2022-05-10 10:51:04 +03:00
|
|
|
fmt.Println("loaded world map imgage as", format)
|
2022-05-01 13:29:39 +03:00
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
err = png.Encode(buf, img)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
w.MapData = buf.Bytes()
|
|
|
|
w.MapReady = true
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *DfWorld) LoadDimensions() {
|
2022-05-10 10:51:04 +03:00
|
|
|
fmt.Println("")
|
|
|
|
|
2022-05-01 13:29:39 +03:00
|
|
|
files, err := filepath.Glob(filepath.Join(filepath.Dir(w.FilePath), "*-world_gen_param.txt"))
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
path := ""
|
|
|
|
for _, f := range files {
|
|
|
|
prefix := filepath.Base(f)[:len(filepath.Base(f))-len("world_gen_param.txt")]
|
|
|
|
if strings.HasPrefix(filepath.Base(w.FilePath), prefix) {
|
|
|
|
path = f
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if path == "" {
|
2022-05-10 10:51:04 +03:00
|
|
|
fmt.Println("no worldgen params found")
|
2022-05-01 13:29:39 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-05-10 10:51:04 +03:00
|
|
|
fmt.Println("found worldgen params", path)
|
2022-05-01 13:29:39 +03:00
|
|
|
content, err := ioutil.ReadFile(path)
|
|
|
|
if err != nil {
|
2022-05-10 10:51:04 +03:00
|
|
|
fmt.Println(err)
|
2022-05-01 13:29:39 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
r := regexp.MustCompile(`\[DIM:(\d+):(\d+)\]`)
|
2022-05-05 23:18:31 +03:00
|
|
|
result := r.FindAllStringSubmatch(string(content), 1)
|
2022-05-01 13:29:39 +03:00
|
|
|
if result == nil {
|
2022-05-10 10:51:04 +03:00
|
|
|
fmt.Println("no world dimensions found")
|
2022-05-01 13:29:39 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
w.Width, _ = strconv.Atoi(result[0][2])
|
|
|
|
w.Height, _ = strconv.Atoi(result[0][1])
|
|
|
|
}
|
2022-05-07 18:08:42 +03:00
|
|
|
|
|
|
|
type Coord struct {
|
|
|
|
X, Y int
|
|
|
|
}
|
|
|
|
|
|
|
|
func Coords(s string) []Coord {
|
|
|
|
var coords []Coord
|
|
|
|
for _, c := range strings.Split(s, "|") {
|
|
|
|
if c == "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
d := strings.Split(c, ",")
|
|
|
|
x, _ := strconv.Atoi(d[0])
|
|
|
|
y, _ := strconv.Atoi(d[1])
|
|
|
|
coords = append(coords, Coord{X: x, Y: y})
|
|
|
|
}
|
|
|
|
return coords
|
|
|
|
}
|
|
|
|
|
|
|
|
func maxCoords(coords []Coord) Coord {
|
|
|
|
var max Coord
|
|
|
|
for _, c := range coords {
|
|
|
|
if c.X > max.X {
|
|
|
|
max.X = c.X
|
|
|
|
}
|
|
|
|
if c.Y > max.Y {
|
|
|
|
max.Y = c.Y
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return max
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Region) Outline() []Coord {
|
|
|
|
var outline []Coord
|
2022-05-08 17:38:38 +03:00
|
|
|
|
|
|
|
if r.Coords == "" {
|
|
|
|
return outline
|
|
|
|
}
|
2022-05-07 18:08:42 +03:00
|
|
|
// if (cacheOutline != null)
|
|
|
|
// return cacheOutline;
|
|
|
|
|
|
|
|
/* draw the region in a matrix */
|
|
|
|
coords := Coords(r.Coords)
|
|
|
|
max := maxCoords(coords)
|
|
|
|
|
|
|
|
var region = make([][]bool, max.X+3)
|
|
|
|
for i := range region {
|
|
|
|
region[i] = make([]bool, max.Y+3)
|
|
|
|
}
|
|
|
|
for _, c := range coords {
|
|
|
|
region[c.X+1][c.Y+1] = true
|
|
|
|
}
|
|
|
|
|
|
|
|
var curdir, prevdir rune
|
|
|
|
curdir = 'n'
|
|
|
|
if len(coords) == 1 || coords[0].X == coords[1].X-1 {
|
|
|
|
curdir = 'e'
|
|
|
|
}
|
|
|
|
|
|
|
|
x0 := coords[0].X + 1
|
|
|
|
y0 := coords[0].Y + 1
|
|
|
|
x := x0
|
|
|
|
y := y0
|
|
|
|
|
|
|
|
/* follow the outline by keeping the right hand inside */
|
|
|
|
Loop:
|
|
|
|
for {
|
|
|
|
if !(x != x0 || y != y0 || prevdir == 0) {
|
|
|
|
break Loop
|
|
|
|
}
|
|
|
|
|
|
|
|
prevdir = curdir
|
|
|
|
switch {
|
|
|
|
case curdir == 'n' && y > 1:
|
|
|
|
y -= 1
|
|
|
|
if region[x-1][y-1] {
|
|
|
|
curdir = 'w'
|
|
|
|
} else if !region[x][y-1] {
|
|
|
|
curdir = 'e'
|
|
|
|
}
|
|
|
|
case curdir == 's' && y < max.Y+2:
|
|
|
|
y += 1
|
|
|
|
if region[x][y] {
|
|
|
|
curdir = 'e'
|
|
|
|
} else if !region[x-1][y] {
|
|
|
|
curdir = 'w'
|
|
|
|
}
|
|
|
|
case curdir == 'w' && x > 1:
|
|
|
|
x -= 1
|
|
|
|
if region[x-1][y] {
|
|
|
|
curdir = 's'
|
|
|
|
} else if !region[x-1][y-1] {
|
|
|
|
curdir = 'n'
|
|
|
|
}
|
|
|
|
case curdir == 'e' && x < max.X+2:
|
|
|
|
x += 1
|
|
|
|
if region[x][y-1] {
|
|
|
|
curdir = 'n'
|
|
|
|
} else if !region[x][y] {
|
|
|
|
curdir = 's'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if curdir != prevdir {
|
|
|
|
/* change of direction: record point */
|
|
|
|
outline = append(outline, Coord{X: x - 1, Y: y - 1})
|
|
|
|
if len(outline) > 256*10 {
|
|
|
|
break Loop
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return outline
|
|
|
|
}
|
|
|
|
|
|
|
|
func (x *WorldConstruction) Line() []Coord {
|
|
|
|
return Coords(x.Coords)
|
|
|
|
}
|