Browse Source

Move to Gitlab. Also fix lexer bugs.

Beoran 7 years ago
parent
commit
046577a09b
18 changed files with 1316 additions and 1437 deletions
  1. 45 120
      raku/raku.go
  2. 32 6
      raku/raku_test.go
  3. 93 96
      server/action.go
  4. 5 5
      server/ask.go
  5. 3 3
      server/client.go
  6. 2 2
      server/dialog.go
  7. 2 2
      server/server.go
  8. 3 3
      server/setuptelnet.go
  9. 309 328
      sitef/sitef.go
  10. 1 1
      telnet/telnet.go
  11. 3 3
      woe.go
  12. 135 149
      world/account.go
  13. 2 2
      world/being.go
  14. 89 94
      world/character.go
  15. 155 164
      world/entity.go
  16. 232 243
      world/item.go
  17. 42 43
      world/room.go
  18. 163 173
      world/world.go

+ 45 - 120
raku/raku.go

@@ -6,15 +6,15 @@ Desrired syntax (verified LL(1) on smlweb.cpsc.ucalgary.ca)
 
 PROGRAM -> STATEMENTS.
 STATEMENTS -> STATEMENT STATEMENTS | .
-STATEMENT -> EXPRESSION EOX  | DEFINITION | BLOCK | EOX .
-DEFINITION -> define WORDS BLOCK.
-WORDS -> word WORDS | .
-EXPRESSION -> WORDVALUE MODIFIERS.
-MODIFIERS -> MODIFIER MODIFIERS | .
-OPERATION ->  operator MODIFIER .
-MODIFIER -> OPERATION | WORDVALUE | PARENTHESIS | BLOCK.
+STATEMENT -> EXPRESSION EOX  | DEFINITION | BLOCK .
+DEFINITION -> define WORDOP WORDOPS BLOCK.
+WORDOPS -> WORDOP WORDOPS | .
+EXPRESSION -> WORDVALUE PARAMETERSS.
+PARAMETERS -> PARAMETER PARAMETERS | .
+PARAMETER -> WORDVALUE | PARENTHESIS | BLOCK | operator.
 PARENTHESIS -> '(' EXPRESSION ')' | ot EXPRESSION ct.
 BLOCK -> oe STATEMENTS ce | do STATEMENTS end .
+WORDOP -> word | operator | a | the.
 WORDVALUE -> word | VALUE | a | the.
 VALUE -> string | number | symbol.
 EOX -> eol | period.
@@ -34,9 +34,9 @@ import (
 	"strings"
 	"unicode"
 
-	"github.com/beoran/woe/graphviz"
-	"github.com/beoran/woe/monolog"
-	"github.com/beoran/woe/tree"
+	"gitlab.com/beoran/woe/graphviz"
+	"gitlab.com/beoran/woe/monolog"
+	"gitlab.com/beoran/woe/tree"
 )
 
 type Value string
@@ -121,6 +121,8 @@ var sigilMap map[string]TokenType = map[string]TokenType{
 	")": TokenCloseParen,
 }
 
+const operator_chars = "&|@'^-*%/+=<>~\\"
+
 func (me TokenType) String() string {
 	name, found := tokenTypeMap[me]
 	if found {
@@ -241,7 +243,7 @@ func LexComment(me *Lexer) LexerRule {
 }
 
 func LexPunctuator(me *Lexer) LexerRule {
-	me.Found(TokenType(me.Next()))
+	me.Found(TokenType(me.Peek()))
 	me.Advance()
 	return LexNormal
 }
@@ -253,13 +255,8 @@ func LexEOL(me *Lexer) LexerRule {
 }
 
 func LexOperator(me *Lexer) LexerRule {
-	me.SkipNotIn(" \t\r\n({[]})")
-	issig, kind := LookupSigil(me.CurrentStringValue())
-	if issig {
-		me.Found(kind)
-	} else {
-		me.Found(TokenOperator)
-	}
+	me.SkipIn(operator_chars)
+	me.Found(TokenOperator)
 	return LexNormal
 }
 
@@ -323,8 +320,10 @@ func LexNormal(me *Lexer) LexerRule {
 		return LexWord
 	} else if unicode.IsDigit(peek) {
 		return LexNumber
-	} else {
+	} else if strings.ContainsRune(operator_chars, peek) {
 		return LexOperator
+	} else {
+		return LexError
 	}
 }
 
@@ -747,13 +746,6 @@ func (me *Parser) ParseWordValue() bool {
 	return res
 }
 
-func (me *Parser) ParseParameter() bool {
-	me.NewAstChildDescend(AstTypeParameter)
-	res := me.ParseWordValue() || me.ParseBlock()
-	me.AstAscend(res)
-	return res
-}
-
 func (me *Parser) ParseParametersNonempty() bool {
 	res := false
 	for me.ParseParameter() {
@@ -762,13 +754,6 @@ func (me *Parser) ParseParametersNonempty() bool {
 	return res
 }
 
-func (me *Parser) ParseParameters() bool {
-	me.NewAstChildDescend(AstTypeParameters)
-	_ = me.ParseParametersNonempty()
-	me.AstAscend(true)
-	return true
-}
-
 func (me *Parser) ParseCallArgs() bool {
 	me.NewAstChildDescend(AstTypeCallArgs)
 	res := me.ParseParameters() && me.ParseEOX()
@@ -780,52 +765,6 @@ func (me *Parser) ParseOperator() bool {
 	return me.Consume(AstTypeOperator, TokenOperator)
 }
 
-/*
-func (me *Parser) ParseOperation() bool {
-	me.NewAstChildDescend(AstTypeOperation)
-	res := me.ParseOperator() && me.ParseParameter()
-	me.AstAscend(res)
-	return res
-}
-*/
-
-func (me *Parser) ParseOperations() bool {
-	me.NewAstChildDescend(AstTypeOperations)
-	res := me.ParseOperation()
-	for me.ParseOperation() {
-	}
-	me.AstAscend(res)
-	return res
-}
-
-func (me *Parser) ParseWordCallOp() bool {
-	me.NewAstChildDescend(AstTypeWordCallop)
-	res := me.ParseCallArgs() || me.ParseOperations()
-	me.AstAscend(res)
-	return res
-}
-
-func (me *Parser) ParseWordExpression() bool {
-	me.NewAstChildDescend(AstTypeWordExpression)
-	res := me.ParseWord() && me.ParseWordCallOp()
-	me.AstAscend(res)
-	return res
-}
-
-func (me *Parser) ParseValueCallOp() bool {
-	me.NewAstChildDescend(AstTypeValueCallop)
-	res := me.ParseCallArgs() || me.ParseOperations()
-	me.AstAscend(res)
-	return res
-}
-
-func (me *Parser) ParseValueExpression() bool {
-	me.NewAstChildDescend(AstTypeValueExpression)
-	res := me.ParseValue() && me.ParseValueCallOp()
-	me.AstAscend(res)
-	return false
-}
-
 func (me *Parser) NewAstChild(tyty AstType) *Ast {
 	return me.now.NewChild(tyty, me.lookahead)
 }
@@ -849,8 +788,8 @@ func (me TokenType) BlockCloseForOpen() (TokenType, bool) {
 	switch me {
 	case TokenOpenBrace:
 		return TokenCloseBrace, true
-	case TokenOpenParen:
-		return TokenCloseParen, true
+	case TokenKeywordDo:
+		return TokenKeywordEnd, true
 	default:
 		return TokenError, false
 	}
@@ -928,35 +867,28 @@ func (me *Parser) ParseDefinition() bool {
 	if !res {
 		return false
 	}
-	res = res && me.ParseWords()
+	res = res && (me.ParseWord() || me.ParseOperator())
 	if !res {
 		_ = me.ParseError()
 	}
-	res = res && me.ParseBlock()
+	res = res && me.ParseParametersNonempty()
 	if !res {
 		_ = me.ParseError()
 	}
-	me.AstAscend(true)
-	return res
-}
-
-func (me *Parser) ParseOperation() bool {
-	me.NewAstChildDescend(AstTypeOperation)
-	res := me.ParseOperator() && me.ParseModifier()
 	me.AstAscend(res)
 	return res
 }
 
-func (me *Parser) ParseModifier() bool {
-	me.NewAstChildDescend(AstTypeModifier)
-	res := me.ParseOperation() || me.ParseWordValue() ||
+func (me *Parser) ParseParameter() bool {
+	me.NewAstChildDescend(AstTypeParameter)
+	res := me.ParseWordValue() || me.ParseOperator() ||
 		me.ParseParenthesis() || me.ParseBlock()
 	me.AstAscend(res)
 	return res
 }
 
-func (me *Parser) ParseModifiers() bool {
-	for me.ParseModifier() {
+func (me *Parser) ParseParameters() bool {
+	for me.ParseParameter() {
 	}
 	return true
 }
@@ -968,7 +900,7 @@ func (me *Parser) ParseError() bool {
 }
 
 func (me *Parser) ParseExpression() bool {
-	return me.ParseWordValue() && me.ParseModifiers()
+	return (me.ParseWordValue() || me.ParseOperator()) && me.ParseParameters()
 }
 
 func (me *Parser) ParseStatement() bool {
@@ -1041,70 +973,63 @@ func (me *Ast) Dotty() {
 
 PROGRAM -> STATEMENTS.
 STATEMENTS -> STATEMENT STATEMENTS | .
-STATEMENT -> EXPRESSION EOX  | DEFINITION | BLOCK | EOX .
-DEFINITION -> define WORDS BLOCK.
-WORDS -> word WORDS | .
-EXPRESSION -> WORDVALUE MODIFIERS.
-MODIFIERS -> MODIFIER MODIFIERS | .
-OPERATION ->  operator MODIFIER .
-MODIFIER -> OPERATION | WORDVALUE | PARENTHESIS | BLOCK.
+STATEMENT -> EXPRESSION EOX  | DEFINITION | BLOCK .
+DEFINITION -> define WORDOP WORDOPS BLOCK.
+WORDOPS -> WORDOP WORDOPS | .
+EXPRESSION -> WORDVALUE PARAMETERSS.
+PARAMETERS -> PARAMETER PARAMETERS | .
+PARAMETER -> WORDVALUE | PARENTHESIS | BLOCK | operator.
 PARENTHESIS -> '(' EXPRESSION ')' | ot EXPRESSION ct.
 BLOCK -> oe STATEMENTS ce | do STATEMENTS end .
+WORDOP -> word | operator | a | the.
 WORDVALUE -> word | VALUE | a | the.
 VALUE -> string | number | symbol.
 EOX -> eol | period.
 
-	AstNodeBlock = AstNodeType(iota)
 )
 */
 
 type DefineType int
 
 const (
-		DefineTypeNone = DefineType(iota),
-		DefineTypeGo,
-		DefineTypeUser,
-		DefineTypeVar,
+	DefineTypeNone = DefineType(iota)
+	DefineTypeGo
+	DefineTypeUser
+	DefineTypeVar
 )
 
-type Value interface {
-	
+type Var interface {
 }
 
 type DefinePattern struct {
 	Parts []string
 }
 
-type GoDefineFunc func(runtime Runtime, args ... Value) Value;
+type GoDefineFunc func(runtime Runtime, args ...Var) Var
 
 type UserDefine struct {
 	DefinePattern
-	* Ast	
+	*Ast
 }
 
 type GoDefine struct {
 	DefinePattern
-	* GoDefineFunc
+	*GoDefineFunc
 }
 
-
 type Define struct {
 	DefineType
-	Ast * definition
+	definition *Ast
 }
 
 type Environment struct {
-	Parent *Environment	
+	Parent *Environment
 }
 
-
 type Runtime struct {
 	Environment
 }
 
-
-
-
 func main() {
 	fmt.Println("Hello World!")
 }

+ 32 - 6
raku/raku_test.go

@@ -5,8 +5,8 @@ import (
 	"strings"
 	"testing"
 
-	_ "github.com/beoran/woe/monolog"
-	"github.com/beoran/woe/tree"
+	_ "gitlab.com/beoran/woe/monolog"
+	"gitlab.com/beoran/woe/tree"
 )
 
 func HelperTryLexing(me *Lexer, test *testing.T) {
@@ -123,7 +123,7 @@ func TestParseWordExpression(test *testing.T) {
 	const input = `say "hello world" three times
 	`
 	parser := NewParserForText(input)
-	Assert(test, parser.ParseWordExpression(), "Could not parse word expression")
+	Assert(test, parser.ParseExpression(), "Could not parse word expression")
 	tree.Display(parser.Ast)
 }
 
@@ -131,7 +131,7 @@ func TestParseWordExpression2(test *testing.T) {
 	const input = `val + 10 * z
 	`
 	parser := NewParserForText(input)
-	Assert(test, parser.ParseWordExpression(), "Could not parse word expression with operators")
+	Assert(test, parser.ParseExpression(), "Could not parse word expression with operators")
 	tree.Display(parser.Ast)
 }
 
@@ -152,11 +152,18 @@ func TestParseProgram(test *testing.T) {
 }
 
 func TestParseProgram2(test *testing.T) {
-	const input = `to greet someone  {
+	const input = `define greet a person  do
 say "hello" someone
-}
+end
 
 greet bob
+greet sally
+if 0 do
+	foo
+end else {
+	bar
+}
+
 
 if mp < cost do
 	say "Not enough mana!"
@@ -168,6 +175,7 @@ end
 	parser := NewParserForText(input)
 	Assert(test, parser.ParseProgram(), "Could not parse program.")
 	tree.Display(parser.Ast)
+	parser.Ast.Dotty()
 }
 
 func TestParseblock(test *testing.T) {
@@ -206,6 +214,15 @@ func TestParseParenthesis(test *testing.T) {
 	parser.Ast.Dotty()
 }
 
+func TestParseBlock2(test *testing.T) {
+	// monolog.Setup("raku_test.log", true, false)
+	const input = `{ . }`
+	parser := NewParserForText(input)
+	Assert(test, parser.ParseBlock(), "Could not parse block.")
+	tree.Display(parser.Ast)
+	parser.Ast.Dotty()
+}
+
 func LexingTest(test *testing.T, input string, expected ...TokenType) {
 	tokens := LexText(input)
 	if len(tokens) != len(expected) {
@@ -224,3 +241,12 @@ func TestLexingParen(test *testing.T) {
 	LexingTest(test, "(", TokenOpenParen, TokenEOF)
 	LexingTest(test, "((", TokenOpenParen, TokenOpenParen, TokenEOF)
 }
+
+func TestLexingDoEnd(test *testing.T) {
+	LexingTest(test, "do", TokenKeywordDo, TokenEOF)
+	LexingTest(test, "end", TokenKeywordEnd, TokenEOF)
+	LexingTest(test, "do\nend", TokenKeywordDo, TokenEOL, TokenKeywordEnd, TokenEOF)
+	LexingTest(test, ".}", TokenPeriod, TokenCloseBrace, TokenEOF)
+	LexingTest(test, "{.}", TokenOpenBrace, TokenPeriod, TokenCloseBrace, TokenEOF)
+
+}

+ 93 - 96
server/action.go

@@ -3,129 +3,126 @@ package server
 import "bytes"
 import "errors"
 import "regexp"
-// import "github.com/beoran/woe/telnet"
-import "github.com/beoran/woe/world"
-import "github.com/beoran/woe/monolog"
 
+// imporgitlab.comomm/beoran/woe/telnet"
+import "gitlab.com/beoran/woe/world"
+import "gitlab.com/beoran/woe/monolog"
 
-/* Actiondata are the params passed to an Actin, neatly wrapped in 
+/* Actiondata are the params passed to an Actin, neatly wrapped in
  * a struct */
 type ActionData struct {
-    Client * Client
-    Server * Server
-    World  * world.World
-    Account* world.Account
-    Action * Action
-    Command  []byte
-    Rest     []byte
-    Argv     [][]byte
+	Client  *Client
+	Server  *Server
+	World   *world.World
+	Account *world.Account
+	Action  *Action
+	Command []byte
+	Rest    []byte
+	Argv    [][]byte
 }
 
 /* A handler for an action. */
-type ActionHandler func(data * ActionData) (err error) 
+type ActionHandler func(data *ActionData) (err error)
 
-/* Actions that  a client can perform on a server or in 
+/* Actions that  a client can perform on a server or in
  * the server's world. */
 type Action struct {
-    Name        string
-    Privilege   world.Privilege
-    Handler     ActionHandler
+	Name      string
+	Privilege world.Privilege
+	Handler   ActionHandler
 }
 
-
-var ActionMap map[string] Action
+var ActionMap map[string]Action
 
 func AddAction(name string, privilege world.Privilege, handler ActionHandler) {
-    monolog.Info("Adding new action %s with privilege %d", name, privilege)
-    action := Action{name, privilege, handler}
-    ActionMap[name] = action
+	monolog.Info("Adding new action %s with privilege %d", name, privilege)
+	action := Action{name, privilege, handler}
+	ActionMap[name] = action
 }
 
-func doShout(data * ActionData) (err error) {
-      data.Server.Broadcast("Client said %s\r\n", data.Rest)
-      return nil  
+func doShout(data *ActionData) (err error) {
+	data.Server.Broadcast("Client said %s\r\n", data.Rest)
+	return nil
 }
 
-func doShutdown(data * ActionData) (err error) {    
-    data.Server.Broadcast("Shutting down server NOW!\n")
-    data.Server.Restart();
-    return nil
+func doShutdown(data *ActionData) (err error) {
+	data.Server.Broadcast("Shutting down server NOW!\n")
+	data.Server.Restart()
+	return nil
 }
 
-func doRestart(data * ActionData) (err error) {
-    data.Server.Broadcast("Restarting server NOW!\n")
-    data.Server.Restart();
-    return nil
+func doRestart(data *ActionData) (err error) {
+	data.Server.Broadcast("Restarting server NOW!\n")
+	data.Server.Restart()
+	return nil
 }
 
-func doQuit(data * ActionData) (err error) {  
-    data.Client.Printf("Byebye!\n")
-    data.Client.Disconnect()
-    return nil
+func doQuit(data *ActionData) (err error) {
+	data.Client.Printf("Byebye!\n")
+	data.Client.Disconnect()
+	return nil
 }
 
-func doEnableLog(data * ActionData) (err error) {  
-    // strings. string(data.Rest)
-    return nil
+func doEnableLog(data *ActionData) (err error) {
+	// strings. string(data.Rest)
+	return nil
 }
 
-
-func ParseCommand(command []byte, data * ActionData) (err error) {
-    /* strip any leading blanks  */
-    trimmed    := bytes.TrimLeft(command, " \t")
-    re         := regexp.MustCompile("[^ \t,]+")
-    parts      := re.FindAll(command, -1)
-    
-    bytes.SplitN(trimmed, []byte(" \t,"), 2)  
-    
-    if len(parts) < 1 {
-        data.Command = nil
-        return errors.New("Come again?")
-    }
-    data.Command = parts[0]
-    if len(parts) > 1 { 
-        data.Rest    = parts[1]
-        data.Argv    = parts
-    } else {
-        data.Rest    = nil
-        data.Argv    = nil
-    }
-        
-    return nil
-} 
+func ParseCommand(command []byte, data *ActionData) (err error) {
+	/* strip any leading blanks  */
+	trimmed := bytes.TrimLeft(command, " \t")
+	re := regexp.MustCompile("[^ \t,]+")
+	parts := re.FindAll(command, -1)
+
+	bytes.SplitN(trimmed, []byte(" \t,"), 2)
+
+	if len(parts) < 1 {
+		data.Command = nil
+		return errors.New("Come again?")
+	}
+	data.Command = parts[0]
+	if len(parts) > 1 {
+		data.Rest = parts[1]
+		data.Argv = parts
+	} else {
+		data.Rest = nil
+		data.Argv = nil
+	}
+
+	return nil
+}
 
 func init() {
-    ActionMap = make(map[string] Action)
-    AddAction("/shutdown"   , world.PRIVILEGE_LORD, doShutdown)
-    AddAction("/restart"    , world.PRIVILEGE_LORD, doRestart)
-    AddAction("/quit"       , world.PRIVILEGE_ZERO, doQuit)
+	ActionMap = make(map[string]Action)
+	AddAction("/shutdown", world.PRIVILEGE_LORD, doShutdown)
+	AddAction("/restart", world.PRIVILEGE_LORD, doRestart)
+	AddAction("/quit", world.PRIVILEGE_ZERO, doQuit)
 }
 
-func (client * Client) ProcessCommand(command []byte) {
-    ad := &ActionData{client, client.GetServer(), 
-        client.GetWorld(), client.GetAccount(), nil, nil, nil, nil }
-    _ = ad
-    err := ParseCommand(command, ad);
-    if err != nil {
-        client.Printf("%s", err)
-        return
-    }
-    
-    action, ok := ActionMap[string(ad.Command)]
-    ad.Action = &action
-    
-    if ad.Action == nil || (!ok) {
-        client.Printf("Unknown command %s.", ad.Command)
-        return
-    }
-    // Check if sufficient rights to perform the action
-    if (ad.Action.Privilege > client.GetAccount().Privilege) {
-        client.Printf("You lack the privilege to %s (%d vs %d).", 
-        ad.Command, ad.Action.Privilege, client.GetAccount().Privilege)
-        return
-    }
-    
-    // Finally run action
-    ad.Action.Handler(ad)
-} 
-
+func (client *Client) ProcessCommand(command []byte) {
+	ad := &ActionData{client, client.GetServer(),
+		client.GetWorld(), client.GetAccount(), nil, nil, nil, nil}
+	_ = ad
+	err := ParseCommand(command, ad)
+	if err != nil {
+		client.Printf("%s", err)
+		return
+	}
+
+	action, ok := ActionMap[string(ad.Command)]
+	ad.Action = &action
+
+	if ad.Action == nil || (!ok) {
+		client.Printf("Unknown command %s.", ad.Command)
+		return
+	}
+	// Check if sufficient rights to perform the action
+	if ad.Action.Privilege > client.GetAccount().Privilege {
+		client.Printf("You lack the privilege to %s (%d vs %d).",
+			ad.Command, ad.Action.Privilege, client.GetAccount().Privilege)
+		return
+	}
+
+	// Finally run action
+	ad.Action.Handler(ad)
+}

+ 5 - 5
server/ask.go

@@ -2,12 +2,12 @@ package server
 
 /* This file contains dialog helpers for the client. */
 
-// import "github.com/beoran/woe/monolog"
-import t "github.com/beoran/woe/telnet"
-import "github.com/beoran/woe/telnet"
-import "github.com/beoran/woe/world"
+// import "gitlab.com/beoran/woe/monolog"
+import t "gitlab.com/beoran/woe/telnet"
+import "gitlab.com/beoran/woe/telnet"
+import "gitlab.com/beoran/woe/world"
 
-// import "github.com/beoran/woe/monolog"
+// import "gitlab.com/beoran/woe/monolog"
 import "bytes"
 import "strings"
 import "regexp"

+ 3 - 3
server/client.go

@@ -6,9 +6,9 @@ import (
 	"time"
 	// "errors"
 	// "io"
-	"github.com/beoran/woe/monolog"
-	"github.com/beoran/woe/telnet"
-	"github.com/beoran/woe/world"
+	"gitlab.com/beoran/woe/monolog"
+	"gitlab.com/beoran/woe/telnet"
+	"gitlab.com/beoran/woe/world"
 )
 
 /* Specific properties of a client. */

+ 2 - 2
server/dialog.go

@@ -3,8 +3,8 @@ package server
 
 /* This file contains dialogs for the client. The dialog helpers are in ask.go. */
 
-import "github.com/beoran/woe/monolog"
-import "github.com/beoran/woe/world"
+import "gitlab.com/beoran/woe/monolog"
+import "gitlab.com/beoran/woe/world"
 
 const NEW_CHARACTER_PRICE = 4
 

+ 2 - 2
server/server.go

@@ -11,8 +11,8 @@ import (
 	"runtime"
 	"time"
 
-	"github.com/beoran/woe/monolog"
-	"github.com/beoran/woe/world"
+	"gitlab.com/beoran/woe/monolog"
+	"gitlab.com/beoran/woe/world"
 )
 
 var MSSP map[string]string

+ 3 - 3
server/setuptelnet.go

@@ -1,8 +1,8 @@
 package server
 
-import "github.com/beoran/woe/monolog"
-import t "github.com/beoran/woe/telnet"
-import "github.com/beoran/woe/telnet"
+import "gitlab.com/beoran/woe/monolog"
+import t "gitlab.com/beoran/woe/telnet"
+import "gitlab.com/beoran/woe/telnet"
 import "strings"
 import "strconv"
 

+ 309 - 328
sitef/sitef.go

@@ -9,15 +9,14 @@ import "bufio"
 import "strconv"
 import "reflect"
 import "errors"
-import "github.com/beoran/woe/monolog"
-
+import "gitlab.com/beoran/woe/monolog"
 
 // Sitef format for serialization
 // Sitef is a simple text format for serializing data to
-// It's intent is to be human readable and easy to 
+// It's intent is to be human readable and easy to
 // use for multi line text.
-// It is quite similar to recfiles, though not compatible because 
-// in sitef files the first character on the line determines the meaning, 
+// It is quite similar to recfiles, though not compatible because
+// in sitef files the first character on the line determines the meaning,
 // and there is no backslash escaping.
 //
 // Sitef is a line based syntax where the first character on the line
@@ -25,409 +24,392 @@ import "github.com/beoran/woe/monolog"
 // Several lines together form a record.
 // A line that starts with # is a comment. There may be no whitespace
 // in front of the comment.
-// A newline character by itself (that is, an empty line), 
+// A newline character by itself (that is, an empty line),
 // or a - ends a record.
-// A plus character, an escape on the previous line or a tab or 
+// A plus character, an escape on the previous line or a tab or
 // a space continues a value.
 // A Continues value gets a newline inserted only when a space or tab was used.
 // + supresses the newline.
 // Anything else signifies the beginning of the next key.
-// % is allowed for special keys for recfile compatibility.  
+// % is allowed for special keys for recfile compatibility.
 // However % directives are not implemented.
-// Keys may not be nested, however, you could use spaces or dots, 
-// or array indexes to emulate nexted keys. 
+// Keys may not be nested, however, you could use spaces or dots,
+// or array indexes to emulate nexted keys.
 // A # at the start optionally after whitespace is a comment
-// 
+//
 
-type Record struct { 
-        dict map[string]string
-        order []string
+type Record struct {
+	dict  map[string]string
+	order []string
 }
 
-func NewRecord() (* Record) {
-    rec := &Record{}
-    rec.dict  = make(map[string]string)
-    rec.order = make([]string, 0)
-    return rec
+func NewRecord() *Record {
+	rec := &Record{}
+	rec.dict = make(map[string]string)
+	rec.order = make([]string, 0)
+	return rec
 }
 
-func (me * Record) Put(key string, val string) {
-    me.order = append(me.order, key)
-    me.dict[key] = val
+func (me *Record) Put(key string, val string) {
+	me.order = append(me.order, key)
+	me.dict[key] = val
 }
 
-func (me * Record) Putf(key string, format string, values ...interface{}) {
-    me.Put(key, fmt.Sprintf(format, values...))
-    monolog.Debug("After putf: %s %v", key, me.order)
+func (me *Record) Putf(key string, format string, values ...interface{}) {
+	me.Put(key, fmt.Sprintf(format, values...))
+	monolog.Debug("After putf: %s %v", key, me.order)
 }
 
-func (me * Record) PutArrayIndex(key string, index int, value string) {
-    realkey := fmt.Sprintf("%s[%d]", key, index)
-    me.Put(realkey, value)
-} 
-
-func (me * Record) PutArray(key string, values []string) {
-    for i, value := range values {
-        me.PutArrayIndex(key, i, value)
-    }
-} 
+func (me *Record) PutArrayIndex(key string, index int, value string) {
+	realkey := fmt.Sprintf("%s[%d]", key, index)
+	me.Put(realkey, value)
+}
 
-func (me * Record) PutInt(key string, val int) {
-    me.Putf(key, "%d", val)
+func (me *Record) PutArray(key string, values []string) {
+	for i, value := range values {
+		me.PutArrayIndex(key, i, value)
+	}
 }
 
+func (me *Record) PutInt(key string, val int) {
+	me.Putf(key, "%d", val)
+}
 
-func (me * Record) PutInt64(key string, val int64) {
-    me.Putf(key, "%d", val)
+func (me *Record) PutInt64(key string, val int64) {
+	me.Putf(key, "%d", val)
 }
 
-func (me * Record) PutFloat64(key string, val float64) {
-    me.Putf(key, "%lf", val)
+func (me *Record) PutFloat64(key string, val float64) {
+	me.Putf(key, "%lf", val)
 }
 
 func (me Record) MayGet(key string) (result string, ok bool) {
-    result, ok = me.dict[key]
-    return result, ok
+	result, ok = me.dict[key]
+	return result, ok
 }
 
-
 func (me Record) Get(key string) (result string) {
-    result= me.dict[key]
-    return result
+	result = me.dict[key]
+	return result
 }
 
-func (me * Record) GetArrayIndex(key string, i int) (result string) {
-    realkey := fmt.Sprintf("%s[%d]", key, i)
-    return me.Get(realkey)
+func (me *Record) GetArrayIndex(key string, i int) (result string) {
+	realkey := fmt.Sprintf("%s[%d]", key, i)
+	return me.Get(realkey)
 }
 
-
-func (me Record) Getf(key string, format string, 
-    values ...interface{}) (amount int, ok bool) {
-    val := me.Get(key)
-    count, err := fmt.Sscanf(val, format, values...)
-    if err != nil {
-        return 0, false
-    }
-    return count, true
+func (me Record) Getf(key string, format string,
+	values ...interface{}) (amount int, ok bool) {
+	val := me.Get(key)
+	count, err := fmt.Sscanf(val, format, values...)
+	if err != nil {
+		return 0, false
+	}
+	return count, true
 }
 
 func (me Record) GetInt(key string) (val int, err error) {
-    i, err := strconv.ParseInt(me.Get(key), 0, 0)
-    return int(i), err
+	i, err := strconv.ParseInt(me.Get(key), 0, 0)
+	return int(i), err
 }
 
 func (me Record) GetIntDefault(key string, def int) (val int) {
-    i, err := strconv.ParseInt(me.Get(key), 0, 0)
-    if err != nil {
-        return def;
-    }
-    return int(i);
+	i, err := strconv.ParseInt(me.Get(key), 0, 0)
+	if err != nil {
+		return def
+	}
+	return int(i)
 }
 
-
 func (me Record) GetFloat(key string) (val float64, error error) {
-    return strconv.ParseFloat(me.Get(key), 64)
+	return strconv.ParseFloat(me.Get(key), 64)
 }
 
-func (me * Record) convSimple(typ reflect.Type, val reflect.Value) (res string, err error) {
-    switch val.Kind() {
-    case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-    return strconv.FormatInt(val.Int(), 10), nil
-        
-    case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
-    return strconv.FormatUint(val.Uint(), 10), nil
-    
-    case reflect.Float32, reflect.Float64:
-    return strconv.FormatFloat(val.Float(), 'g', -1, val.Type().Bits()), nil
-    case reflect.String:
-    return val.String(), nil
-    case reflect.Bool:
-    return strconv.FormatBool(val.Bool()), nil
-    default: 
-    return "", errors.New("Unsupported type")
-    }
+func (me *Record) convSimple(typ reflect.Type, val reflect.Value) (res string, err error) {
+	switch val.Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return strconv.FormatInt(val.Int(), 10), nil
+
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		return strconv.FormatUint(val.Uint(), 10), nil
+
+	case reflect.Float32, reflect.Float64:
+		return strconv.FormatFloat(val.Float(), 'g', -1, val.Type().Bits()), nil
+	case reflect.String:
+		return val.String(), nil
+	case reflect.Bool:
+		return strconv.FormatBool(val.Bool()), nil
+	default:
+		return "", errors.New("Unsupported type")
+	}
 }
 
+func (me *Record) PutValue(key string, value reflect.Value) {
+
+	monolog.Debug("PutValue: %s %v", key, value)
+
+	stringer, ok := value.Interface().(fmt.Stringer)
+	if ok {
+		me.Put(key, stringer.String())
+		return
+	}
+
+	switch value.Kind() {
+	case reflect.Int, reflect.Int32, reflect.Int64:
+		me.Putf(key, "%d", value.Int())
+	case reflect.Uint, reflect.Uint32, reflect.Uint64:
+		me.Putf(key, "%d", value.Uint())
+	case reflect.Float32, reflect.Float64:
+		me.Putf(key, "%f", value.Float())
+	case reflect.String:
+		me.Putf(key, "%s", value.String())
+	case reflect.Struct:
+		me.PutStruct(key+".", value.Interface())
+	default:
+		me.Put(key, "???")
+	}
+
+	monolog.Debug("Put: key %s value %s, result %v", key, value, me)
 
-func (me * Record) PutValue(key string, value reflect.Value) {
-
-    monolog.Debug("PutValue: %s %v", key, value)
-
-    stringer, ok := value.Interface().(fmt.Stringer)
-    if ok {
-        me.Put(key, stringer.String())
-        return
-    }
-    
-    switch (value.Kind()) {
-        case reflect.Int, reflect.Int32, reflect.Int64:
-            me.Putf(key, "%d", value.Int())
-        case reflect.Uint, reflect.Uint32, reflect.Uint64:
-            me.Putf(key, "%d", value.Uint())
-        case reflect.Float32, reflect.Float64:
-            me.Putf(key, "%f", value.Float())
-        case reflect.String:
-            me.Putf(key, "%s", value.String())
-        case reflect.Struct:
-            me.PutStruct(key + ".", value.Interface());
-        default:
-            me.Put(key, "???")
-    }
-    
-    monolog.Debug("Put: key %s value %s, result %v", key, value, me) 
-    
 }
 
-func (me * Record) PutStruct(prefix string, structure interface {}) {
-    st := reflect.TypeOf(structure)
-    vt := reflect.ValueOf(structure)
-    
-    for i:= 0 ; i < st.NumField() ; i++ {
-        field := st.Field(i)
-        key := strings.ToLower(field.Name)
-        value :=  vt.Field(i)
-        me.PutValue(prefix + key, value)
-    }
-}
+func (me *Record) PutStruct(prefix string, structure interface{}) {
+	st := reflect.TypeOf(structure)
+	vt := reflect.ValueOf(structure)
 
+	for i := 0; i < st.NumField(); i++ {
+		field := st.Field(i)
+		key := strings.ToLower(field.Name)
+		value := vt.Field(i)
+		me.PutValue(prefix+key, value)
+	}
+}
 
-func (me Record) GetValue(key string, value reflect.Value) (err error){
-    /*stringer, ok := value.Interface().(fmt.Stringer)
-    if ok {
-        me.Gut(key, stringer.String())
-        return
-    }*/
-    monolog.Debug("GetValue: %s %v", key, value)
-    
-    switch (value.Kind()) {
-        case reflect.Int, reflect.Int32, reflect.Int64:
-            value.SetInt(int64(me.GetIntDefault(key, 0)))
-        case reflect.Uint, reflect.Uint32, reflect.Uint64:
-            value.SetUint(uint64(me.GetIntDefault(key, 0)))
-        case reflect.Float32, reflect.Float64:
-            f, err := me.GetFloat(key)
-            if (err != nil) { 
-                return err
-            }
-            value.SetFloat(f)
-        case reflect.String:
-            s, ok := me.MayGet(key)
-            if (!ok) {
-                return fmt.Errorf("Could not get string for key %s", key)
-            }
-            value.SetString(s)
-        case reflect.Struct:
-            me.GetStruct(key + ".", value.Addr().Interface());
-        default:
-            monolog.Warning("Don't know what to do with %v", value)
-    }
-    return nil
+func (me Record) GetValue(key string, value reflect.Value) (err error) {
+	/*stringer, ok := value.Interface().(fmt.Stringer)
+	  if ok {
+	      me.Gut(key, stringer.String())
+	      return
+	  }*/
+	monolog.Debug("GetValue: %s %v", key, value)
+
+	switch value.Kind() {
+	case reflect.Int, reflect.Int32, reflect.Int64:
+		value.SetInt(int64(me.GetIntDefault(key, 0)))
+	case reflect.Uint, reflect.Uint32, reflect.Uint64:
+		value.SetUint(uint64(me.GetIntDefault(key, 0)))
+	case reflect.Float32, reflect.Float64:
+		f, err := me.GetFloat(key)
+		if err != nil {
+			return err
+		}
+		value.SetFloat(f)
+	case reflect.String:
+		s, ok := me.MayGet(key)
+		if !ok {
+			return fmt.Errorf("Could not get string for key %s", key)
+		}
+		value.SetString(s)
+	case reflect.Struct:
+		me.GetStruct(key+".", value.Addr().Interface())
+	default:
+		monolog.Warning("Don't know what to do with %v", value)
+	}
+	return nil
 }
 
+func (me Record) GetStruct(prefix string, structure interface{}) {
+	monolog.Info("GetStruct: structure %v, %v\n", structure,
+		reflect.TypeOf(structure))
 
-func (me Record) GetStruct(prefix string, structure interface {}) {
-    monolog.Info("GetStruct: structure %v, %v\n", structure, 
-        reflect.TypeOf(structure))
-    
-    st := reflect.TypeOf(structure).Elem()
-    vt := reflect.Indirect(reflect.ValueOf(structure))
-    monolog.Info("GetStruct: type %v value %v\n", st, vt)
-    
-    for i:= 0 ; i < st.NumField() ; i++ {
-        field := st.Field(i)
-        key := prefix + strings.ToLower(field.Name)
-        value :=  reflect.Indirect(vt).Field(i)
-        me.GetValue(key, value)
-    }
-}
+	st := reflect.TypeOf(structure).Elem()
+	vt := reflect.Indirect(reflect.ValueOf(structure))
+	monolog.Info("GetStruct: type %v value %v\n", st, vt)
 
+	for i := 0; i < st.NumField(); i++ {
+		field := st.Field(i)
+		key := prefix + strings.ToLower(field.Name)
+		value := reflect.Indirect(vt).Field(i)
+		me.GetValue(key, value)
+	}
+}
 
 type Error struct {
-    error   string
-    lineno  int
+	error  string
+	lineno int
 }
 
 func (me Error) Error() string {
-    return fmt.Sprintf("%d: %s", me.Lineno, me.error)
+	return fmt.Sprintf("%d: %s", me.Lineno, me.error)
 }
 
 func (me Error) Lineno() int {
-    return me.lineno
+	return me.lineno
 }
 
-
 type ParserState int
 
 const (
-    PARSER_STATE_INIT   ParserState = iota
-    PARSER_STATE_KEY
-    PARSER_STATE_VALUE
+	PARSER_STATE_INIT ParserState = iota
+	PARSER_STATE_KEY
+	PARSER_STATE_VALUE
 )
 
 type RecordList []*Record
 
-
 func ParseReader(read io.Reader) (RecordList, error) {
-    var records     RecordList
-    record      := NewRecord()
-    var err         Error
-    lineno      := 0
-    scanner     := bufio.NewScanner(read)
-    var key     bytes.Buffer
-    var value   bytes.Buffer
-    
-    
-    for scanner.Scan() {
-        lineno++
-        line := scanner.Text()
-        // End of record?
-        if (len(line) < 1) || line[0] == '-' {
-            // Append last record if needed. 
-            if len(key.String()) > 0 {
-                record.Put(key.String(), value.String())
-            }
-            // save the record and make a new one
-            records = append(records, record)
-            record  = NewRecord()
-        // comment?
-        } else if line[0] == '#' {
-            continue; 
-        // continue value?
-        } else if line[0] == '\t' || line[0] == ' '|| line[0] == '+' {
-            
-            /* Add a newline unless + is used */
-            if (line[0] != '+') {
-                value.WriteRune('\n')          
-            }
-            
-            // continue the value, skipping the first character
-            value.WriteString(line[1:])            
-        // new key
-        } else if strings.ContainsRune(line, ':') {
-            // save the previous key/value pair if needed
-            if len(key.String()) > 0 {
-                record.Put(key.String(), value.String())
-            }
-            
-            key.Reset()
-            value.Reset()
-
-            parts := strings.SplitN(line, ":", 2)
-                            
-            key.WriteString(parts[0])
-            if len(parts) > 1 {
-               value.WriteString(parts[1])   
-            }            
-        // Not a key. Be lenient and assume this is a continued value.
-        } else {
-            value.WriteString(line)   
-        }
-    }
-    
-    // Append last record if needed. 
-    if len(key.String()) > 0 {
-        record.Put(key.String(), value.String())
-    }
-    
-    if (len(record.order) > 0) {
-        records = append(records, record)
-    }
-
-    
-
-    if serr := scanner.Err(); serr != nil {
-       err.lineno = lineno
-       err.error  = serr.Error()
-       monolog.Error("Sitef parse error: %d %s", lineno, serr.Error) 
-       return records, err
-    }
-    
-    return records, nil
-    
+	var records RecordList
+	record := NewRecord()
+	var err Error
+	lineno := 0
+	scanner := bufio.NewScanner(read)
+	var key bytes.Buffer
+	var value bytes.Buffer
+
+	for scanner.Scan() {
+		lineno++
+		line := scanner.Text()
+		// End of record?
+		if (len(line) < 1) || line[0] == '-' {
+			// Append last record if needed.
+			if len(key.String()) > 0 {
+				record.Put(key.String(), value.String())
+			}
+			// save the record and make a new one
+			records = append(records, record)
+			record = NewRecord()
+			// comment?
+		} else if line[0] == '#' {
+			continue
+			// continue value?
+		} else if line[0] == '\t' || line[0] == ' ' || line[0] == '+' {
+
+			/* Add a newline unless + is used */
+			if line[0] != '+' {
+				value.WriteRune('\n')
+			}
+
+			// continue the value, skipping the first character
+			value.WriteString(line[1:])
+			// new key
+		} else if strings.ContainsRune(line, ':') {
+			// save the previous key/value pair if needed
+			if len(key.String()) > 0 {
+				record.Put(key.String(), value.String())
+			}
+
+			key.Reset()
+			value.Reset()
+
+			parts := strings.SplitN(line, ":", 2)
+
+			key.WriteString(parts[0])
+			if len(parts) > 1 {
+				value.WriteString(parts[1])
+			}
+			// Not a key. Be lenient and assume this is a continued value.
+		} else {
+			value.WriteString(line)
+		}
+	}
+
+	// Append last record if needed.
+	if len(key.String()) > 0 {
+		record.Put(key.String(), value.String())
+	}
+
+	if len(record.order) > 0 {
+		records = append(records, record)
+	}
+
+	if serr := scanner.Err(); serr != nil {
+		err.lineno = lineno
+		err.error = serr.Error()
+		monolog.Error("Sitef parse error: %d %s", lineno, serr.Error)
+		return records, err
+	}
+
+	return records, nil
+
 }
 
 func ParseFilename(filename string) (RecordList, error) {
-    file, err := os.Open(filename)
-    if err != nil {
-        return nil, err
-    }
-    defer file.Close()
-    return ParseReader(file)
+	file, err := os.Open(filename)
+	if err != nil {
+		return nil, err
+	}
+	defer file.Close()
+	return ParseReader(file)
 }
 
 func WriteField(writer io.Writer, key string, value string) {
-    monolog.Debug("WriteField %s:%s", key, value)
-    replacer := strings.NewReplacer("\n", "\n\t")    
-    writer.Write([]byte(key))
-    writer.Write([]byte{':'})    
-    writer.Write([]byte(replacer.Replace(value)))
-    writer.Write([]byte{'\n'})
+	monolog.Debug("WriteField %s:%s", key, value)
+	replacer := strings.NewReplacer("\n", "\n\t")
+	writer.Write([]byte(key))
+	writer.Write([]byte{':'})
+	writer.Write([]byte(replacer.Replace(value)))
+	writer.Write([]byte{'\n'})
 }
 
 func WriteRecord(writer io.Writer, record Record) {
-    monolog.Debug("WriteRecord %v", record)
-
-    for index := 0 ; index < len(record.order) ; index++ {
-        key := record.order[index];
-        value := record.dict[key];
-        WriteField(writer, key, value);
-    }
-    writer.Write([]byte{'-', '-', '-', '-', '\n'})
+	monolog.Debug("WriteRecord %v", record)
+
+	for index := 0; index < len(record.order); index++ {
+		key := record.order[index]
+		value := record.dict[key]
+		WriteField(writer, key, value)
+	}
+	writer.Write([]byte{'-', '-', '-', '-', '\n'})
 }
 
 func WriteRecordList(writer io.Writer, records RecordList) {
-    for _, record := range records {
-        WriteRecord(writer, *record);
-    }
+	for _, record := range records {
+		WriteRecord(writer, *record)
+	}
 }
 
-
-func SaveRecord(filename string, record Record) (error) {
-    file, err := os.Create(filename)
-    if err != nil {
-        monolog.WriteError(err)
-        return err
-    }
-    defer file.Close()
-    WriteRecord(file, record)
-    return nil
+func SaveRecord(filename string, record Record) error {
+	file, err := os.Create(filename)
+	if err != nil {
+		monolog.WriteError(err)
+		return err
+	}
+	defer file.Close()
+	WriteRecord(file, record)
+	return nil
 }
 
-
-
-func SaveRecordList(filename string, records RecordList) (error) {
-    file, err := os.Create(filename)
-    if err != nil {
-        return err
-    }
-    defer file.Close()
-    WriteRecordList(file, records)
-    return nil
+func SaveRecordList(filename string, records RecordList) error {
+	file, err := os.Create(filename)
+	if err != nil {
+		return err
+	}
+	defer file.Close()
+	WriteRecordList(file, records)
+	return nil
 }
 
-
 /*
 func ParseFile(file)
     lineno   = 0
     results  = []
     errors   = []
-    
+
     record   = {}
     key      = nil
     value    = nil
     until file.eof?
-      lineno     += 1 
+      lineno     += 1
       line        = file.gets(256)
       break if line.nil?
-      next if line.empty? 
+      next if line.empty?
       // new record
-      if line[0,2] == '--' 
+      if line[0,2] == '--'
         // Store last key used if any.
-        if key          
+        if key
           record[key] = value.chomp
           key = nil
-        end  
+        end
         results << record
         record = {}
       elsif line[0] == '//'
@@ -438,11 +420,11 @@ func ParseFile(file)
       record[key] = value.chomp
       key = value = nil
       elsif line[0, 2] == '..'
-      // end of multiline value 
+      // end of multiline value
       record[key] = value.chomp
       key = value = nil
       elsif (line[0] == '.') && key.nil?
-      // Multiline key/value starts here (but is ignored 
+      // Multiline key/value starts here (but is ignored
       // until .. is encountered)
       key   = line[1, line.size]
       key.chomp!
@@ -458,54 +440,54 @@ func ParseFile(file)
       else
           // Not in a key, sntax error.
           errors << "//{lineno}: Don't know how to process line"
-      end      
+      end
     end
     // Store last key used if any.
-    if key      
+    if key
       record[key] = value.chomp
-    end  
-    // store last record 
+    end
+    // store last record
     results << record unless record.empty?
     return results, errors
-  end  
-  
+  end
+
   func load_filename(filename)
     results, errors = nil, nil, nil;
     file = File.open(filename, 'rt') rescue nil
     return nil, ["Could not open //{filename}"] unless file
-    begin 
+    begin
       results, errors = parse_file(file)
     ensure
       file.close
     end
     return results, errors
   end
-  
+
   // Loads a Sitef fileas obejcts. Uses the ruby_klass atribute to load the object
   // If that is missing, uses defklass
   func load_objects(filename, defklass=nil)
     results, errors = load_filename(filename)
     p filename, results, errors
     unless errors.nil? || errors.empty?
-      return nil, errors 
+      return nil, errors
     end
-    
-    objres = [] 
+
+    objres = []
     results.each do | result |
       klassname = result['ruby_class'] || defklass
       return nil unless klassname
-      klass = klassname.split('::').inject(Kernel) { |klass, name| klass.const_get(name) rescue nil } 
+      klass = klassname.split('::').inject(Kernel) { |klass, name| klass.const_get(name) rescue nil }
       return nil unless klass
       if klass.respond_to? :from_sitef
         objres << klass.from_sitef(result)
       else
         objres << klass.new(result)
-      end      
+      end
     end
-    return objres, errors    
+    return objres, errors
   end
-  
-  
+
+
   // Saves a single field to a file in Sitef format.
   func save_field(file, key, value)
     if value.is_a? String
@@ -524,7 +506,7 @@ func ParseFile(file)
       file.printf("://{key}://{sval}\n")
     end
   end
-  
+
   func save_object(file, object, *fields)
     save_field(file, :ruby_class, object.class.to_s)
     fields.each do | field |
@@ -532,7 +514,7 @@ func ParseFile(file)
       save_field(file, field, value)
     end
   end
-  
+
   func save_record(file, record, *fields)
     record.each do | key, value |
       next if fields && !fields.empty? && !fields.member?(key)
@@ -544,26 +526,25 @@ func ParseFile(file)
     records.each do | record |
       if record.is_a? Hash
         save_record(file, record, *fields)
-      else 
+      else
         save_object(file, record, *fields)
       end
       file.puts("--\n")
     end
   end
-  
+
   func save_filename(filename, records, *fields)
     results , errors = nil, nil
     file = File.open(filename, 'wt')
     return false, ["Could not open //{filename}"] unless file
-    begin 
+    begin
       save_file(file, records, *fields)
     ensure
       file.close
     end
     return true, []
   end
-  
+
 end
 
 */
-

+ 1 - 1
telnet/telnet.go

@@ -5,7 +5,7 @@ import "io"
 import "strings"
 import "fmt"
 import "compress/zlib"
-import "github.com/beoran/woe/monolog"
+import "gitlab.com/beoran/woe/monolog"
 
 // This Telnet module implements a subset of the Telnet protocol.
 

+ 3 - 3
woe.go

@@ -1,9 +1,9 @@
 package main
 
 // import "fmt"
-import "github.com/beoran/woe/server"
-import "github.com/beoran/woe/monolog"
-import "github.com/beoran/woe/raku"
+import "gitlab.com/beoran/woe/server"
+import "gitlab.com/beoran/woe/monolog"
+import "gitlab.com/beoran/woe/raku"
 import "os"
 import "os/exec"
 import "flag"

+ 135 - 149
world/account.go

@@ -1,195 +1,181 @@
 package world
 
 import "path/filepath"
-import "github.com/beoran/woe/sitef"
-import "github.com/beoran/woe/monolog"
+import "gitlab.com/beoran/woe/sitef"
+import "gitlab.com/beoran/woe/monolog"
 import "fmt"
 import "errors"
 
 type Privilege int
 
 const (
-    PRIVILEGE_ZERO        = Privilege(iota * 100)
-    PRIVILEGE_NORMAL
-    PRIVILEGE_MASTER
-    PRIVILEGE_LORD
-    PRIVILEGE_IMPLEMENTOR
+	PRIVILEGE_ZERO = Privilege(iota * 100)
+	PRIVILEGE_NORMAL
+	PRIVILEGE_MASTER
+	PRIVILEGE_LORD
+	PRIVILEGE_IMPLEMENTOR
 )
 
-
 type Named struct {
-    Name string
+	Name string
 }
 
-
 type Account struct {
-    Name              string
-    Hash              string
-    Algo              string
-    Email             string
-    Points            int
-    Privilege         Privilege
-    CharacterNames  []string
-    characters      [] * Character
+	Name           string
+	Hash           string
+	Algo           string
+	Email          string
+	Points         int
+	Privilege      Privilege
+	CharacterNames []string
+	characters     []*Character
 }
 
 func SavePathForXML(dirname string, typename string, name string) string {
-    return filepath.Join(dirname, typename, name + ".xml")
-} 
+	return filepath.Join(dirname, typename, name+".xml")
+}
 
 func SavePathFor(dirname string, typename string, name string) string {
-    return filepath.Join(dirname, typename, name + ".sitef")
+	return filepath.Join(dirname, typename, name+".sitef")
 }
 
-
-
-func NewAccount(name string, pass string, email string, points int) (*Account) {    
-    hash := WoeCryptPassword(pass, "")
-    return &Account{name, hash, "woe", email, points, PRIVILEGE_NORMAL, nil, nil}    
-    // return &Account{name, pass, "plain", email, points, PRIVILEGE_NORMAL, nil, nil}
+func NewAccount(name string, pass string, email string, points int) *Account {
+	hash := WoeCryptPassword(pass, "")
+	return &Account{name, hash, "woe", email, points, PRIVILEGE_NORMAL, nil, nil}
+	// return &Account{name, pass, "plain", email, points, PRIVILEGE_NORMAL, nil, nil}
 }
 
 // Export an account to a "universal" map
-func (me * Account) ToUniMap() map[string] interface{} {
-    res := make(map[string] interface{})
-    return res
+func (me *Account) ToUniMap() map[string]interface{} {
+	res := make(map[string]interface{})
+	return res
 }
 
 // Password Challenge for an account.
-func (me * Account) Challenge(challenge string) bool {
-    if me.Algo == "plain" {
-        return me.Hash == challenge
-    } else if me.Algo == "woe" {
-        return WoeCryptChallenge(me.Hash, challenge)
-    }
-    // implement beter passwd encryption later
-    return false
+func (me *Account) Challenge(challenge string) bool {
+	if me.Algo == "plain" {
+		return me.Hash == challenge
+	} else if me.Algo == "woe" {
+		return WoeCryptChallenge(me.Hash, challenge)
+	}
+	// implement beter passwd encryption later
+	return false
 }
 
-
 // Add a character to an account.
-func (me * Account) AddCharacter(chara * Character) {
-    me.characters = append(me.characters, chara)
+func (me *Account) AddCharacter(chara *Character) {
+	me.characters = append(me.characters, chara)
 }
 
-
 // Save an account as a sitef file.
-func (me * Account) Save(dirname string) (err error) {
-    path := SavePathFor(dirname, "account", me.Name)
-    
-    rec                := sitef.NewRecord()
-    rec.Put("name",         me.Name)
-    rec.Put("hash",         me.Hash)
-    rec.Put("algo",         me.Algo)
-    rec.Put("email",        me.Email)
-    rec.PutInt("points",    me.Points)
-    rec.PutInt("privilege", int(me.Privilege))
-    rec.PutInt("characters",len(me.characters))
-    for i, chara   := range me.characters {
-        key        := fmt.Sprintf("characters[%d]", i)
-        rec.Put(key, chara.ID)
-        
-    }
-    monolog.Debug("Saving Acccount record: %s %v", path, rec)
-    return sitef.SaveRecord(path, *rec)
+func (me *Account) Save(dirname string) (err error) {
+	path := SavePathFor(dirname, "account", me.Name)
+
+	rec := sitef.NewRecord()
+	rec.Put("name", me.Name)
+	rec.Put("hash", me.Hash)
+	rec.Put("algo", me.Algo)
+	rec.Put("email", me.Email)
+	rec.PutInt("points", me.Points)
+	rec.PutInt("privilege", int(me.Privilege))
+	rec.PutInt("characters", len(me.characters))
+	for i, chara := range me.characters {
+		key := fmt.Sprintf("characters[%d]", i)
+		rec.Put(key, chara.ID)
+
+	}
+	monolog.Debug("Saving Acccount record: %s %v", path, rec)
+	return sitef.SaveRecord(path, *rec)
 }
 
 // Load an account from a sitef file.
 func LoadAccount(dirname string, name string) (account *Account, err error) {
-    
-    path := SavePathFor(dirname, "account", name)
-    
-    records, err := sitef.ParseFilename(path)
-    if err != nil {
-        return nil, err
-    }
-    
-    if len(records) < 1 {
-        return nil, errors.New("No record found!")
-    }
-    
-    record := records[0]
-    monolog.Info("Loading Account record: %s %v", path, record)
-    
-    account = new(Account)
-    account.Name            = record.Get("name")
-    account.Hash            = record.Get("hash")
-    account.Algo            = record.Get("algo")
-    account.Email           = record.Get("email")
-    account.Points          = record.GetIntDefault("points", 0)
-    account.Privilege       = Privilege(record.GetIntDefault("privilege", 
-                                int(PRIVILEGE_NORMAL)))
-    
-    nchars                 := record.GetIntDefault("characters", 0)
-    account.characters      = make([] * Character, 0, nchars)
-    monolog.Info("Try to load %d characters:\n", nchars)
-    for index := 0 ; index < nchars ; index ++ {
-
-        chid := record.GetArrayIndex("characters", index)
-        monolog.Info("Loading character: %d %s\n", index, chid)
-        
-        ch, err := account.LoadCharacter(dirname, chid);
-        if err != nil {
-            monolog.Error("Could not load character %s: %s", chid, err.Error())
-            // return nil, err
-        } else {
-            account.characters = append(account.characters, ch)
-        } 
-    }
-    
-    
-    /* Todo: load characters here... */    
-    monolog.Info("Loaded Account: %s %v", path, account)
-    return account, nil
+
+	path := SavePathFor(dirname, "account", name)
+
+	records, err := sitef.ParseFilename(path)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(records) < 1 {
+		return nil, errors.New("No record found!")
+	}
+
+	record := records[0]
+	monolog.Info("Loading Account record: %s %v", path, record)
+
+	account = new(Account)
+	account.Name = record.Get("name")
+	account.Hash = record.Get("hash")
+	account.Algo = record.Get("algo")
+	account.Email = record.Get("email")
+	account.Points = record.GetIntDefault("points", 0)
+	account.Privilege = Privilege(record.GetIntDefault("privilege",
+		int(PRIVILEGE_NORMAL)))
+
+	nchars := record.GetIntDefault("characters", 0)
+	account.characters = make([]*Character, 0, nchars)
+	monolog.Info("Try to load %d characters:\n", nchars)
+	for index := 0; index < nchars; index++ {
+
+		chid := record.GetArrayIndex("characters", index)
+		monolog.Info("Loading character: %d %s\n", index, chid)
+
+		ch, err := account.LoadCharacter(dirname, chid)
+		if err != nil {
+			monolog.Error("Could not load character %s: %s", chid, err.Error())
+			// return nil, err
+		} else {
+			account.characters = append(account.characters, ch)
+		}
+	}
+
+	/* Todo: load characters here... */
+	monolog.Info("Loaded Account: %s %v", path, account)
+	return account, nil
 }
 
- 
-func (me * Account) NumCharacters() int {
-    return len(me.characters)
-} 
+func (me *Account) NumCharacters() int {
+	return len(me.characters)
+}
 
-func (me * Account) GetCharacter(index int) (* Character) {
-    return me.characters[index]
-} 
+func (me *Account) GetCharacter(index int) *Character {
+	return me.characters[index]
+}
 
-func (me * Account) FindCharacter(character * Character) (index int) {
-    for k, c := range me.characters {
-        if c == character  {
-            return k
-        }
-    }
-    return -1;
-} 
+func (me *Account) FindCharacter(character *Character) (index int) {
+	for k, c := range me.characters {
+		if c == character {
+			return k
+		}
+	}
+	return -1
+}
 
 // Delete a character from this account.
-func (me * Account) DeleteCharacter(dirname string, character * Character) bool {
-    
-    if i:= me.FindCharacter(character) ; i < 0 {
-        monolog.Warning("Could not find character: %v %d", character, i)
-        return false;  
-    } else {
-        copy(me.characters[i:], me.characters[i+1:])
-        newlen := len(me.characters) - 1 
-        me.characters[newlen] = nil
-        me.characters = me.characters[:newlen]
-    }
-    /// Save self so the deletion is correctly recorded.
-    me.Save(dirname)
-    
-    return character.Delete(dirname)
-} 
-
-
-func (me * Account) CharacterEntitylikeSlice() EntitylikeSlice {
-    els := make(EntitylikeSlice, 0, 16)
-    for i:= 0 ; i < me.NumCharacters(); i++ {
-        chara := me.GetCharacter(i)
-        els = append(els, chara)
-    }
-    return els
+func (me *Account) DeleteCharacter(dirname string, character *Character) bool {
+
+	if i := me.FindCharacter(character); i < 0 {
+		monolog.Warning("Could not find character: %v %d", character, i)
+		return false
+	} else {
+		copy(me.characters[i:], me.characters[i+1:])
+		newlen := len(me.characters) - 1
+		me.characters[newlen] = nil
+		me.characters = me.characters[:newlen]
+	}
+	/// Save self so the deletion is correctly recorded.
+	me.Save(dirname)
+
+	return character.Delete(dirname)
 }
 
-
-
-
-
+func (me *Account) CharacterEntitylikeSlice() EntitylikeSlice {
+	els := make(EntitylikeSlice, 0, 16)
+	for i := 0; i < me.NumCharacters(); i++ {
+		chara := me.GetCharacter(i)
+		els = append(els, chara)
+	}
+	return els
+}

+ 2 - 2
world/being.go

@@ -5,8 +5,8 @@ import (
 	"math"
 	"strings"
 
-	"github.com/beoran/woe/monolog"
-	"github.com/beoran/woe/sitef"
+	"gitlab.com/beoran/woe/monolog"
+	"gitlab.com/beoran/woe/sitef"
 )
 
 /* Aptitudes of a being, species or profession */

+ 89 - 94
world/character.go

@@ -2,133 +2,128 @@ package world
 
 import "fmt"
 import "os"
-// import "strconv"
-import "github.com/beoran/woe/monolog"
-import "github.com/beoran/woe/sitef"
+
+// imporgitlab.com"
+import "gitlab.com/beoran/woe/monolog"
+import "gitlab.com/beoran/woe/sitef"
 
 /* Characters may exist "outside" of any world, because, at login of a client,
  * the Character must be loaded or created before it enters a World. */
 
 type Character struct {
-    Being       
-    Account * Account
+	Being
+	Account *Account
 }
 
-
-func NewCharacterFromBeing(being Being, account * Account) (*Character) {
-    return &Character{being, account}
+func NewCharacterFromBeing(being Being, account *Account) *Character {
+	return &Character{being, account}
 }
 
-func (me * Character) Init(account * Account, name string, 
-              kin Entitylike, gender Entitylike, job Entitylike) (* Character) {
-    me.Account = account
-    me.Being.Init("character", name, account.Privilege, kin, gender, job)
-    return me
+func (me *Character) Init(account *Account, name string,
+	kin Entitylike, gender Entitylike, job Entitylike) *Character {
+	me.Account = account
+	me.Being.Init("character", name, account.Privilege, kin, gender, job)
+	return me
 }
 
-func NewCharacter(account * Account, name string, 
-              kin Entitylike, gender Entitylike, job Entitylike) (* Character) {
-    me := &Character{};
-    return me.Init(account, name, kin, gender, job)
+func NewCharacter(account *Account, name string,
+	kin Entitylike, gender Entitylike, job Entitylike) *Character {
+	me := &Character{}
+	return me.Init(account, name, kin, gender, job)
 }
 
 // Save a character into a a sitef record.
-func (me * Character) SaveSirec(rec * sitef.Record) (err error) {
-    rec.Put("accountname", me.Account.Name)
-    me.Being.SaveSitef(rec)
-    return nil
+func (me *Character) SaveSirec(rec *sitef.Record) (err error) {
+	rec.Put("accountname", me.Account.Name)
+	me.Being.SaveSitef(rec)
+	return nil
 }
 
 // Load a character from a sitef record.
-func (me * Character) LoadSirec(rec sitef.Record) (err error) {
-    aname := rec.Get("accountname")
-    account, err := DefaultWorld.LoadAccount(aname)
-    if err != nil {
-        return err
-    } 
-    me.Account = account
-    me.Being.LoadSitef(rec)
-    return nil
+func (me *Character) LoadSirec(rec sitef.Record) (err error) {
+	aname := rec.Get("accountname")
+	account, err := DefaultWorld.LoadAccount(aname)
+	if err != nil {
+		return err
+	}
+	me.Account = account
+	me.Being.LoadSitef(rec)
+	return nil
 }
 
-
 // Save a character as a sitef file.
-func (me * Character) Save(dirname string) (err error) {
-    path := SavePathFor(dirname, "character", me.ID)
-    
-    rec                := sitef.NewRecord()
-    me.SaveSirec(rec)
-    monolog.Debug("Saving Character record: %s %v", path, rec)
-    return sitef.SaveRecord(path, *rec)
-}
+func (me *Character) Save(dirname string) (err error) {
+	path := SavePathFor(dirname, "character", me.ID)
 
+	rec := sitef.NewRecord()
+	me.SaveSirec(rec)
+	monolog.Debug("Saving Character record: %s %v", path, rec)
+	return sitef.SaveRecord(path, *rec)
+}
 
 // Load a character from a sitef file. Does no account checking, but returns the account name.
 func LoadCharacter(dirname string, id string) (character *Character, aname string, err error) {
-    
-    path := SavePathFor(dirname, "character", id)
-    
-    records, err := sitef.ParseFilename(path)
-    if err != nil {
-        return nil, "", err
-    }
-    
-    if len(records) < 1 {
-        return nil, "",  fmt.Errorf("No sitef record found for %s!", id)
-    }
-    
-    record := records[0]
-    monolog.Info("Loading Character record: %s %v", path, record)
-    
-    character               = new(Character)
-    aname                   = record.Get("accountname")
-    character.Being.LoadSitef(*record);
-    
-    return character, aname, nil
+
+	path := SavePathFor(dirname, "character", id)
+
+	records, err := sitef.ParseFilename(path)
+	if err != nil {
+		return nil, "", err
+	}
+
+	if len(records) < 1 {
+		return nil, "", fmt.Errorf("No sitef record found for %s!", id)
+	}
+
+	record := records[0]
+	monolog.Info("Loading Character record: %s %v", path, record)
+
+	character = new(Character)
+	aname = record.Get("accountname")
+	character.Being.LoadSitef(*record)
+
+	return character, aname, nil
 }
 
 // Load a character WITH A GIVEN NAME from a sitef file. Does no account checking, but returns the account name.
 func LoadCharacterByName(dirname string, name string) (character *Character, aname string, err error) {
-    id := EntityNameToID("character", name)
-    return LoadCharacter(dirname, id)
+	id := EntityNameToID("character", name)
+	return LoadCharacter(dirname, id)
 }
 
-
 // Load an character from a sitef file for the given account.
-func (account * Account) LoadCharacter(dirname string, id string) (character *Character, err error) {
-    
-    character, aname, err := LoadCharacter(dirname, id)
-    if character == nil {
-        return character, err
-    }
-    
-    if aname != account.Name  {
-        err := fmt.Errorf("Account doesn't match! %s %s", aname, account.Name)
-        monolog.Error("%s", err.Error())
-        return nil, err
-    }
-        
-    character.Account = account    
-    return character, nil
-}
+func (account *Account) LoadCharacter(dirname string, id string) (character *Character, err error) {
 
+	character, aname, err := LoadCharacter(dirname, id)
+	if character == nil {
+		return character, err
+	}
 
+	if aname != account.Name {
+		err := fmt.Errorf("Account doesn't match! %s %s", aname, account.Name)
+		monolog.Error("%s", err.Error())
+		return nil, err
+	}
+
+	character.Account = account
+	return character, nil
+}
 
 // Deletes the character itself from disk
-func (me * Character) Delete(dirname string) bool {
-    path := SavePathFor(dirname, "character", me.ID)
-    
-    if err := os.Remove(path) ; err != nil {
-        monolog.Warning("Could not delete character: %v %s: %s", 
-            me, path, err.Error())
-        return false
-    }
-    
-    me.Account = nil
-    monolog.Info("Character deleted: %s", me.ID)    
-    return true
-} 
-
-func (me * Character) AskLong() string {
-    return me.Long + "\n" + me.ToStatus()
+func (me *Character) Delete(dirname string) bool {
+	path := SavePathFor(dirname, "character", me.ID)
+
+	if err := os.Remove(path); err != nil {
+		monolog.Warning("Could not delete character: %v %s: %s",
+			me, path, err.Error())
+		return false
+	}
+
+	me.Account = nil
+	monolog.Info("Character deleted: %s", me.ID)
+	return true
+}
+
+func (me *Character) AskLong() string {
+	return me.Long + "\n" + me.ToStatus()
 }

+ 155 - 164
world/entity.go

@@ -1,281 +1,272 @@
 package world
+
 import "strings"
 import "os"
 import "sort"
 import "encoding/xml"
-import "github.com/beoran/woe/sitef"
-
-
-
+import "gitlab.com/beoran/woe/sitef"
 
-// Anything inside the WOE World can be identified by a unique short string 
+// Anything inside the WOE World can be identified by a unique short string
 // description, the Label
 type Labeled interface {
-    Label() string // Returns a unique label of the thing.
+	Label() string // Returns a unique label of the thing.
 }
 
 type Typed interface {
-    Type() string // Returns a string description of the type of the thing. 
+	Type() string // Returns a string description of the type of the thing.
 }
 
-
 // An entity is anything that can exist in a World
 type Entity struct {
-    ID                  string      `xml:"id,attr"`
-    Name                string      `xml:"name,attr"`
-    Short               string      `xml:"short,attr"`
-    Long                string
-    Aliases           []string    
-    // Privilege level needed to use/interact with/enter/... this Entity
-    Privilege           Privilege
+	ID      string `xml:"id,attr"`
+	Name    string `xml:"name,attr"`
+	Short   string `xml:"short,attr"`
+	Long    string
+	Aliases []string
+	// Privilege level needed to use/interact with/enter/... this Entity
+	Privilege Privilege
 }
 
-
 func EntityNameToID(kind string, name string) string {
-    return kind + "_" + strings.ToLower(name)
+	return kind + "_" + strings.ToLower(name)
 }
 
-
-func (me * Entity) InitKind(kind string, name string, 
-    privilege Privilege) (* Entity) {
-    if me == nil {
-        return me
-    }
-    me.ID       = EntityNameToID(kind, name) 
-    me.Name     = name
-    me.Short    = name
-    me.Long     = name
-    me.Privilege= privilege
-    return me
+func (me *Entity) InitKind(kind string, name string,
+	privilege Privilege) *Entity {
+	if me == nil {
+		return me
+	}
+	me.ID = EntityNameToID(kind, name)
+	me.Name = name
+	me.Short = name
+	me.Long = name
+	me.Privilege = privilege
+	return me
 }
 
 // Devious polymorphism for Entities...
 type Entitylike interface {
-    AsEntity() * Entity
+	AsEntity() *Entity
 }
 
 // A little trick to need less setters and getters
-func (me * Entity) AsEntity() (*Entity) {
-    return me
+func (me *Entity) AsEntity() *Entity {
+	return me
 }
 
 func (me Entity) Label() string {
-    return string(me.ID)
+	return string(me.ID)
 }
 
-
 type EntitySlice []Entitylike
 type EntityMap map[string]Entitylike
 
 type EntityLookup struct {
-    slice EntitySlice
-    table EntityMap  
+	slice EntitySlice
+	table EntityMap
 }
 
-
 // By is the type of a "less" function that defines the ordering of its Planet arguments.
 type EntityLikeBy func(p1, p2 Entitylike) bool
 
 // planetSorter joins a By function and a slice of Planets to be sorted.
 type EntityLikeSorter struct {
-    Entities EntitySlice
-    By       EntityLikeBy
+	Entities EntitySlice
+	By       EntityLikeBy
 }
 
-
-func (me EntitySlice) By(compare func (p1, p2 Entitylike) bool) *EntityLikeSorter {
-    return &EntityLikeSorter { me,  EntityLikeBy(compare) };
+func (me EntitySlice) By(compare func(p1, p2 Entitylike) bool) *EntityLikeSorter {
+	return &EntityLikeSorter{me, EntityLikeBy(compare)}
 }
 
 // Len is part of sort.Interface.
-func (s * EntityLikeSorter) Len() int {
-    return len(s.Entities)
+func (s *EntityLikeSorter) Len() int {
+	return len(s.Entities)
 }
 
 // Swap is part of sort.Interface.
 func (s *EntityLikeSorter) Swap(i, j int) {
-    s.Entities[i], s.Entities[j] = s.Entities[j], s.Entities[i]
+	s.Entities[i], s.Entities[j] = s.Entities[j], s.Entities[i]
 }
 
 // Less is part of sort.Interface. It is implemented by calling the "by" closure in the sorter.
 func (s *EntityLikeSorter) Less(i, j int) bool {
-    return s.By(s.Entities[i], s.Entities[j])
+	return s.By(s.Entities[i], s.Entities[j])
 }
 
-func (me * EntityLikeSorter) Sort() {
-    sort.Sort(me)
-} 
+func (me *EntityLikeSorter) Sort() {
+	sort.Sort(me)
+}
 
 // Sort is a method on the function type, By, that sorts the argument slice according to the function.
 func (by EntityLikeBy) Sort(entities EntitySlice) {
-    ps := &EntityLikeSorter{
-        Entities: entities,
-        By:      by, // The Sort method's receiver is the function (closure) that defines the sort order.
-    }
-    sort.Sort(ps)
+	ps := &EntityLikeSorter{
+		Entities: entities,
+		By:       by, // The Sort method's receiver is the function (closure) that defines the sort order.
+	}
+	sort.Sort(ps)
 }
 
-
 func (me EntityLookup) Get(index int) Entitylike {
-    return me.slice[index]
+	return me.slice[index]
 }
 
 func (me EntityLookup) Len() int {
-    return len(me.table)
+	return len(me.table)
 }
 
-func (me * EntityLookup) Add(ent Entitylike) int {
-    me.slice = append(me.slice, ent)
-    me.slice.By(func (e1, e2 Entitylike) bool {
-            return (e1.AsEntity().Label() < e2.AsEntity().Label()) 
-        }).Sort()
-    res := len(me.slice) - 1 
-    if me.table == nil {
-        me.table = make(EntityMap)
-    }
-    me.table[ent.AsEntity().Label()] = ent
-    return res 
+func (me *EntityLookup) Add(ent Entitylike) int {
+	me.slice = append(me.slice, ent)
+	me.slice.By(func(e1, e2 Entitylike) bool {
+		return (e1.AsEntity().Label() < e2.AsEntity().Label())
+	}).Sort()
+	res := len(me.slice) - 1
+	if me.table == nil {
+		me.table = make(EntityMap)
+	}
+	me.table[ent.AsEntity().Label()] = ent
+	return res
 }
 
-func (me EntityLookup) Lookup(id string) (Entitylike) {
-    res, ok := me.table[id]
-    if !ok {
-        return nil
-    }
-    return res    
+func (me EntityLookup) Lookup(id string) Entitylike {
+	res, ok := me.table[id]
+	if !ok {
+		return nil
+	}
+	return res
 }
 
 func (me EntityLookup) Remove(ent Entitylike) bool {
-    key := ent.AsEntity().Label()
-    delete(me.table, key)
-    return true
+	key := ent.AsEntity().Label()
+	delete(me.table, key)
+	return true
 }
 
-type EntityLookupEachFunc func (id string, ent Entitylike, args...interface{}) Entitylike
+type EntityLookupEachFunc func(id string, ent Entitylike, args ...interface{}) Entitylike
 
-func (me EntityLookup) Each(lambda EntityLookupEachFunc, args...interface{}) Entitylike {
-    for k, v := range (me.table) {
-        res := lambda(k, v, args...) 
-        if res != nil {
-            return res
-        }
-    } 
-    return nil
+func (me EntityLookup) Each(lambda EntityLookupEachFunc, args ...interface{}) Entitylike {
+	for k, v := range me.table {
+		res := lambda(k, v, args...)
+		if res != nil {
+			return res
+		}
+	}
+	return nil
 }
 
-
 type EntityList interface {
-    Get(int) Entitylike
-    Len() int
-    Add(Entitylike) int
-    Lookup(string) (Entitylike)
-    Remove(Entitylike) bool
+	Get(int) Entitylike
+	Len() int
+	Add(Entitylike) int
+	Lookup(string) Entitylike
+	Remove(Entitylike) bool
 }
 
-// Interface 
+// Interface
 type Savable interface {
-    Labeled
-    Typed
+	Labeled
+	Typed
 }
 
-type Loadable interface {    
-    Typed
+type Loadable interface {
+	Typed
 }
 
 func SaveSavable(dirname string, savable Savable) (err error) {
-    path := SavePathFor(dirname, savable.Type(), savable.Label())
-    
-    file, err := os.Create(path)
-    if err != nil {
-        return err
-    }
-    enc := xml.NewEncoder(file)
-    enc.Indent(" ", "  ")
-    return enc.Encode(savable)
-}
-
-func LoadLoadable(dirname string, nameid string, result Loadable) (Loadable) {
-    path := SavePathFor(dirname, result.Type(), nameid)
-    
-    file, err := os.Open(path)
-    if err != nil {
-        return nil
-    }
-    dec := xml.NewDecoder(file)    
-    err = dec.Decode(result)
-    if err != nil { return nil }
-    return result
-}
-
-// A list of Identifier items mapped to their ID's 
+	path := SavePathFor(dirname, savable.Type(), savable.Label())
+
+	file, err := os.Create(path)
+	if err != nil {
+		return err
+	}
+	enc := xml.NewEncoder(file)
+	enc.Indent(" ", "  ")
+	return enc.Encode(savable)
+}
+
+func LoadLoadable(dirname string, nameid string, result Loadable) Loadable {
+	path := SavePathFor(dirname, result.Type(), nameid)
+
+	file, err := os.Open(path)
+	if err != nil {
+		return nil
+	}
+	dec := xml.NewDecoder(file)
+	err = dec.Decode(result)
+	if err != nil {
+		return nil
+	}
+	return result
+}
+
+// A list of Identifier items mapped to their ID's
 type LabeledLister interface {
-    Get(string)     Labeled
-    Put(Labeled)
-    Size()          int
-    Index(int)      Labeled
-    PutIndex(int)
+	Get(string) Labeled
+	Put(Labeled)
+	Size() int
+	Index(int) Labeled
+	PutIndex(int)
 }
 
 type LabeledList struct {
-    byList        []Labeled
-    byLabel       map[string] Labeled
+	byList  []Labeled
+	byLabel map[string]Labeled
 }
 
-func NewLabeledList() * LabeledList {
-    byname := make(map[string] Labeled)
-    return &LabeledList{nil, byname}
+func NewLabeledList() *LabeledList {
+	byname := make(map[string]Labeled)
+	return &LabeledList{nil, byname}
 }
 
-func (me * LabeledList) Get(id string) Labeled {
-    val, ok := me.byLabel[id]
-    if !ok { return nil }
-    return val
+func (me *LabeledList) Get(id string) Labeled {
+	val, ok := me.byLabel[id]
+	if !ok {
+		return nil
+	}
+	return val
 }
 
-func (me * LabeledList) Index(index int) Labeled {
-    if index < 0 { return nil } 
-    if index > len(me.byList) { return nil }
-    val := me.byList[index]
-    return val
+func (me *LabeledList) Index(index int) Labeled {
+	if index < 0 {
+		return nil
+	}
+	if index > len(me.byList) {
+		return nil
+	}
+	val := me.byList[index]
+	return val
 }
 
-
 // Save an entity to a sitef record.
-func (me * Entity) SaveSitef(rec * sitef.Record) (err error) {
-    rec.Put("id", me.ID)
-    rec.Put("name", me.Name)
-    rec.Put("short", me.Short)
-    rec.Put("long",  me.Long)
-    return nil
+func (me *Entity) SaveSitef(rec *sitef.Record) (err error) {
+	rec.Put("id", me.ID)
+	rec.Put("name", me.Name)
+	rec.Put("short", me.Short)
+	rec.Put("long", me.Long)
+	return nil
 }
 
 // Load an entity from a sitef record.
-func (me * Entity) LoadSitef(rec sitef.Record) (err error) {
-    me.ID       = rec.Get("id")
-    me.Name     = rec.Get("name")
-    me.Short    = rec.Get("short")
-    me.Long     = rec.Get("long")
-    return nil
+func (me *Entity) LoadSitef(rec sitef.Record) (err error) {
+	me.ID = rec.Get("id")
+	me.Name = rec.Get("name")
+	me.Short = rec.Get("short")
+	me.Long = rec.Get("long")
+	return nil
 }
 
-
 func (me Entity) AskName() string {
-    return me.Name
+	return me.Name
 }
 
 func (me Entity) AskShort() string {
-    return me.Short
+	return me.Short
 }
 
 func (me Entity) AskLong() string {
-    return me.Long
+	return me.Long
 }
 
 func (me Entity) AskPrivilege() Privilege {
-    return me.Privilege
+	return me.Privilege
 }
-
-
-
-
-

+ 232 - 243
world/item.go

@@ -1,281 +1,270 @@
 package world
 
-import "github.com/beoran/woe/sitef"
-import "github.com/beoran/woe/monolog"
+import "gitlab.com/beoran/woe/sitef"
+import "gitlab.com/beoran/woe/monolog"
 import "fmt"
 import "errors"
 
 type DamageKind string
+
 const (
-    DAMAGE_CUT          DamageKind = "cut"
-    DAMAGE_CRUSH        DamageKind = "crush"
-    DAMAGE_PIERCE       DamageKind = "pierce"
-    DAMAGE_HEAT         DamageKind = "heat"
-    DAMAGE_COLD         DamageKind = "cold"
-    DAMAGE_SHOCK        DamageKind = "shock"
-    DAMAGE_TOXIC        DamageKind = "toxic"
-    DAMAGE_LASER        DamageKind = "laser"
-    DAMAGE_BLAST        DamageKind = "blast"
-    DAMAGE_TONE         DamageKind = "tone"
-    DAMAGE_CORRUPTION   DamageKind = "corruption"
-    DAMAGE_ARCANE       DamageKind = "arcane"
-    DAMAGE_HEAL         DamageKind = "heal"
-    DAMAGE_REPAIR       DamageKind = "repair"
+	DAMAGE_CUT        DamageKind = "cut"
+	DAMAGE_CRUSH      DamageKind = "crush"
+	DAMAGE_PIERCE     DamageKind = "pierce"
+	DAMAGE_HEAT       DamageKind = "heat"
+	DAMAGE_COLD       DamageKind = "cold"
+	DAMAGE_SHOCK      DamageKind = "shock"
+	DAMAGE_TOXIC      DamageKind = "toxic"
+	DAMAGE_LASER      DamageKind = "laser"
+	DAMAGE_BLAST      DamageKind = "blast"
+	DAMAGE_TONE       DamageKind = "tone"
+	DAMAGE_CORRUPTION DamageKind = "corruption"
+	DAMAGE_ARCANE     DamageKind = "arcane"
+	DAMAGE_HEAL       DamageKind = "heal"
+	DAMAGE_REPAIR     DamageKind = "repair"
 )
-    
-    
-
-
 
 type ItemKind string
 
 const (
-    ITEM_MEDICINE   ItemKind = "medicine"
-    
-    ITEM_CAP        ItemKind = "cap"
-    ITEM_RIBBON     ItemKind = "ribbon"    
-    ITEM_HAT        ItemKind = "hat"
-    ITEM_SCARF      ItemKind = "scarf"
-    ITEM_CIRCLET    ItemKind = "circlet"
-    ITEM_HEADGEAR   ItemKind = "headgear"
-    ITEM_CROWN      ItemKind = "crown"
-    ITEM_HELMET     ItemKind = "helmet"
-    
-    ITEM_CAPE       ItemKind = "cape"
-    ITEM_COAT       ItemKind = "coat"
-    ITEM_ROBE       ItemKind = "robe"
-    ITEM_VEST       ItemKind = "vest"
-    ITEM_CHEST      ItemKind = "chest"
-    ITEM_SUIT       ItemKind = "suit"
-    ITEM_ARMOR      ItemKind = "armor"
-
-    ITEM_SANDAL     ItemKind = "sandal"
-    ITEM_SHOE       ItemKind = "shoe"
-    ITEM_BOOT       ItemKind = "boot"
-    
-
- 
- //not sure...   
-    ITEM_PANTS      ItemKind = "pants"
-    ITEM_SKIRT      ItemKind = "skirt"
-    ITEM_GREAVES    ItemKind = "greaves"  
-    ITEM_RING       ItemKind = "ring"
-    ITEM_BRACELET   ItemKind = "bracelet"
-    ITEM_ARMLET     ItemKind = "armlet"
-    ITEM_SLEEVE     ItemKind = "sleeve"
-    ITEM_PAULDRON   ItemKind = "pauldron"
-    ITEM_GAUNTLET   ItemKind = "gauntlet"
-    ITEM_NECKLACE   ItemKind = "necklace"
-    ITEM_EARRING    ItemKind = "earring"
-    ITEM_LAMP       ItemKind = "lamp"
-    ITEM_FLASHLIGHT ItemKind = "flashlight"
-  // sure again
-   
-    ITEM_SWORD      ItemKind = "sword"
-    ITEM_TWOHANDER  ItemKind = "twohander"
-    ITEM_KNIFE      ItemKind = "knife"
-    ITEM_DAGGER     ItemKind = "dagger"
-    ITEM_GLOVE      ItemKind = "glove"
-    ITEM_CLAW       ItemKind = "claw"
-    ITEM_WAND       ItemKind = "wand"
-    ITEM_STAFF      ItemKind = "staff"
-    ITEM_FOCUS      ItemKind = "focus"
-    
-    // Not sure if these will be implemented.
-    
-    ITEM_AXE        ItemKind = "axe"
-    ITEM_MAUL       ItemKind = "maul"
-    ITEM_SPEAR      ItemKind = "spear"
-    ITEM_NAGINATA   ItemKind = "naginata"
-    ITEM_BOW        ItemKind = "bow"
-    ITEM_CROSSBOW   ItemKind = "crossbow"
-    ITEM_ARROW      ItemKind = "arrow"
-    ITEM_BOLT       ItemKind = "bolt"
-
-    // But these below are planned.
-    
-    ITEM_NEEDLER    ItemKind = "needler"
-    ITEM_HANDGUN    ItemKind = "handgun"
-    ITEM_LASERGUN   ItemKind = "lasergun"
-    ITEM_MACHINEGUN ItemKind = "machinegun"
-    ITEM_CANNON     ItemKind = "cannon"
-    ITEM_BAZOOKA    ItemKind = "bazooka"
-    
-    ITEM_NEEDLE     ItemKind = "needle"
-    ITEM_BULLET     ItemKind = "bullet"
-    ITEM_CELL       ItemKind = "cell"
-    ITEM_ROCKET     ItemKind = "rocket"
-    
-    ITEM_EXPLOSIVE  ItemKind = "explosive"
-    ITEM_GRENADE    ItemKind = "grenade"
-    ITEM_REPAIR     ItemKind = "repair"
-    ITEM_ORE        ItemKind = "ore"
-    ITEM_INGOT      ItemKind = "ingot"
-    ITEM_METAL      ItemKind = "metal"
-    ITEM_PLANT      ItemKind = "plant"
-    ITEM_FRUIT      ItemKind = "fruit"
-    ITEM_WOOD       ItemKind = "wood"
-    ITEM_FOOD       ItemKind = "food"
-    ITEM_TRAP       ItemKind = "trap"
-    ITEM_HANDCUFFS  ItemKind = "handcuffs"
-    ITEM_CHEMICAL   ItemKind = "chemical"
-    ITEM_FISH       ItemKind = "fish"
-    ITEM_MEAT       ItemKind = "meat"
-    ITEM_HIDE       ItemKind = "hide"
-    ITEM_LEATHER    ItemKind = "leather"
-    ITEM_FIBER      ItemKind = "fiber"
-    ITEM_CLOTH      ItemKind = "cloth"
-    ITEM_CERAMIC    ItemKind = "ceramic"
-    ITEM_POLYMER    ItemKind = "polymer"
-    
-    // android parts
-    // AGI, STR, CHA 
-    ITEM_LEGPARTS   ItemKind = "legparts"
-    // DEX, STR, CHA
-    ITEM_ARMPARTS   ItemKind = "armparts"
-    // TOU, CHA
-    ITEM_BODYPARTS  ItemKind = "bodyparts"
-    // INT, WIS, CHA
-    ITEM_HEADPARTS  ItemKind = "headparts"
-    
-    
-    ITEM_           ItemKind = ""
+	ITEM_MEDICINE ItemKind = "medicine"
+
+	ITEM_CAP      ItemKind = "cap"
+	ITEM_RIBBON   ItemKind = "ribbon"
+	ITEM_HAT      ItemKind = "hat"
+	ITEM_SCARF    ItemKind = "scarf"
+	ITEM_CIRCLET  ItemKind = "circlet"
+	ITEM_HEADGEAR ItemKind = "headgear"
+	ITEM_CROWN    ItemKind = "crown"
+	ITEM_HELMET   ItemKind = "helmet"
+
+	ITEM_CAPE  ItemKind = "cape"
+	ITEM_COAT  ItemKind = "coat"
+	ITEM_ROBE  ItemKind = "robe"
+	ITEM_VEST  ItemKind = "vest"
+	ITEM_CHEST ItemKind = "chest"
+	ITEM_SUIT  ItemKind = "suit"
+	ITEM_ARMOR ItemKind = "armor"
+
+	ITEM_SANDAL ItemKind = "sandal"
+	ITEM_SHOE   ItemKind = "shoe"
+	ITEM_BOOT   ItemKind = "boot"
+
+	//not sure...
+	ITEM_PANTS      ItemKind = "pants"
+	ITEM_SKIRT      ItemKind = "skirt"
+	ITEM_GREAVES    ItemKind = "greaves"
+	ITEM_RING       ItemKind = "ring"
+	ITEM_BRACELET   ItemKind = "bracelet"
+	ITEM_ARMLET     ItemKind = "armlet"
+	ITEM_SLEEVE     ItemKind = "sleeve"
+	ITEM_PAULDRON   ItemKind = "pauldron"
+	ITEM_GAUNTLET   ItemKind = "gauntlet"
+	ITEM_NECKLACE   ItemKind = "necklace"
+	ITEM_EARRING    ItemKind = "earring"
+	ITEM_LAMP       ItemKind = "lamp"
+	ITEM_FLASHLIGHT ItemKind = "flashlight"
+	// sure again
+
+	ITEM_SWORD     ItemKind = "sword"
+	ITEM_TWOHANDER ItemKind = "twohander"
+	ITEM_KNIFE     ItemKind = "knife"
+	ITEM_DAGGER    ItemKind = "dagger"
+	ITEM_GLOVE     ItemKind = "glove"
+	ITEM_CLAW      ItemKind = "claw"
+	ITEM_WAND      ItemKind = "wand"
+	ITEM_STAFF     ItemKind = "staff"
+	ITEM_FOCUS     ItemKind = "focus"
+
+	// Not sure if these will be implemented.
+
+	ITEM_AXE      ItemKind = "axe"
+	ITEM_MAUL     ItemKind = "maul"
+	ITEM_SPEAR    ItemKind = "spear"
+	ITEM_NAGINATA ItemKind = "naginata"
+	ITEM_BOW      ItemKind = "bow"
+	ITEM_CROSSBOW ItemKind = "crossbow"
+	ITEM_ARROW    ItemKind = "arrow"
+	ITEM_BOLT     ItemKind = "bolt"
+
+	// But these below are planned.
+
+	ITEM_NEEDLER    ItemKind = "needler"
+	ITEM_HANDGUN    ItemKind = "handgun"
+	ITEM_LASERGUN   ItemKind = "lasergun"
+	ITEM_MACHINEGUN ItemKind = "machinegun"
+	ITEM_CANNON     ItemKind = "cannon"
+	ITEM_BAZOOKA    ItemKind = "bazooka"
+
+	ITEM_NEEDLE ItemKind = "needle"
+	ITEM_BULLET ItemKind = "bullet"
+	ITEM_CELL   ItemKind = "cell"
+	ITEM_ROCKET ItemKind = "rocket"
+
+	ITEM_EXPLOSIVE ItemKind = "explosive"
+	ITEM_GRENADE   ItemKind = "grenade"
+	ITEM_REPAIR    ItemKind = "repair"
+	ITEM_ORE       ItemKind = "ore"
+	ITEM_INGOT     ItemKind = "ingot"
+	ITEM_METAL     ItemKind = "metal"
+	ITEM_PLANT     ItemKind = "plant"
+	ITEM_FRUIT     ItemKind = "fruit"
+	ITEM_WOOD      ItemKind = "wood"
+	ITEM_FOOD      ItemKind = "food"
+	ITEM_TRAP      ItemKind = "trap"
+	ITEM_HANDCUFFS ItemKind = "handcuffs"
+	ITEM_CHEMICAL  ItemKind = "chemical"
+	ITEM_FISH      ItemKind = "fish"
+	ITEM_MEAT      ItemKind = "meat"
+	ITEM_HIDE      ItemKind = "hide"
+	ITEM_LEATHER   ItemKind = "leather"
+	ITEM_FIBER     ItemKind = "fiber"
+	ITEM_CLOTH     ItemKind = "cloth"
+	ITEM_CERAMIC   ItemKind = "ceramic"
+	ITEM_POLYMER   ItemKind = "polymer"
+
+	// android parts
+	// AGI, STR, CHA
+	ITEM_LEGPARTS ItemKind = "legparts"
+	// DEX, STR, CHA
+	ITEM_ARMPARTS ItemKind = "armparts"
+	// TOU, CHA
+	ITEM_BODYPARTS ItemKind = "bodyparts"
+	// INT, WIS, CHA
+	ITEM_HEADPARTS ItemKind = "headparts"
+
+	ITEM_ ItemKind = ""
 )
 
 type EquipWhere string
 
 const (
-    EQUIP_NONE      EquipWhere = "none"
-    EQUIP_HEAD      EquipWhere = "head"
-    EQUIP_TORSO     EquipWhere = "torso"
-    EQUIP_OFFHAND   EquipWhere = "offhand"
-    EQUIP_DOMINANT  EquipWhere = "dominant"
-    EQUIP_AMMO      EquipWhere = "ammo"    
-    EQUIP_FEET      EquipWhere = "feet"
-    EQUIP_FOCUS     EquipWhere = "focus"
-    EQUIP_PHONE     EquipWhere = "phone"
-    
-    EQUIP_GLOVES    EquipWhere = "gloves"
-    EQUIP_NECK      EquipWhere = "neck"
-    EQUIP_LEGS      EquipWhere = "legs"
-    EQUIP_ARMS      EquipWhere = "arms"
-    EQUIP_RIGHTRING EquipWhere = "rightring"
-    EQUIP_LEFTRING  EquipWhere = "leftring"
-    EQUIP_BELT      EquipWhere = "belt"
-    EQUIP_LIGHT     EquipWhere = "light"
-    EQUIP_          EquipWhere = ""    
+	EQUIP_NONE     EquipWhere = "none"
+	EQUIP_HEAD     EquipWhere = "head"
+	EQUIP_TORSO    EquipWhere = "torso"
+	EQUIP_OFFHAND  EquipWhere = "offhand"
+	EQUIP_DOMINANT EquipWhere = "dominant"
+	EQUIP_AMMO     EquipWhere = "ammo"
+	EQUIP_FEET     EquipWhere = "feet"
+	EQUIP_FOCUS    EquipWhere = "focus"
+	EQUIP_PHONE    EquipWhere = "phone"
+
+	EQUIP_GLOVES    EquipWhere = "gloves"
+	EQUIP_NECK      EquipWhere = "neck"
+	EQUIP_LEGS      EquipWhere = "legs"
+	EQUIP_ARMS      EquipWhere = "arms"
+	EQUIP_RIGHTRING EquipWhere = "rightring"
+	EQUIP_LEFTRING  EquipWhere = "leftring"
+	EQUIP_BELT      EquipWhere = "belt"
+	EQUIP_LIGHT     EquipWhere = "light"
+	EQUIP_          EquipWhere = ""
 )
 
-var EquipWhereList []EquipWhere = []EquipWhere {
-    EQUIP_HEAD,         EQUIP_TORSO,    EQUIP_OFFHAND,  EQUIP_DOMINANT,
-    EQUIP_AMMO,         EQUIP_FEET,     EQUIP_FOCUS,    EQUIP_PHONE,
-    EQUIP_GLOVES,       EQUIP_NECK,     EQUIP_LEGS,     EQUIP_ARMS,
-    EQUIP_RIGHTRING,    EQUIP_LEFTRING, EQUIP_BELT,     EQUIP_LIGHT,
+var EquipWhereList []EquipWhere = []EquipWhere{
+	EQUIP_HEAD, EQUIP_TORSO, EQUIP_OFFHAND, EQUIP_DOMINANT,
+	EQUIP_AMMO, EQUIP_FEET, EQUIP_FOCUS, EQUIP_PHONE,
+	EQUIP_GLOVES, EQUIP_NECK, EQUIP_LEGS, EQUIP_ARMS,
+	EQUIP_RIGHTRING, EQUIP_LEFTRING, EQUIP_BELT, EQUIP_LIGHT,
 }
 
 type Item struct {
-    Entity
-    Quality       int
-    Price         int
-    Kind          ItemKind
-    Damage        DamageKind
-    // Equipment location,  "none" if not equippable
-    Equip         EquipWhere
-    // Level of crafing skill needed to craft this, or of harvesting skill 
-    // to harvest this, or of mining skill to mine this. Negative if cannot 
-    // be crafted nor harvested, nor mined.    
-    Level         int
-    // Id's of ingredients to craft this item. Empty if it cannot be crafted.
-    Ingredients []string
-    // Id of item this item can be upgraded/enhanced to. empty or "none"
-    // if it cannot be upgraded.
-    Upgrade       string
-    // ID of item this item can degrade into. empty or "none" if cannot be 
-    // degraded.
-    Degrade       string
-    // ID of technique/art/exploit this item teaches when used, empty or 
-    // none if it teaches nothing. If it's a skill, the XP of teaching is 
-    // determined by the Quality of the item.   
-    Teaches       string
-     // ID of skill needed to craft this item   
-    Craft         string
+	Entity
+	Quality int
+	Price   int
+	Kind    ItemKind
+	Damage  DamageKind
+	// Equipment location,  "none" if not equippable
+	Equip EquipWhere
+	// Level of crafing skill needed to craft this, or of harvesting skill
+	// to harvest this, or of mining skill to mine this. Negative if cannot
+	// be crafted nor harvested, nor mined.
+	Level int
+	// Id's of ingredients to craft this item. Empty if it cannot be crafted.
+	Ingredients []string
+	// Id of item this item can be upgraded/enhanced to. empty or "none"
+	// if it cannot be upgraded.
+	Upgrade string
+	// ID of item this item can degrade into. empty or "none" if cannot be
+	// degraded.
+	Degrade string
+	// ID of technique/art/exploit this item teaches when used, empty or
+	// none if it teaches nothing. If it's a skill, the XP of teaching is
+	// determined by the Quality of the item.
+	Teaches string
+	// ID of skill needed to craft this item
+	Craft string
 }
 
 // Load an item from a sitef file.
 func LoadItem(dirname string, id string) (item *Item, err error) {
-    
-    path := SavePathFor(dirname, "item", id)
-    
-    records, err := sitef.ParseFilename(path)
-    if err != nil {
-        return nil, err
-    }
-    
-    if len(records) < 1 {
-        return nil, errors.New("No item found!")
-    }
-    
-    record := records[0]
-    monolog.Info("Loading Item record: %s %v", path, record)
-    
-    item            = new(Item)
-    item.Entity.LoadSitef(*record)
-    item.Quality    = record.GetIntDefault("quality", 0)
-    item.Price      = record.GetIntDefault("price", -1)
-    item.Level      = record.GetIntDefault("level", -1)
-    item.Kind       = ItemKind(record.Get("kind"))
-    item.Damage     = DamageKind(record.Get("damage"))
-    item.Equip      = EquipWhere(record.Get("equip"))
-    item.Upgrade    = record.Get("upgrade")
-    item.Degrade    = record.Get("degrade")
-    item.Teaches    = record.Get("teaches")
-    item.Craft      = record.Get("craft")
-    
-    ningredients   := record.GetIntDefault("ingredients", 0)
-    
-    for i := 0; i < ningredients; i++ {
-        ingr := record.GetArrayIndex("ingredients", i)
-        item.Ingredients = append(item.Ingredients, ingr) 
-    }
-    
-    monolog.Info("Loaded Item: %s %v", path, item)
-    return item, nil
-}
 
+	path := SavePathFor(dirname, "item", id)
+
+	records, err := sitef.ParseFilename(path)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(records) < 1 {
+		return nil, errors.New("No item found!")
+	}
+
+	record := records[0]
+	monolog.Info("Loading Item record: %s %v", path, record)
 
+	item = new(Item)
+	item.Entity.LoadSitef(*record)
+	item.Quality = record.GetIntDefault("quality", 0)
+	item.Price = record.GetIntDefault("price", -1)
+	item.Level = record.GetIntDefault("level", -1)
+	item.Kind = ItemKind(record.Get("kind"))
+	item.Damage = DamageKind(record.Get("damage"))
+	item.Equip = EquipWhere(record.Get("equip"))
+	item.Upgrade = record.Get("upgrade")
+	item.Degrade = record.Get("degrade")
+	item.Teaches = record.Get("teaches")
+	item.Craft = record.Get("craft")
+
+	ningredients := record.GetIntDefault("ingredients", 0)
+
+	for i := 0; i < ningredients; i++ {
+		ingr := record.GetArrayIndex("ingredients", i)
+		item.Ingredients = append(item.Ingredients, ingr)
+	}
+
+	monolog.Info("Loaded Item: %s %v", path, item)
+	return item, nil
+}
 
 type ItemPointer struct {
-    ID     string
-    item * Item
+	ID   string
+	item *Item
 }
 
 type Equipment struct {
-    Equipped map[EquipWhere] * Item
+	Equipped map[EquipWhere]*Item
 }
 
-
-func (me * Equipment) SaveSitef(rec sitef.Record) (err error) {
-    for k, v := range(me.Equipped) {
-        if v != nil {
-            key := fmt.Sprintf("equipment[%s]", k)
-            rec.Put(key, v.ID)
-        }
-    }
-    return nil
+func (me *Equipment) SaveSitef(rec sitef.Record) (err error) {
+	for k, v := range me.Equipped {
+		if v != nil {
+			key := fmt.Sprintf("equipment[%s]", k)
+			rec.Put(key, v.ID)
+		}
+	}
+	return nil
 }
 
-func (me * Equipment) LoadSitef(rec sitef.Record, world *World, dirname string) (err error) {
-    for k := range(EquipWhereList) {
-        key := fmt.Sprintf("equipment[%s]", k)
-        val, ok := rec.MayGet(key)
-        if ok {   
-            item, err := world.LoadItem(val)
-            if item != nil && err == nil {
-               me.Equipped[EquipWhere(k)] = item
-            }               
-        }
-    }
-    return nil
+func (me *Equipment) LoadSitef(rec sitef.Record, world *World, dirname string) (err error) {
+	for k := range EquipWhereList {
+		key := fmt.Sprintf("equipment[%s]", k)
+		val, ok := rec.MayGet(key)
+		if ok {
+			item, err := world.LoadItem(val)
+			if item != nil && err == nil {
+				me.Equipped[EquipWhere(k)] = item
+			}
+		}
+	}
+	return nil
 }
-
-

+ 42 - 43
world/room.go

@@ -1,57 +1,56 @@
 package world
 
-import "github.com/beoran/woe/sitef"
-import "github.com/beoran/woe/monolog"
+import "gitlab.com/beoran/woe/sitef"
+import "gitlab.com/beoran/woe/monolog"
+
 // import "fmt"
 import "errors"
 
-
-
-type Direction  string
+type Direction string
 
 type Exit struct {
-    Direction
-    ToRoomID    int
-    toRoom    * Room
+	Direction
+	ToRoomID int
+	toRoom   *Room
 }
 
 type Room struct {
-    Entity
-    Exits   map[Direction]Exit
+	Entity
+	Exits map[Direction]Exit
 }
 
 // Load a room from a sitef file.
-func LoadRoom(dirname string, id string) (room * Room, err error) {
-    
-    path := SavePathFor(dirname, "room", id)
-    
-    records, err := sitef.ParseFilename(path)
-    if err != nil {
-        return nil, err
-    }
-    
-    if len(records) < 1 {
-        return nil, errors.New("No room found!")
-    }
-    
-    record := records[0]
-    monolog.Info("Loading Room record: %s %v", path, record)
-    
-    room = new(Room)
-    room.Entity.LoadSitef(*record)
-    /*
-    account.Name            = record.Get("name")
-    account.Hash            = record.Get("hash")
-    account.Algo            = record.Get("algo")
-    account.Email           = record.Get("email")
-    account.Points          = record.GetIntDefault("points", 0)
-    account.Privilege       = Privilege(record.GetIntDefault("privilege", 
-                                int(PRIVILEGE_NORMAL)))
-    
-    var nchars int
-    nchars                  = record.GetIntDefault("characters", 0)
-    _ = nchars    
-    */
-    monolog.Info("Loaded Room: %s %v", path, room)
-    return room, nil
+func LoadRoom(dirname string, id string) (room *Room, err error) {
+
+	path := SavePathFor(dirname, "room", id)
+
+	records, err := sitef.ParseFilename(path)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(records) < 1 {
+		return nil, errors.New("No room found!")
+	}
+
+	record := records[0]
+	monolog.Info("Loading Room record: %s %v", path, record)
+
+	room = new(Room)
+	room.Entity.LoadSitef(*record)
+	/*
+	   account.Name            = record.Get("name")
+	   account.Hash            = record.Get("hash")
+	   account.Algo            = record.Get("algo")
+	   account.Email           = record.Get("email")
+	   account.Points          = record.GetIntDefault("points", 0)
+	   account.Privilege       = Privilege(record.GetIntDefault("privilege",
+	                               int(PRIVILEGE_NORMAL)))
+
+	   var nchars int
+	   nchars                  = record.GetIntDefault("characters", 0)
+	   _ = nchars
+	*/
+	monolog.Info("Loaded Room: %s %v", path, room)
+	return room, nil
 }

+ 163 - 173
world/world.go

@@ -1,224 +1,214 @@
 package world
 
-import "github.com/beoran/woe/monolog"
-import "github.com/beoran/woe/sitef"
+import "gitlab.com/beoran/woe/monolog"
+import "gitlab.com/beoran/woe/sitef"
 import "errors"
 
-/* Elements of the WOE game world.  
- * Only Zones, Rooms and their Exits, Items, 
+/* Elements of the WOE game world.
+ * Only Zones, Rooms and their Exits, Items,
  * Mobiles & Characters are saved
- * and loaded from disk. All the rest 
+ * and loaded from disk. All the rest
  * is kept statically delared in code for simplicity.
-*/
-
+ */
 
 type World struct {
-    Name                      string
-    MOTD                      string
-    dirname                   string
-    entitymap       map[string] * Entity
-    zonemap         map[string] * Zone
-    zones                [] * Zone
-    charactermap    map[string] * Character
-    characters           []   Character
-    roommap         map[string] * Room
-    rooms                []   Room
-    itemmap         map[string] * Item
-    items                []   Item
-    mobilemap       map[string] * Mobile
-    mobiles              []   Mobile
-    accounts             [] * Account
-    accountmap      map[string] * Account
+	Name         string
+	MOTD         string
+	dirname      string
+	entitymap    map[string]*Entity
+	zonemap      map[string]*Zone
+	zones        []*Zone
+	charactermap map[string]*Character
+	characters   []Character
+	roommap      map[string]*Room
+	rooms        []Room
+	itemmap      map[string]*Item
+	items        []Item
+	mobilemap    map[string]*Mobile
+	mobiles      []Mobile
+	accounts     []*Account
+	accountmap   map[string]*Account
 }
 
-
-
-func (me * World) AddWoeDefaults() {
-    /*
-    me.AddSpecies(NewSpecies("sp_human"  , "Human"))
-    me.AddSpecies(NewSpecies("sp_neosa"  , "Neosa"))
-    me.AddSpecies(NewSpecies("sp_mantu"  , "Mantu"))
-    me.AddSpecies(NewSpecies("sp_cyborg" , "Cyborg"))
-    me.AddSpecies(NewSpecies("sp_android", "Android"))
-    */
+func (me *World) AddWoeDefaults() {
+	/*
+	   me.AddSpecies(NewSpecies("sp_human"  , "Human"))
+	   me.AddSpecies(NewSpecies("sp_neosa"  , "Neosa"))
+	   me.AddSpecies(NewSpecies("sp_mantu"  , "Mantu"))
+	   me.AddSpecies(NewSpecies("sp_cyborg" , "Cyborg"))
+	   me.AddSpecies(NewSpecies("sp_android", "Android"))
+	*/
 }
 
-func NewWorld(name string, motd string, dirname string) (*World) {
-    world := new(World)
-    world.Name          = name
-    world.MOTD          = motd
-    world.dirname       = dirname
-    world.accountmap    = make(map[string] * Account)
-    world.itemmap       = make(map[string] * Item)
-    world.roommap       = make(map[string] * Room)
-    world.charactermap  = make(map[string] * Character)
-
-    world.AddWoeDefaults()
-    return world;
+func NewWorld(name string, motd string, dirname string) *World {
+	world := new(World)
+	world.Name = name
+	world.MOTD = motd
+	world.dirname = dirname
+	world.accountmap = make(map[string]*Account)
+	world.itemmap = make(map[string]*Item)
+	world.roommap = make(map[string]*Room)
+	world.charactermap = make(map[string]*Character)
+
+	world.AddWoeDefaults()
+	return world
 }
 
-
-func HaveID(ids [] string, id string) bool {
-    for index := 0 ; index < len(ids) ; index++ {
-        if ids[index] == id { return true }  
-    }
-    return false
+func HaveID(ids []string, id string) bool {
+	for index := 0; index < len(ids); index++ {
+		if ids[index] == id {
+			return true
+		}
+	}
+	return false
 }
 
-func (me * World) AddEntity(entity * Entity) {
-    me.entitymap[entity.ID] = entity;
+func (me *World) AddEntity(entity *Entity) {
+	me.entitymap[entity.ID] = entity
 }
 
-func (me * World) AddZone(zone * Zone) {
-    me.zones = append(me.zones, zone)
-    me.zonemap[zone.ID] = zone;
-    me.AddEntity(&zone.Entity);
+func (me *World) AddZone(zone *Zone) {
+	me.zones = append(me.zones, zone)
+	me.zonemap[zone.ID] = zone
+	me.AddEntity(&zone.Entity)
 }
 
 // Save an account as a sitef file.
-func (me * World) Save(dirname string) (err error) {
-    path := SavePathFor(dirname, "world", me.Name)
-    
-    rec                  := sitef.NewRecord()
-    rec.Put("name",         me.Name)
-    rec.Put("motd",         me.MOTD)
-    monolog.Debug("Saving World record: %s %v", path, rec)
-    return sitef.SaveRecord(path, *rec)
+func (me *World) Save(dirname string) (err error) {
+	path := SavePathFor(dirname, "world", me.Name)
+
+	rec := sitef.NewRecord()
+	rec.Put("name", me.Name)
+	rec.Put("motd", me.MOTD)
+	monolog.Debug("Saving World record: %s %v", path, rec)
+	return sitef.SaveRecord(path, *rec)
 }
 
 // Load a world from a sitef file.
-func LoadWorld(dirname string, name string) (world * World, err error) {
-    
-    path := SavePathFor(dirname, "world", name)
-    
-    records, err := sitef.ParseFilename(path)
-    if err != nil {
-        return nil, err
-    }
-    
-    if len(records) < 1 {
-        return nil, errors.New("No record found!")
-    }
-    
-    record := records[0]
-    monolog.Info("Loading World record: %s %v", path, record)
-    
-    world = NewWorld(record.Get("name"), record.Get("motd"), dirname)
-    monolog.Info("Loaded World: %s %v", path, world)
-    return world, nil
-}
+func LoadWorld(dirname string, name string) (world *World, err error) {
 
+	path := SavePathFor(dirname, "world", name)
+
+	records, err := sitef.ParseFilename(path)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(records) < 1 {
+		return nil, errors.New("No record found!")
+	}
+
+	record := records[0]
+	monolog.Info("Loading World record: %s %v", path, record)
+
+	world = NewWorld(record.Get("name"), record.Get("motd"), dirname)
+	monolog.Info("Loaded World: %s %v", path, world)
+	return world, nil
+}
 
 // Returns an acccount that has already been loaded or nil if not found
-func (me * World) GetAccount(name string) (account * Account) {
-    account, ok := me.accountmap[name];
-    if !ok {
-        return nil
-    }
-    return account
-} 
+func (me *World) GetAccount(name string) (account *Account) {
+	account, ok := me.accountmap[name]
+	if !ok {
+		return nil
+	}
+	return account
+}
 
 // Loads an account to be used with this world. Characters will be linked.
 // If the account was already loaded, returns that in stead.
-func (me * World) LoadAccount(name string) (account *Account, err error) {
-    account = me.GetAccount(name)
-    if (account != nil) {
-        return account, nil
-    }
-    
-    account, err = LoadAccount(me.dirname, name);
-    if err != nil {
-        return account, err
-    }
-    me.accountmap[account.Name] = account
-    return account, nil
+func (me *World) LoadAccount(name string) (account *Account, err error) {
+	account = me.GetAccount(name)
+	if account != nil {
+		return account, nil
+	}
+
+	account, err = LoadAccount(me.dirname, name)
+	if err != nil {
+		return account, err
+	}
+	me.accountmap[account.Name] = account
+	return account, nil
 }
 
 // Removes an account from this world by name.
-func (me * World) RemoveAccount(name string) {
-    _, have := me.accountmap[name]
-    if (!have) {
-        return
-    }    
-    delete(me.accountmap, name)
+func (me *World) RemoveAccount(name string) {
+	_, have := me.accountmap[name]
+	if !have {
+		return
+	}
+	delete(me.accountmap, name)
 }
 
 // Default world pointer
-var DefaultWorld * World
-
+var DefaultWorld *World
 
 // Returns an item that has already been loaded or nil if not found
-func (me * World) GetItem(id string) (item * Item) {
-    item, ok := me.itemmap[id]
-    if !ok {
-        return nil
-    }
-    return item
-} 
-
-// Loads an item to be used with this world. 
+func (me *World) GetItem(id string) (item *Item) {
+	item, ok := me.itemmap[id]
+	if !ok {
+		return nil
+	}
+	return item
+}
+
+// Loads an item to be used with this world.
 // If the item was already loaded, returns that in stead.
-func (me * World) LoadItem(id string) (item *Item, err error) {
-    item = me.GetItem(id)
-    
-    if (item != nil) {
-        return item, nil
-    }
-    
-    item, err = LoadItem(me.dirname, id);
-    if err != nil {
-        return item, err
-    }
-    me.itemmap[item.ID] = item
-    return item, nil
+func (me *World) LoadItem(id string) (item *Item, err error) {
+	item = me.GetItem(id)
+
+	if item != nil {
+		return item, nil
+	}
+
+	item, err = LoadItem(me.dirname, id)
+	if err != nil {
+		return item, err
+	}
+	me.itemmap[item.ID] = item
+	return item, nil
 }
 
 // Removes an item from this world by ID.
-func (me * World) RemoveItem(id string) {
-    _, have := me.itemmap[id]
-    if (!have) {
-        return
-    }    
-    delete(me.itemmap, id)
+func (me *World) RemoveItem(id string) {
+	_, have := me.itemmap[id]
+	if !have {
+		return
+	}
+	delete(me.itemmap, id)
 }
 
-
 // Returns a Room that has already been loaded or nil if not found
-func (me * World) GetRoom(id string) (room * Room) {
-    room, ok := me.roommap[id]
-    if !ok {
-        return nil
-    }
-    return room
-} 
-
-
+func (me *World) GetRoom(id string) (room *Room) {
+	room, ok := me.roommap[id]
+	if !ok {
+		return nil
+	}
+	return room
+}
 
-// Loads a Room to be used with this world. 
+// Loads a Room to be used with this world.
 // If the room was already loaded, returns that in stead.
-func (me * World) LoadRoom(id string) (room *Room, err error) {
-    room = me.GetRoom(id)
-    
-    if (room != nil) {
-        return room, nil
-    }
-    
-    room, err = LoadRoom(me.dirname, id);
-    if err != nil {
-        return room, err
-    }
-    me.roommap[room.ID] = room
-    return room, nil
+func (me *World) LoadRoom(id string) (room *Room, err error) {
+	room = me.GetRoom(id)
+
+	if room != nil {
+		return room, nil
+	}
+
+	room, err = LoadRoom(me.dirname, id)
+	if err != nil {
+		return room, err
+	}
+	me.roommap[room.ID] = room
+	return room, nil
 }
 
 // Removes an item from this world by ID.
-func (me * World) RemoveRoom(id string) {
-    _, have := me.roommap[id]
-    if (!have) {
-        return
-    }    
-    delete(me.roommap, id)
+func (me *World) RemoveRoom(id string) {
+	_, have := me.roommap[id]
+	if !have {
+		return
+	}
+	delete(me.roommap, id)
 }
-
-
-