krampus19/soko/levelparser.go

86 lines
1.7 KiB
Go

package soko
import (
"errors"
"fmt"
"io"
"opslag.de/schobers/krampus19/gut"
)
func ParseLevel(r io.Reader) (Level, error) {
var l Level
ctx := levelContext{&l}
err := gut.ParseLines(r, ctx.parse)
if err != nil {
return Level{}, err
}
return l, nil
}
type levelContext struct {
level *Level
}
func (c *levelContext) parse(p *gut.LineParser) gut.ParseLineFn {
if p.EOF() {
return nil
}
switch p.Peek() {
case "level:":
return c.parseContent
case "":
p.Next() // skip
return c.parse
default:
return nil
}
}
func (c *levelContext) parseContent(p *gut.LineParser) gut.ParseLineFn {
if p.Next() != "level:" {
return p.EmitErr(errors.New("expected level start"))
}
return c.parseRow
}
func (c *levelContext) parseRow(p *gut.LineParser) gut.ParseLineFn {
if p.EOF() {
return p.EmitErr(errors.New("unexpected end of file"))
}
line := p.Next()
if line == ":level" {
return c.parse
}
if c.level.Height == 0 {
c.level.Width = len(line) / 2
}
return c.addRow(p, line)
}
func (c *levelContext) addRow(p *gut.LineParser, line string) gut.ParseLineFn {
var tiles []TileType
var entities []EntityType
for i := 0; i < len(line); i += 2 {
tiles = append(tiles, TileType(line[i]))
entities = append(entities, EntityType(line[i+1]))
}
for i, t := range tiles {
if !t.IsValid() {
return p.EmitErr(fmt.Errorf("level contains invalid TileType at (%d, %d)", i, c.level.Height))
}
}
for i, e := range entities {
if !e.IsValid() {
return p.EmitErr(fmt.Errorf("level contains invalid entity type at (%d, %d)", i, c.level.Height))
}
}
c.level.Height++
c.level.Tiles = append(c.level.Tiles, tiles...)
c.level.Entities = append(c.level.Entities, entities...)
return c.parseRow
}