├── client ├── .gitignore ├── config.lua ├── panel.go ├── camera.go ├── playerpanel.go ├── statspanel.go ├── viewpanel.go ├── main.go ├── chatpanel.go ├── logpanel.go ├── term.go └── game.go ├── server ├── .gitignore ├── config.lua ├── packetlogger.go ├── clientpacket.go ├── packetrouter.go ├── luabindings.go ├── main.go ├── worldsession.go ├── gameserver.go └── map ├── goland.png ├── game ├── gutil │ ├── interfaces.go │ ├── lua.go │ ├── terminal.go │ └── luaconfig.go ├── session.go ├── player.go ├── data │ └── itemdb.lua ├── gnet │ └── packet.go ├── item.go ├── unit.go ├── observer.go ├── time.go ├── inventory.go ├── map.go └── gameobject.go ├── .gitignore ├── scripts ├── system.lua ├── items.lua ├── loot.lua ├── collision.lua └── map1.lua ├── LICENSE └── README.md /client/.gitignore: -------------------------------------------------------------------------------- 1 | client 2 | 3 | *.log 4 | *.profile 5 | 6 | -------------------------------------------------------------------------------- /server/.gitignore: -------------------------------------------------------------------------------- 1 | server 2 | 3 | *.log 4 | *.profile 5 | 6 | -------------------------------------------------------------------------------- /goland.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mischief/goland/HEAD/goland.png -------------------------------------------------------------------------------- /game/gutil/interfaces.go: -------------------------------------------------------------------------------- 1 | // This file describes general interfaces that game objects 2 | // should try to take advantage of. 3 | package gutil 4 | 5 | import ( 6 | "time" 7 | ) 8 | 9 | type Updater interface { 10 | Update(delta time.Duration) 11 | } 12 | -------------------------------------------------------------------------------- /game/session.go: -------------------------------------------------------------------------------- 1 | package game 2 | 3 | import ( 4 | "github.com/mischief/goland/game/gnet" 5 | uuid "github.com/nu7hatch/gouuid" 6 | ) 7 | 8 | type Session interface { 9 | SendPacket(pk *gnet.Packet) 10 | GetPlayer() *Player 11 | ID() uuid.UUID 12 | Username() string 13 | } 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | -------------------------------------------------------------------------------- /server/config.lua: -------------------------------------------------------------------------------- 1 | config = { 2 | -- map file 3 | map = "map", 4 | scriptpath = "../scripts/?.lua", 5 | 6 | -- listen dialstring 7 | listener = "127.0.0.1:61507", 8 | 9 | -- logging & debugging 10 | logfile = "server.log", 11 | 12 | debug = "false", 13 | --cpuprofile = "server.profile", 14 | } 15 | 16 | return config 17 | -------------------------------------------------------------------------------- /client/config.lua: -------------------------------------------------------------------------------- 1 | config = { 2 | -- username 3 | username = os.getenv("USER"), -- "anonymous" .. math.random(1, 256), 4 | 5 | -- server 6 | server = "127.0.0.1:61507", 7 | 8 | -- logging & debugging 9 | logfile = "client.log", 10 | 11 | debug = "true", 12 | --cpuprofile = "client.profile", 13 | 14 | } 15 | 16 | return config 17 | 18 | -------------------------------------------------------------------------------- /server/packetlogger.go: -------------------------------------------------------------------------------- 1 | // PacketLogger: flow proc to log Packets 2 | package main 3 | 4 | import ( 5 | "github.com/trustmaster/goflow" 6 | "log" 7 | ) 8 | 9 | type PacketLogger struct { 10 | flow.Component 11 | In <-chan *ClientPacket // channel of packets to log 12 | } 13 | 14 | func (l *PacketLogger) OnIn(p *ClientPacket) { 15 | log.Printf("PacketLogger: OnIn: %s", p) 16 | } 17 | -------------------------------------------------------------------------------- /client/panel.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/errnoh/termbox/panel" 5 | "github.com/mischief/goland/game/gutil" 6 | termbox "github.com/nsf/termbox-go" 7 | ) 8 | 9 | // Interface for panels which can handle input events 10 | type InputHandler interface { 11 | HandleInput(ev termbox.Event) 12 | } 13 | 14 | type GamePanel interface { 15 | panel.Panel 16 | gutil.Updater 17 | InputHandler 18 | } 19 | -------------------------------------------------------------------------------- /game/player.go: -------------------------------------------------------------------------------- 1 | // Player is a Unit that is controllable by a client 2 | // (this should really have no distinction) 3 | package game 4 | 5 | import "encoding/gob" 6 | 7 | func init() { 8 | gob.Register(&Player{}) 9 | } 10 | 11 | type Player struct { 12 | *Unit 13 | } 14 | 15 | func NewPlayer(name string) *Player { 16 | o := NewUnit(name) 17 | o.SetGlyph(GLYPH_HUMAN) 18 | p := &Player{Unit: o} 19 | 20 | p.SetTag("player", true) 21 | return p 22 | } 23 | -------------------------------------------------------------------------------- /scripts/system.lua: -------------------------------------------------------------------------------- 1 | -- things to NOT do 2 | -- 3 | -- dont assign newindex to userdata 4 | --gameserver.onpacket = 'lol' 5 | -- 6 | -- use . not : for calling go userdata 7 | --gameserver:ANYTHING() 8 | 9 | -- item handling stuff? 10 | loot = require('loot') 11 | items = require('items') 12 | coll = require('collision') 13 | 14 | collide = coll.collide 15 | 16 | -- load our only map.. 17 | map = require('map1') 18 | 19 | map.load() 20 | 21 | -- get a debug shell after loading 22 | if gs.Debug() == true then 23 | debug.debug() 24 | end 25 | 26 | -------------------------------------------------------------------------------- /game/data/itemdb.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Item database. 3 | -- 4 | 5 | DB={ 6 | {itemid=0, name="Flag", desc="A brightly colored linen flag fixed to a steel pole.", glyph="⚑", color_fg="default", color_bg=""}, 7 | {itemid=1, name="Dagger", desc="A dull blade, 3 inches long.", glyph="†", color_fg="default", color_bg="" }, 8 | { itemid=2, name="Cast iron shield", desc="A shield made from grimy cast iron.", glyph="]", color_fg="default", color_bg="" }, 9 | { itemid=3, name="Leather Skullcap", desc="A thin leather skullcap.", glyph="∩", color_fg="yellow", color_bg="" } 10 | } 11 | 12 | return { 13 | DB=DB 14 | } 15 | -------------------------------------------------------------------------------- /game/gnet/packet.go: -------------------------------------------------------------------------------- 1 | // Packet: message type for flow procs and chanio connections 2 | package gnet 3 | 4 | import ( 5 | "encoding/gob" 6 | "fmt" 7 | ) 8 | 9 | type Packet struct { 10 | Tag string // packet tag identifying the operation 11 | Data interface{} // packet payload 12 | } 13 | 14 | func (p Packet) String() string { 15 | dat := "nil" 16 | if p.Data != nil { 17 | dat = fmt.Sprintf("%s", p.Data) 18 | } 19 | 20 | return fmt.Sprintf("(%s %s)", p.Tag, dat) 21 | } 22 | 23 | func NewPacket(tag string, data interface{}) *Packet { 24 | return &Packet{tag, data} 25 | } 26 | 27 | func init() { 28 | gob.Register(&Packet{}) 29 | } 30 | -------------------------------------------------------------------------------- /game/gutil/lua.go: -------------------------------------------------------------------------------- 1 | // provides some handy lua functions 2 | package gutil 3 | 4 | import ( 5 | "errors" 6 | "github.com/aarzilli/golua/lua" 7 | "github.com/stevedonovan/luar" 8 | ) 9 | 10 | // function that lua will call before aborting. 11 | // we override this because normally lua longjmps, 12 | // but that breaks go's defer/panic. so we just panic. 13 | func LuaAtPanic(L *lua.State) int { 14 | panic(errors.New(L.ToString(-1))) 15 | return 0 16 | } 17 | 18 | // TODO: better error handling 19 | func LuaInit() *lua.State { 20 | L := luar.Init() 21 | //L.AtPanic(LuaAtPanic) 22 | 23 | L.OpenLibs() 24 | L.DoString("math.randomseed( os.time() )") 25 | 26 | return L 27 | } 28 | -------------------------------------------------------------------------------- /server/clientpacket.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/mischief/goland/game/gnet" 6 | "log" 7 | ) 8 | 9 | type ClientPacket struct { 10 | Client *WorldSession 11 | *gnet.Packet 12 | } 13 | 14 | func (cp ClientPacket) String() string { 15 | return fmt.Sprintf("%s %s", cp.Client.Con.RemoteAddr(), cp.Packet) 16 | } 17 | 18 | func (cp *ClientPacket) Reply(pk *gnet.Packet) { 19 | log.Printf("ClientPacket: Reply: %s -> %s %s", cp.Packet, cp.Client.Con.RemoteAddr(), pk) 20 | 21 | defer func() { 22 | if err := recover(); err != nil { 23 | log.Printf("ClientPacket: Reply: error: %s", err) 24 | } 25 | }() 26 | 27 | cp.Client.ClientWChan <- pk 28 | } 29 | -------------------------------------------------------------------------------- /scripts/items.lua: -------------------------------------------------------------------------------- 1 | -- item handling junk 2 | 3 | 4 | -- make a new go game object and initialize it 5 | local new = function(name, x, y) 6 | i = object.New(name) 7 | i.SetPos(x, y) 8 | i.SetTag('visible', true) 9 | i.SetTag('gettable', true) 10 | i.SetTag('item', true) 11 | return i 12 | end 13 | 14 | -- load a table of items like 15 | -- { {'flag', 2, 4, '4'}, ... } 16 | local load = function(items) 17 | for k,v in pairs(items) do 18 | i = new(v[1], v[2], v[3]) 19 | i.SetGlyph(util.NewGlyph(v[4], v[5], v[6])) 20 | 21 | --gameserver.LuaLog(string.format("%s %d %d", i.GetName(), i.GetPos())) 22 | 23 | gs.AddObject(i) 24 | end 25 | end 26 | 27 | return { 28 | new = new, 29 | load = load, 30 | } 31 | 32 | -------------------------------------------------------------------------------- /game/item.go: -------------------------------------------------------------------------------- 1 | // Item is any construct which can be stored in a Unit's inventory 2 | // can be equipment. 3 | package game 4 | 5 | import ( 6 | "encoding/gob" 7 | "fmt" 8 | ) 9 | 10 | func init() { 11 | gob.Register(&Item{}) 12 | } 13 | 14 | type Item struct { 15 | Object // The game object? 16 | 17 | Desc string 18 | Weight int 19 | Modifier int 20 | } 21 | 22 | func NewItem(name string) *Item { 23 | i := &Item{Object: NewGameObject(name)} 24 | // i := BootstrapItem(o) 25 | // i.Tags["visible"] = true 26 | // i.Tags["gettable"] = true 27 | return i 28 | } 29 | 30 | func (i Item) String() string { 31 | return fmt.Sprintf("%s: ", 32 | i.GetName(), i.Weight, i.Modifier, i.Desc, i.Object) 33 | } 34 | -------------------------------------------------------------------------------- /game/unit.go: -------------------------------------------------------------------------------- 1 | // Unit is a non-static game object 2 | package game 3 | 4 | import ( 5 | "fmt" 6 | ) 7 | 8 | const ( 9 | DEFAULT_HP = 10 10 | ) 11 | 12 | type Unit struct { 13 | Object 14 | *Inventory 15 | 16 | Level int 17 | Hp, HpMax int 18 | } 19 | 20 | func NewUnit(name string) *Unit { 21 | u := &Unit{Level: 1, 22 | Hp: DEFAULT_HP, 23 | HpMax: DEFAULT_HP, 24 | } 25 | u.Inventory = NewInventory() 26 | 27 | ob := NewGameObject(name) 28 | u.Object = ob 29 | 30 | return u 31 | } 32 | 33 | // Checks if a Unit HasItem *Item 34 | func (u Unit) HasItem(i *Item) bool { 35 | if u.Inventory.ContainsItem(i) { 36 | return true 37 | } 38 | return false 39 | } 40 | 41 | func (u Unit) String() string { 42 | return fmt.Sprintf("%s: Hp: %d(%d) %s", u.GetName(), u.Hp, u.HpMax, u.Object) 43 | } 44 | -------------------------------------------------------------------------------- /game/gutil/terminal.go: -------------------------------------------------------------------------------- 1 | package gutil 2 | 3 | import ( 4 | termbox "github.com/nsf/termbox-go" 5 | ) 6 | 7 | var attrmap = map[string]termbox.Attribute{ 8 | // Colors 9 | "default": termbox.ColorDefault, 10 | "black": termbox.ColorBlack, 11 | "red": termbox.ColorRed, 12 | "green": termbox.ColorGreen, 13 | "yellow": termbox.ColorYellow, 14 | "blue": termbox.ColorBlue, 15 | "magenta": termbox.ColorMagenta, 16 | "cyan": termbox.ColorCyan, 17 | "white": termbox.ColorWhite, 18 | 19 | // Attributes 20 | "bold": termbox.AttrBold, 21 | "underline": termbox.AttrUnderline, 22 | "reverse": termbox.AttrReverse, 23 | } 24 | 25 | func StrToTermboxAttr(str string) termbox.Attribute { 26 | attr, ok := attrmap[str] 27 | if ok { 28 | return attr 29 | } 30 | 31 | return attrmap["default"] 32 | } 33 | -------------------------------------------------------------------------------- /game/observer.go: -------------------------------------------------------------------------------- 1 | package game 2 | 3 | import ( 4 | "container/list" 5 | "sync" 6 | ) 7 | 8 | type Subject interface { 9 | Attach(obs Observer) 10 | Detach(obs Observer) 11 | Notify() 12 | } 13 | 14 | type Observer interface { 15 | Update() 16 | } 17 | 18 | type DefaultSubject struct { 19 | sync.Mutex 20 | Observers *list.List 21 | } 22 | 23 | func NewDefaultSubject() *DefaultSubject { 24 | return &DefaultSubject{Observers: list.New()} 25 | } 26 | 27 | func (sub *DefaultSubject) Attach(obs Observer) { 28 | sub.Lock() 29 | sub.Observers.PushBack(obs) 30 | sub.Unlock() 31 | } 32 | 33 | func (sub *DefaultSubject) Detach(obs Observer) { 34 | sub.Lock() 35 | for o := sub.Observers.Front(); o != nil; o = o.Next() { 36 | if o.Value == obs { 37 | sub.Observers.Remove(o) 38 | } 39 | } 40 | sub.Unlock() 41 | } 42 | 43 | func (sub *DefaultSubject) Notify() { 44 | for s := sub.Observers.Front(); s != nil; s = s.Next() { 45 | s.Value.(Observer).Update() 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /server/packetrouter.go: -------------------------------------------------------------------------------- 1 | // PacketRouter: proc to handle actions for different known Packet tags 2 | package main 3 | 4 | import ( 5 | "github.com/trustmaster/goflow" 6 | 7 | // "log" 8 | ) 9 | 10 | type PacketRouter struct { 11 | flow.Component 12 | In <-chan *ClientPacket 13 | Log chan<- *ClientPacket 14 | 15 | world *GameServer 16 | } 17 | 18 | func NewPacketRouter(w *GameServer) *PacketRouter { 19 | pr := new(PacketRouter) 20 | 21 | pr.world = w 22 | 23 | return pr 24 | } 25 | 26 | func (pr *PacketRouter) OnIn(p *ClientPacket) { 27 | 28 | defer func() { 29 | //if err := recover(); err != nil { 30 | // log.Println("PacketRouter: OnIn: panic:", err) 31 | //} 32 | }() 33 | 34 | // log all packets 35 | pr.Log <- p 36 | 37 | pr.world.HandlePacket(p) 38 | 39 | /* 40 | switch p.Tag { 41 | case "move": 42 | v := p.Data.(game.Direction) 43 | log.Printf("PacketRouter: OnIn: %s %s %s", p.Client.Con.RemoteAddr(), p.Tag, v) 44 | default: 45 | log.Printf("PacketRouter: OnIn: unknown packet type %s", p.Tag) 46 | } 47 | */ 48 | } 49 | -------------------------------------------------------------------------------- /server/luabindings.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/aarzilli/golua/lua" 5 | "github.com/mischief/goland/game" 6 | "github.com/mischief/goland/game/gutil" 7 | "github.com/nsf/termbox-go" 8 | "github.com/stevedonovan/luar" 9 | "unicode/utf8" 10 | ) 11 | 12 | // make a new GameObject 13 | func LuaNewGameObject(name string) game.Object { 14 | return game.NewGameObject(name) 15 | } 16 | 17 | var LuaGameObjectLib luar.Map = map[string]interface{}{ 18 | "New": LuaNewGameObject, 19 | } 20 | 21 | func NewGlyph(ch string, fg string, bg string) termbox.Cell { 22 | newfg := gutil.StrToTermboxAttr(fg) 23 | newbg := gutil.StrToTermboxAttr(bg) 24 | 25 | r, _ := utf8.DecodeRuneInString(ch) 26 | 27 | newch := termbox.Cell{Ch: r, Fg: newfg, Bg: newbg} 28 | 29 | return newch 30 | } 31 | 32 | var LuaUtilLib luar.Map = map[string]interface{}{ 33 | "NewGlyph": NewGlyph, 34 | } 35 | 36 | func Lua_OpenObjectLib(L *lua.State) bool { 37 | luar.Register(L, "object", LuaGameObjectLib) 38 | luar.Register(L, "util", LuaUtilLib) 39 | 40 | return true 41 | } 42 | -------------------------------------------------------------------------------- /client/camera.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image" 5 | ) 6 | 7 | type Camera struct { 8 | Pos image.Point // center of the camera 9 | SizeRect image.Rectangle // camera's size 10 | Rect image.Rectangle // camera's bounding box 11 | } 12 | 13 | func NewCamera(rect image.Rectangle) Camera { 14 | sz := rect.Size() 15 | r := image.Rect(0, 0, sz.X, sz.Y) 16 | 17 | c := Camera{ 18 | Pos: image.ZP, 19 | SizeRect: r, 20 | Rect: r, 21 | } 22 | 23 | return c 24 | } 25 | 26 | // place the camera's center at pt 27 | func (c *Camera) SetCenter(pt image.Point) { 28 | newpos := pt.Sub(c.SizeRect.Size().Div(2)) 29 | c.Pos = pt 30 | c.Rect = image.Rect(newpos.X, newpos.Y, newpos.X+c.SizeRect.Dx(), newpos.Y+c.SizeRect.Dy()) 31 | } 32 | 33 | // 34 | func (c *Camera) Transform(pt image.Point) image.Point { 35 | return pt.Sub(c.Rect.Min) //.Add(c.Rect.Size().Div(2)) 36 | } 37 | 38 | // check if world tile pt is inside camera bounds c.Rect 39 | // FIXME 40 | func (c *Camera) ContainsWorldPoint(pt image.Point) bool { 41 | return pt.In(c.Rect) 42 | } 43 | -------------------------------------------------------------------------------- /game/time.go: -------------------------------------------------------------------------------- 1 | // Time wrapper for easy delta timers 2 | package game 3 | 4 | import ( 5 | "time" 6 | ) 7 | 8 | type DeltaTimer struct { 9 | t time.Time 10 | } 11 | 12 | func NewDeltaTimer() *DeltaTimer { 13 | return &DeltaTimer{t: time.Now()} 14 | } 15 | 16 | // Reset resets sets the time of the timer to now. 17 | func (dt *DeltaTimer) Reset() { 18 | dt.t = time.Now() 19 | } 20 | 21 | // DeltaTime returns the time between now and the last time DeltaTime was called. 22 | // If DeltaTime is called the first time, the last time is the time DeltaTimer was created. 23 | // DeltaTime also resets the timer. 24 | func (dt *DeltaTimer) DeltaTime() time.Duration { 25 | now := time.Now() 26 | deltaTime := now.Sub(dt.t) 27 | dt.t = now 28 | return deltaTime 29 | } 30 | 31 | // GetDeltaTime returns the time between now and the last time DeltaTime was called. 32 | // If DeltaTime is called the first time, the last time is the time DeltaTimer was created. 33 | // GetDeltaTime does not reset the timer. 34 | func (dt *DeltaTimer) GetDeltaTime() time.Duration { 35 | return time.Since(dt.t) 36 | } 37 | -------------------------------------------------------------------------------- /scripts/loot.lua: -------------------------------------------------------------------------------- 1 | -- loot database 2 | -- 3 | -- loot.make: 4 | -- Load a dagger, itemid(1) on a map @ pos 194, 254: 5 | -- 6 | -- items.load({loot.make(1, 194, 254)}) 7 | -- 8 | 9 | -- Add something to the package path to include the itemdb. 10 | package.path = package.path .. ";../game/data/?.lua" 11 | 12 | function file_load(location, filename) 13 | local path = location .. "/" .. filename 14 | local f = assert(io.open(path, "r")) 15 | local c = f:read "*a" 16 | 17 | f:close() 18 | 19 | return c 20 | end 21 | 22 | itemdb = require('itemdb') 23 | local DB = itemdb.DB 24 | 25 | local get_item = function(DB, itemid) 26 | return DB[itemid + 1] 27 | end 28 | -- creates an item entry to place itemid on the map at (posx, posy) 29 | local make = function(itemid, posx, posy) 30 | i = get_item(DB, itemid) 31 | return { i.name, posx, posy, i.glyph, i.color_fg, i.color_bg } 32 | end 33 | 34 | -- modifies the color of the item (useful for flags) 35 | local colorize = function(item, color) 36 | item[5] = color 37 | return item 38 | end 39 | 40 | return { 41 | make = make, 42 | colorize = colorize 43 | } 44 | -------------------------------------------------------------------------------- /client/playerpanel.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/errnoh/termbox/panel" 6 | "github.com/nsf/termbox-go" 7 | "image" 8 | "time" 9 | ) 10 | 11 | // PlayerPanel is a panel which runs the in-game chat and command input. 12 | type PlayerPanel struct { 13 | *panel.Buffered // Panel 14 | 15 | x, y int 16 | name string 17 | 18 | g *Game 19 | } 20 | 21 | func NewPlayerPanel(g *Game) *PlayerPanel { 22 | cb := &PlayerPanel{g: g} 23 | 24 | cb.HandleInput(termbox.Event{Type: termbox.EventResize}) 25 | 26 | return cb 27 | } 28 | 29 | func (c *PlayerPanel) Update(delta time.Duration) { 30 | p := c.g.GetPlayer() 31 | c.x, c.y = p.GetPos() 32 | c.name = p.GetName() 33 | } 34 | 35 | func (c *PlayerPanel) HandleInput(ev termbox.Event) { 36 | if ev.Type == termbox.EventResize { 37 | w, h := termbox.Size() 38 | r := image.Rect(1, h-2, w/2, h-1) 39 | c.Buffered = panel.NewBuffered(r, termbox.Cell{'s', termbox.ColorGreen, 0}) 40 | } 41 | } 42 | 43 | func (c *PlayerPanel) Draw() { 44 | c.Clear() 45 | str := fmt.Sprintf("User: %s Pos: %d,%d", c.name, c.x, c.y) 46 | for i, r := range str { 47 | c.SetCell(i, 0, r, termbox.ColorBlue, termbox.ColorDefault) 48 | } 49 | c.Buffered.Draw() 50 | } 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Goland Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, 7 | this list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | -------------------------------------------------------------------------------- /client/statspanel.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/errnoh/termbox/panel" 6 | "github.com/nsf/termbox-go" 7 | "image" 8 | "runtime" 9 | "time" 10 | ) 11 | 12 | const ( 13 | FPS_SAMPLES = 64 14 | ) 15 | 16 | type StatsPanel struct { 17 | *panel.Buffered 18 | 19 | samples [64]float64 20 | current int 21 | memstats runtime.MemStats 22 | 23 | fps float64 24 | } 25 | 26 | func NewStatsPanel() *StatsPanel { 27 | sp := &StatsPanel{} 28 | 29 | sp.HandleInput(termbox.Event{Type: termbox.EventResize}) 30 | 31 | return sp 32 | } 33 | 34 | func (s StatsPanel) String() string { 35 | return fmt.Sprintf("%5.2f FPS %5.2f MB %d GC %d GR", s.fps, float64(s.memstats.HeapAlloc)/1000000.0, s.memstats.NumGC, runtime.NumGoroutine()) 36 | } 37 | 38 | func (s *StatsPanel) Update(delta time.Duration) { 39 | runtime.ReadMemStats(&s.memstats) 40 | 41 | s.samples[s.current%FPS_SAMPLES] = 1.0 / delta.Seconds() 42 | s.current++ 43 | 44 | for i := 0; i < FPS_SAMPLES; i++ { 45 | s.fps += s.samples[i] 46 | } 47 | 48 | s.fps /= FPS_SAMPLES 49 | } 50 | 51 | func (s *StatsPanel) HandleInput(ev termbox.Event) { 52 | if ev.Type == termbox.EventResize { 53 | w, _ := termbox.Size() 54 | r := image.Rect(1, 1, w-1, 2) 55 | s.Buffered = panel.NewBuffered(r, termbox.Cell{'s', termbox.ColorGreen, 0}) 56 | } 57 | } 58 | 59 | func (s *StatsPanel) Draw() { 60 | w, h := termbox.Size() 61 | str := fmt.Sprintf("Terminal: %d,%d SZ %s", w, h, s) 62 | for i, r := range str { 63 | s.SetCell(i, 0, r, termbox.ColorBlue, termbox.ColorDefault) 64 | } 65 | //io.WriteString(s, s.String() + fmt.Sprintf(" %s", s.Bounds())) 66 | s.Buffered.Draw() 67 | } 68 | -------------------------------------------------------------------------------- /game/inventory.go: -------------------------------------------------------------------------------- 1 | // Inventory is a collection of items 2 | package game 3 | 4 | import ( 5 | "fmt" 6 | 7 | // uuid "github.com/nu7hatch/gouuid" 8 | ) 9 | 10 | const ( 11 | // weight? #items? 12 | DEFAULT_INVENTORY_CAP = 10 13 | ) 14 | 15 | type Inventory struct { 16 | Items map[int]*Item 17 | Capacity int 18 | } 19 | 20 | func NewInventory() *Inventory { 21 | i := &Inventory{Capacity: DEFAULT_INVENTORY_CAP, 22 | Items: make(map[int]*Item), 23 | } 24 | return i 25 | } 26 | 27 | // Returns an item with .Name == name if it exists, otherwise false 28 | func (inv Inventory) ContainsItemNamed(name string) bool { 29 | for _, i := range inv.Items { 30 | if i.GetName() == name { 31 | return true 32 | } 33 | } 34 | return false 35 | } 36 | 37 | func (inv Inventory) ContainsItem(i *Item) bool { 38 | _, exists := inv.Items[i.GetID()] 39 | return exists 40 | } 41 | 42 | func (inv Inventory) AddItem(i *Item) { 43 | inv.Items[i.GetID()] = i 44 | } 45 | 46 | // Removes an item from an Invetory yet 47 | // returns the dropped item to the caller 48 | // for further processing 49 | func (inv Inventory) DropItem(i *Item) *Item { 50 | delete(inv.Items, i.GetID()) 51 | return i 52 | } 53 | 54 | // Assumes Item exists in Inventory (or panics) 55 | func (inv Inventory) GetItemNamed(name string) *Item { 56 | for _, i := range inv.Items { 57 | if i.GetName() == name { 58 | return i 59 | } 60 | } 61 | return NewItem("error") // XXX! 62 | } 63 | 64 | func (inv Inventory) DestroyItem(i *Item) { 65 | delete(inv.Items, i.GetID()) 66 | } 67 | 68 | // Iterates over Inventory items and prints their attrs 69 | // Should intelligently handle printing items in qty > 1 70 | // assuming the items also have the same properties (modifiers, etc) 71 | func (i Inventory) String() string { 72 | return fmt.Sprintf("Inventory: %s", i.Items) 73 | } 74 | -------------------------------------------------------------------------------- /client/viewpanel.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/errnoh/termbox/panel" 5 | "github.com/nsf/termbox-go" 6 | "image" 7 | "time" 8 | ) 9 | 10 | const ( 11 | VIEW_START_X = 1 12 | VIEW_START_Y = 3 13 | VIEW_PAD_X = 1 14 | VIEW_PAD_Y = 8 15 | ) 16 | 17 | // ViewPanel holds the main viewport of the game, 18 | // and needs a camera to apply the view transformation. 19 | type ViewPanel struct { 20 | *panel.Buffered 21 | 22 | g *Game 23 | 24 | cam Camera 25 | } 26 | 27 | func NewViewPanel(g *Game) *ViewPanel { 28 | vp := &ViewPanel{g: g} 29 | 30 | vp.HandleInput(termbox.Event{Type: termbox.EventResize}) 31 | 32 | return vp 33 | } 34 | 35 | func (vp *ViewPanel) Update(delta time.Duration) { 36 | // should set camera center 37 | p := vp.g.GetPlayer() 38 | if p != nil { 39 | vp.cam.SetCenter(image.Pt(p.GetPos())) 40 | } else { 41 | vp.cam.SetCenter(image.Pt(256/2, 256/2)) 42 | } 43 | } 44 | 45 | func (vp *ViewPanel) HandleInput(ev termbox.Event) { 46 | if ev.Type == termbox.EventResize { 47 | w, h := termbox.Size() 48 | r := image.Rect(VIEW_START_X, VIEW_START_Y, w-VIEW_PAD_X, h-VIEW_PAD_Y) 49 | vp.Buffered = panel.NewBuffered(r, termbox.Cell{'s', termbox.ColorGreen, 0}) 50 | 51 | vp.cam = NewCamera(r) 52 | 53 | //vp.cam.SetCenter(image.Pt(vp.g.Player.GetPos())) 54 | } 55 | } 56 | 57 | func (vp *ViewPanel) Draw() { 58 | 59 | vp.Clear() 60 | 61 | // draw terrain 62 | if vp.g.Map != nil { 63 | for x, row := range vp.g.Map.Locations { 64 | for y, terr := range row { 65 | realpos := vp.cam.Transform(image.Pt(x, y)) 66 | if true || vp.cam.ContainsWorldPoint(realpos) { 67 | c := terr.Glyph 68 | vp.SetCell(realpos.X, realpos.Y, c.Ch, c.Fg, c.Bg) 69 | } 70 | } 71 | } 72 | } 73 | 74 | for o := range vp.g.Objects.Chan() { 75 | if o.GetTag("visible") { 76 | realpos := vp.cam.Transform(image.Pt(o.GetPos())) 77 | g := o.GetGlyph() 78 | vp.SetCell(realpos.X, realpos.Y, g.Ch, g.Fg, g.Bg) 79 | } 80 | } 81 | 82 | vp.Buffered.Draw() 83 | } 84 | -------------------------------------------------------------------------------- /scripts/collision.lua: -------------------------------------------------------------------------------- 1 | -- collision handling routines 2 | 3 | local collidefns = {} 4 | 5 | -- called when a flag hits something 6 | collidefns.flag = function(o1,o2) 7 | 8 | return true 9 | end 10 | 11 | -- called when a block hits something 12 | collidefns.block = function(o1,o2) 13 | gs.LuaLog("block collision: %s -> %s", o1.GetName(), o2.GetName()) 14 | 15 | -- if a player hits a block... 16 | if o2.GetTag("player") == true then 17 | 18 | -- find out where we should move and if something is there 19 | x1, y1 = o1.GetPos() 20 | x2, y2 = o2.GetPos() 21 | 22 | if x1 ~= x2 or y1 ~= y2 then 23 | newx = x1 - (x2 - x1) 24 | newy = y1 - (y2 - y1) 25 | 26 | gs.LuaLog("%s move to %f %f", o1.GetName(), newx, newy) 27 | o1.SetPos(newx, newy) 28 | end 29 | 30 | end 31 | 32 | return true 33 | end 34 | 35 | -- called when a player hits something 36 | collidefns.player = function(o1,o2) 37 | return true 38 | end 39 | 40 | -- find the appropriate collision handler 41 | local findcollisionfn = function(o1) 42 | fn = collidefns[o1.GetName()] 43 | 44 | -- if collision function isn't available by name of object, it might be a player 45 | if not fn and o1.GetTag("player") == true then 46 | fn = collidefns['player'] 47 | end 48 | return fn 49 | end 50 | 51 | -- collision entrypoint from go 52 | -- o1 - the object that was moving 53 | -- o2 - the object that was hit by o1 54 | local collide = function(o1, o2) 55 | gs.LuaLog("colliding %s and %s", o1.GetName(), o2.GetName()) 56 | 57 | -- get collision functions for both objects and call them 58 | fn1 = findcollisionfn(o1) 59 | fn2 = findcollisionfn(o2) 60 | if fn1 ~= nil then 61 | gs.LuaLog("collision: %s -> %s", o1.GetName(), o2.GetName()) 62 | res1 = fn1(o1, o2) 63 | end 64 | if fn2 ~= nil then 65 | gs.LuaLog("collision: %s -> %s", o2.GetName(), o1.GetName()) 66 | res2 = fn2(o2, o1) 67 | end 68 | 69 | return (fn1 and res1 or true) and (fn2 and res2 or true) 70 | 71 | end 72 | 73 | return { 74 | collide = collide, 75 | findfn = findcollisionfn, 76 | fns = collidefns, 77 | } 78 | -------------------------------------------------------------------------------- /client/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "github.com/aarzilli/golua/lua" 6 | "github.com/mischief/goland/game/gutil" 7 | "log" 8 | "os" 9 | "reflect" 10 | "runtime" 11 | "runtime/pprof" 12 | ) 13 | 14 | var ( 15 | configfile = flag.String("config", "config.lua", "configuration file") 16 | 17 | Lua *lua.State 18 | ) 19 | 20 | func init() { 21 | runtime.GOMAXPROCS(runtime.NumCPU()) 22 | Lua = gutil.LuaInit() 23 | 24 | if Lua == nil { 25 | log.Fatal("main: init: Can't make lua state") 26 | } 27 | 28 | } 29 | 30 | func main() { 31 | flag.Parse() 32 | 33 | // load configuration 34 | config, err := gutil.NewLuaConfig(Lua, *configfile) 35 | if err != nil { 36 | log.Fatalf("main: Error loading configuration file %s: %s", *configfile, err) 37 | } 38 | 39 | if lf, err := config.Get("logfile", reflect.String); err != nil { 40 | log.Fatalf("main: Error reading logfile from config: %s", err) 41 | } else { 42 | file := lf.(string) 43 | f, err := os.OpenFile(file, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644) 44 | if err != nil { 45 | log.Fatal(err) 46 | } 47 | defer f.Close() 48 | log.SetOutput(f) 49 | } 50 | 51 | log.Print("main: Logging started") 52 | 53 | // log panics 54 | defer func() { 55 | if r := recover(); r != nil { 56 | log.Printf("main: Recovered from %v", r) 57 | } 58 | }() 59 | 60 | log.Printf("main: Config loaded from %s", *configfile) 61 | 62 | // dump config 63 | for ce := range config.Chan() { 64 | log.Printf("main: config: %s -> '%s'", ce.Key, ce.Value) 65 | } 66 | 67 | // enable profiling 68 | if cpuprof, err := config.Get("cpuprofile", reflect.String); err == nil { 69 | fname := cpuprof.(string) 70 | log.Printf("main: Starting profiling in file %s", fname) 71 | f, err := os.OpenFile(fname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) 72 | if err != nil { 73 | log.Printf("main: Can't open profiling file: %s", err) 74 | } 75 | 76 | pprof.StartCPUProfile(f) 77 | defer pprof.StopCPUProfile() 78 | } 79 | 80 | log.Println("Creating game instance") 81 | g := NewGame(config) 82 | 83 | g.Run() 84 | 85 | log.Println("-- Logging ended --") 86 | } 87 | -------------------------------------------------------------------------------- /server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "github.com/aarzilli/golua/lua" 6 | "github.com/mischief/goland/game/gutil" 7 | "log" 8 | "math/rand" 9 | "os" 10 | "reflect" 11 | "runtime" 12 | "runtime/pprof" 13 | "time" 14 | ) 15 | 16 | var ( 17 | configfile = flag.String("config", "config.lua", "configuration file") 18 | 19 | Lua *lua.State 20 | ) 21 | 22 | func init() { 23 | rand.Seed(time.Now().UTC().UnixNano()) 24 | runtime.GOMAXPROCS(runtime.NumCPU()) 25 | 26 | // Lua = lua.NewState() 27 | Lua = gutil.LuaInit() 28 | } 29 | 30 | func main() { 31 | flag.Parse() 32 | 33 | // load configuration 34 | config, err := gutil.NewLuaConfig(Lua, *configfile) 35 | if err != nil { 36 | log.Fatalf("Error loading configuration file %s: %s", *configfile, err) 37 | } 38 | 39 | // setup logging 40 | if lf, err := config.Get("logfile", reflect.String); err != nil { 41 | log.Printf("main: Error reading logfile from config, using stdout: %s", err) 42 | } else { 43 | // open log file 44 | file := lf.(string) 45 | f, err := os.OpenFile(file, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644) 46 | if err != nil { 47 | log.Fatal(err) 48 | } 49 | defer f.Close() 50 | log.SetOutput(f) 51 | } 52 | 53 | log.Print("main: Logging started") 54 | 55 | // log panics 56 | defer func() { 57 | if r := recover(); r != nil { 58 | log.Printf("main: Recovered from %v", r) 59 | } 60 | }() 61 | 62 | log.Printf("main: Config loaded from %s", *configfile) 63 | 64 | // dump config 65 | for ce := range config.Chan() { 66 | log.Printf("main: config: %s -> '%s'", ce.Key, ce.Value) 67 | } 68 | 69 | // enable profiling 70 | if cpuprof, err := config.Get("cpuprofile", reflect.String); err == nil { 71 | fname := cpuprof.(string) 72 | log.Printf("main: Starting profiling in file %s", fname) 73 | f, err := os.OpenFile(fname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) 74 | if err != nil { 75 | log.Printf("main: Can't open profiling file: %s", err) 76 | } 77 | 78 | pprof.StartCPUProfile(f) 79 | defer pprof.StopCPUProfile() 80 | } 81 | 82 | gs, err := NewGameServer(config, Lua) 83 | if err != nil { 84 | log.Println(err) 85 | } else { 86 | gs.Run() 87 | } 88 | 89 | log.Println("main: Logging ended") 90 | } 91 | -------------------------------------------------------------------------------- /client/chatpanel.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "github.com/errnoh/termbox/panel" 6 | "github.com/mischief/goland/game/gnet" 7 | "github.com/nsf/termbox-go" 8 | "image" 9 | "sync" 10 | "unicode/utf8" 11 | ) 12 | 13 | // ChatPanel is a panel which runs the in-game chat and command input. 14 | type ChatPanel struct { 15 | *panel.Buffered // Panel 16 | bytes.Buffer // Buffer for keyboard input 17 | m sync.Mutex 18 | Input chan termbox.Event 19 | g *Game 20 | term *Terminal 21 | } 22 | 23 | func NewChatPanel(g *Game, t *Terminal) *ChatPanel { 24 | cb := &ChatPanel{Input: make(chan termbox.Event), g: g, term: t} 25 | 26 | cb.HandleInput(termbox.Event{Type: termbox.EventResize}) 27 | 28 | return cb 29 | } 30 | 31 | func (c *ChatPanel) HandleInput(ev termbox.Event) { 32 | c.m.Lock() 33 | defer c.m.Unlock() 34 | switch ev.Type { 35 | case termbox.EventKey: 36 | if ev.Ch != 0 { 37 | c.WriteRune(ev.Ch) 38 | } else { 39 | switch ev.Key { 40 | case termbox.KeySpace: 41 | // just add a space 42 | c.WriteRune(' ') 43 | 44 | case termbox.KeyBackspace: 45 | fallthrough 46 | 47 | case termbox.KeyBackspace2: 48 | // on backspace, remove the last rune in the buffer 49 | if c.Len() > 0 { 50 | _, size := utf8.DecodeLastRune(c.Bytes()) 51 | c.Truncate(c.Len() - size) 52 | } 53 | 54 | case termbox.KeyCtrlU: 55 | // clear the buffer, like a UNIX terminal 56 | c.Reset() 57 | 58 | case termbox.KeyEnter: 59 | // input confirmed, send it 60 | if c.Len() > 0 { 61 | c.g.SendPacket(gnet.NewPacket("Tchat", c.String())) 62 | c.Reset() 63 | c.term.SetInputHandler(nil) 64 | 65 | } 66 | case termbox.KeyEsc: 67 | // input cancelled 68 | c.Reset() 69 | c.term.SetInputHandler(nil) 70 | } 71 | } 72 | case termbox.EventResize: 73 | w, h := termbox.Size() 74 | r := image.Rect(w-1, h-2, w/2, h-1) 75 | c.Buffered = panel.NewBuffered(r, termbox.Cell{'s', termbox.ColorGreen, 0}) 76 | 77 | } 78 | 79 | } 80 | 81 | func (c *ChatPanel) Draw() { 82 | c.Clear() 83 | c.m.Lock() 84 | str := "Chat: " + c.Buffer.String() 85 | c.m.Unlock() 86 | for i, r := range str { 87 | c.SetCell(i, 0, r, termbox.ColorBlue, termbox.ColorDefault) 88 | } 89 | c.Buffered.Draw() 90 | } 91 | -------------------------------------------------------------------------------- /server/worldsession.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/mischief/gochanio" 6 | "github.com/mischief/goland/game" 7 | "github.com/mischief/goland/game/gnet" 8 | uuid "github.com/nu7hatch/gouuid" 9 | "image" 10 | "log" 11 | "net" 12 | ) 13 | 14 | type WorldSession struct { 15 | Con net.Conn // connection to the client 16 | ClientRChan <-chan interface{} // client's incoming message channel 17 | ClientWChan chan<- interface{} // client's outgoing message channel 18 | ID uuid.UUID // client's id (account id?) 19 | Username string // associated username 20 | Pos image.Point // XXX: what's this for? 21 | Player game.Object // object this client controls 22 | World *GameServer // world reference 23 | } 24 | 25 | func (ws *WorldSession) String() string { 26 | return fmt.Sprintf("%s %s %s %s", ws.Con.RemoteAddr(), ws.ID, ws.Pos, ws.Player) 27 | } 28 | 29 | func NewWorldSession(w *GameServer, c net.Conn) *WorldSession { 30 | var err error 31 | var id *uuid.UUID 32 | 33 | n := new(WorldSession) 34 | 35 | n.Con = c 36 | 37 | n.ClientRChan = chanio.NewReader(n.Con) 38 | n.ClientWChan = chanio.NewWriter(n.Con) 39 | 40 | if id, err = uuid.NewV4(); err != nil { 41 | log.Printf("NewWorldSession: %s", err) 42 | return nil 43 | } else { 44 | n.ID = *id 45 | } 46 | 47 | n.World = w 48 | 49 | return n 50 | } 51 | 52 | // handle per-client packets 53 | func (ws *WorldSession) ReceiveProc() { 54 | defer func() { 55 | if err := recover(); err != nil { 56 | log.Printf("WorldSession: ReceiveProc: %s", err) 57 | } 58 | }() 59 | 60 | for x := range ws.ClientRChan { 61 | p, ok := x.(*gnet.Packet) 62 | if !ok { 63 | log.Printf("WorldSession: ReceiveProc: bad packet %#v from %s", x, ws.Con.RemoteAddr()) 64 | continue 65 | } 66 | 67 | cp := &ClientPacket{ws, p} 68 | 69 | ws.World.PacketChan <- cp 70 | } 71 | 72 | dis := &ClientPacket{ws, gnet.NewPacket("Tdisconnect", nil)} 73 | 74 | ws.World.PacketChan <- dis 75 | 76 | log.Printf("WorldSession: ReceiveProc: Channel closed %s", ws) 77 | } 78 | 79 | // send packet to this client 80 | func (ws *WorldSession) SendPacket(pk *gnet.Packet) { 81 | log.Printf("WorldSession: SendPacket: %s %s", ws.Con.RemoteAddr(), pk) 82 | 83 | defer func() { 84 | if err := recover(); err != nil { 85 | log.Printf("WorldSession: SendPacket: error: %s", err) 86 | } 87 | }() 88 | ws.ClientWChan <- pk 89 | } 90 | 91 | func (ws *WorldSession) Update() { 92 | } 93 | -------------------------------------------------------------------------------- /client/logpanel.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/errnoh/termbox/panel" 5 | "github.com/nsf/termbox-go" 6 | "image" 7 | "sync" 8 | ) 9 | 10 | const ( 11 | // Number of lines to store in the log's circular buffer 12 | nlines = 4 13 | ) 14 | 15 | // LogPanel holds a log in a circular buffer, 16 | // i.e. old entries fall off (not off the front, off the back) 17 | type LogPanel struct { 18 | *panel.Buffered 19 | sync.Mutex 20 | 21 | lines int // number of lines to show 22 | messages []string // circular buffer of messages 23 | start, count int // tracking for messages 24 | } 25 | 26 | // Construct a new LogPanel 27 | func NewLogPanel() *LogPanel { 28 | lp := &LogPanel{ 29 | lines: nlines, 30 | messages: make([]string, nlines), 31 | } 32 | 33 | lp.HandleInput(termbox.Event{Type: termbox.EventResize}) 34 | 35 | return lp 36 | } 37 | 38 | // Handle an input event 39 | // Only used for resizing panel 40 | func (lp *LogPanel) HandleInput(ev termbox.Event) { 41 | if ev.Type == termbox.EventResize { 42 | w, h := termbox.Size() 43 | r := image.Rect(1, h-7, w-1, h-3) 44 | lp.Buffered = panel.NewBuffered(r, termbox.Cell{'s', termbox.ColorGreen, 0}) 45 | } 46 | } 47 | 48 | // Draw log to internal panel 49 | func (lp *LogPanel) Draw() { 50 | lp.Lock() 51 | defer lp.Unlock() 52 | lp.Clear() 53 | 54 | fg := termbox.ColorBlue 55 | bg := termbox.ColorDefault 56 | 57 | y := 0 58 | 59 | if lp.start+lp.count > lp.lines { 60 | for _, line := range lp.messages[lp.start:] { 61 | for ic, r := range line { 62 | lp.SetCell(ic, y, r, fg, bg) 63 | } 64 | y++ 65 | } 66 | for _, line := range lp.messages[:lp.start+lp.count-lp.lines] { 67 | for ic, r := range line { 68 | lp.SetCell(ic, y, r, fg, bg) 69 | } 70 | y++ 71 | } 72 | } else { 73 | for _, line := range lp.messages[lp.start : lp.start+lp.count] { 74 | for ic, r := range line { 75 | lp.SetCell(ic, y, r, fg, bg) 76 | } 77 | y++ 78 | } 79 | } 80 | 81 | lp.Buffered.Draw() 82 | } 83 | 84 | // Write a line to the log 85 | func (lp *LogPanel) Write(p []byte) (n int, err error) { 86 | lp.Lock() 87 | defer lp.Unlock() 88 | end := (lp.start + lp.count) % lp.lines 89 | 90 | lp.messages[end] = string(p) 91 | 92 | if lp.count == lp.lines { 93 | // we're at the end, just start overwriting 94 | lp.start = (lp.start + 1) % lp.lines 95 | } else { 96 | lp.count++ 97 | } 98 | 99 | return len(p), nil 100 | } 101 | -------------------------------------------------------------------------------- /game/gutil/luaconfig.go: -------------------------------------------------------------------------------- 1 | package gutil 2 | 3 | import ( 4 | "fmt" 5 | "github.com/aarzilli/golua/lua" 6 | "github.com/stevedonovan/luar" 7 | "reflect" 8 | "strings" 9 | "sync" 10 | ) 11 | 12 | type LuaConfigElement struct { 13 | Key string 14 | Value interface{} 15 | } 16 | 17 | // LuaConfig conveniently wraps a lua file as a go map, 18 | // and config elements can be accesses through Get(). 19 | type LuaConfig struct { 20 | file string // 21 | conf map[string]interface{} 22 | m sync.Mutex 23 | } 24 | 25 | // Construct a new LuaConfig given the lua state and file name. 26 | // Returns *LuaConfig, nil on success and nil, error on error. 27 | // Expects that the file provided is a lua script that will return a 28 | // table of strings to values, for example: 29 | // config = { 30 | // key = "value", 31 | // boolean = false, 32 | // } 33 | // return config 34 | // 35 | func NewLuaConfig(lua *lua.State, file string) (*LuaConfig, error) { 36 | lc := &LuaConfig{file: file} 37 | 38 | if err := lua.DoFile(file); err != nil { 39 | return nil, fmt.Errorf("NewLuaConfig: Can't load %s: %s", file, err) 40 | } else { 41 | m := luar.CopyTableToMap(lua, nil, -1) 42 | lc.conf = m.(map[string]interface{}) 43 | } 44 | 45 | return lc, nil 46 | } 47 | 48 | // Get will walk the config for key, and assert that its value is of Kind expected. 49 | // Returns value, nil on success and nil, error on error. 50 | // Get will accept keys like "table.subtable.key", and will walk tables until it finds 51 | // the last element in the key, or abort on error. 52 | func (lc *LuaConfig) Get(key string, expected reflect.Kind) (res interface{}, err error) { 53 | lc.m.Lock() 54 | defer lc.m.Unlock() 55 | 56 | parts := strings.Split(key, ".") 57 | 58 | m := lc.conf 59 | 60 | for i, p := range parts { 61 | val, ok := m[p] 62 | if !ok { 63 | return nil, fmt.Errorf("LuaConfig: %s: no key named %s", lc.file, p) 64 | } else { 65 | kind := reflect.TypeOf(val).Kind() 66 | if i+1 == len(parts) { 67 | if kind != expected { 68 | return nil, fmt.Errorf("LuaConfig: %s: key %s is type %s, expected %s", lc.file, kind, expected) 69 | } else { 70 | return val, nil 71 | } 72 | } else { 73 | if newm, ok := val.(map[string]interface{}); ok { 74 | m = newm 75 | } else { 76 | return nil, fmt.Errorf("LuaConfig: %s: key %s is not a table", lc.file, p) 77 | } 78 | } 79 | } 80 | } 81 | 82 | return 83 | } 84 | 85 | // Gives a channel which will contain top-level config elements 86 | func (lc *LuaConfig) Chan() <-chan LuaConfigElement { 87 | lc.m.Lock() 88 | defer lc.m.Unlock() 89 | 90 | ch := make(chan LuaConfigElement, len(lc.conf)) 91 | 92 | for k, v := range lc.conf { 93 | ch <- LuaConfigElement{k, v} 94 | } 95 | 96 | close(ch) 97 | 98 | return ch 99 | } 100 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | goland 2 | ====== 3 | 4 | a rogue-like terminal game in go 5 | 6 | ## Installation: 7 | 8 | ``` 9 | go get -u github.com/mischief/goland/client 10 | go get -u github.com/mischief/goland/server 11 | ``` 12 | 13 | ## Running: 14 | Start the server: 15 | ``` 16 | cd $GOPATH/src/github.com/mischief/goland/server 17 | ./server 18 | ``` 19 | 20 | Start the client: 21 | ``` 22 | cd $GOPATH/src/github.com/mischief/goland/server 23 | ./client 24 | ``` 25 | 26 | ## Debugging: 27 | Tail the logfiles. 28 | 29 | ## Keybindings 30 | 31 | Key | Action 32 | --- | ------ 33 | `w a s d` | Move up, left, down, right respectively 34 | `h j k l` | Move left, down, up, right respectively 35 | `,` | Pickup items at your location 36 | `i` | List inventory 37 | `x` | Drop all inventory 38 | `ESC` | Quit game, or exit chat mode 39 | `` | Enter chat mode. `ESC` to exit, `` again to send, `C-u` to clear 40 | 41 | ## Other notes 42 | 43 | Currently, walking into another player will take all of their items. 44 | 45 | ## Public Access System 46 | not much to see here, but you can try before you buy (or download) 47 | 48 | ssh goland@iota.offblast.org 49 | 50 | the password is `goland` 51 | 52 | ## Screenshots 53 | 54 | maybe this should be called a 'textshot' 55 | 56 | ``` 57 | Terminal: (80,24) TERM 23.65 FPS 4.54 MB 8 GC 13 GR 58 | #######...#####################.#.#.###.###.#.#.#.#.###.###.#...#.#.#.#####.#. 59 | #######...#################.............#...........#...#.............#.#..### 60 | #######...#####################.#.#####.#.#.#.#####.#.#.#.#.#...#.#####.###### 61 | #######...###############.#.#...............#.....#.......#.......#.#.....#### 62 | #######...###############.#.#.............#.#.#.#.#.###.###.#...#.#.#.#.#.#### 63 | #######.....#...................¤.........................#.....############## 64 | #######...#...#...................†..†.....¤............#...#...############## 65 | #######.....#.............................................#.....############## 66 | #######...###################...¤......@..###################...############## 67 | #######...#############.#.#........_......###################...############## 68 | #######...#############.#.###......@......#.#.#.#.#.###.#.#.#...#.#.#####.#### 69 | #######...###########...#.#.........................#.............#.#.#.#.#... 70 | #######...#############.#.###...†¤........#####.#.###.#.#.#.#...#.#.#.#.###.## 71 | #######...#########.#.......................#...........#.......#.......#...#. 72 | #######...#########.###.#.#.###.###...#.#.###.#.###.#.#.#.#.#.#.#######.#.#.#. 73 | #######...#########...#...#...............#...#.#....................##....... 74 | #######...###########.#.#.#.#.#####...#.###.#.###.#.###.#............######.## 75 | ctf: anonymous295 has 1 points! 76 | Ouch! You bump into anonymous257. 77 | You see a flag here. 78 | You pick up a flag. 79 | [chat] anonymous295: owned noob! 80 | User: anonymous295 Pos: 128,129 Chat: woot 81 | ``` 82 | 83 | real screenshot 84 | 85 | ![goland screenshot](goland.png "goland screenshot") 86 | 87 | -------------------------------------------------------------------------------- /scripts/map1.lua: -------------------------------------------------------------------------------- 1 | -- map1.lua - first map yay 2 | 3 | collision = require('collision') 4 | 5 | -- the goods 6 | 7 | theloot = { 8 | loot.make(1, 120, 126), 9 | loot.make(2, 121, 126), 10 | loot.make(3, 122, 126) 11 | } 12 | 13 | -- flag itemid is "0" 14 | local flag_id = 0 15 | flags = { 16 | loot.colorize(loot.make(flag_id, 119, 125), "red"), 17 | loot.colorize(loot.make(flag_id, 119, 133), "red"), 18 | loot.colorize(loot.make(flag_id, 129, 125), "blue"), 19 | loot.colorize(loot.make(flag_id, 129, 133), "blue"), 20 | } 21 | 22 | blocks = { 23 | {'block', 122, 130, '¤', 'red', ''}, 24 | {'block', 124, 128, '¤', 'red', ''}, 25 | {'block', 124, 132, '¤', 'blue', ''}, 26 | {'block', 126, 130, '¤', 'blue', ''}, 27 | } 28 | 29 | score = { 30 | {'scorepoint', 97, 115, '_', 'white', 'red'}, 31 | {'scorepoint', 124, 130, '_', 'white', 'green'}, 32 | {'scorepoint', 152, 140, '_', 'white', 'blue'}, 33 | } 34 | 35 | scores = {} 36 | 37 | collision.fns.scorepoint = function(o1, o2) 38 | if o2.GetTag('player') ~= true then 39 | return false 40 | end 41 | 42 | gs.LuaLog("%s has stepped on a %s", o2.GetName(), o1.GetName()) 43 | 44 | subobjs = o2.SubObjects.GetSlice() 45 | 46 | print(type(subobjs)) 47 | slice = subobjs 48 | --gs.LuaLog("2 %s %f", type(slice), #slice) 49 | --slice = subobjs.GetSlice() 50 | print(type(slice), #slice) 51 | for k,v in pairs(getmetatable(slice)) do 52 | print(k,v) 53 | end 54 | 55 | -- does not work :( 56 | --for k,v in ipairs(slice) do 57 | -- print(k,v) 58 | --end 59 | --obj = slice[0] 60 | --print(type(obj)) 61 | --slice = assert(slice:Slice(0, #slice)) -- XXX why does this work???? 62 | -- print('slice has ', #slice) 63 | 64 | for i=2, #slice do 65 | obj = slice[i] 66 | -- print(type(obj)) 67 | 68 | -- if the player has a flag, take it and give them a point 69 | -- then spawn another flag 70 | if obj.GetName() == 'flag' then 71 | 72 | gs.LuaLog("%s has flag, removing", o2.GetName()) 73 | o2.RemoveSubObject(obj) 74 | 75 | -- move the flag to random point 76 | 77 | newx, newy = math.random(119, 129), math.random(125,133) 78 | obj.SetPos(newx, newy) 79 | obj.SetTag("visible", true) 80 | obj.SetTag("gettable", true) 81 | 82 | -- tell everyone the object changed 83 | gs.SendPkStrAll("Raction", obj) 84 | 85 | -- give player a point 86 | pname = o2.GetName() 87 | if scores[pname] ~= nil then 88 | scores[pname] = scores[pname] + 1 89 | else 90 | scores[pname] = 1 91 | end 92 | 93 | gs.SendPkStrAll("Rchat", string.format("ctf: %s has %d points!", pname, scores[pname])) 94 | 95 | 96 | end 97 | end 98 | 99 | return true 100 | end 101 | 102 | fns = {} 103 | 104 | fns.load = function() 105 | gs.LoadMap('../server/map') 106 | items.load(theloot) 107 | items.load(flags) 108 | items.load(blocks) 109 | 110 | -- load the score point 111 | for _, v in pairs(score) do 112 | sp = object.New(v[1]) 113 | sp.SetPos(v[2], v[3]) 114 | sp.SetTag('visible', true) 115 | sp.SetGlyph(util.NewGlyph(v[4], v[5], v[6])) 116 | gs.AddObject(sp) 117 | end 118 | end 119 | 120 | return fns 121 | 122 | -------------------------------------------------------------------------------- /client/term.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/nsf/termbox-go" 6 | "github.com/nsf/tulib" 7 | "log" 8 | "sync" 9 | ) 10 | 11 | type KeyHandler func(ev termbox.Event) 12 | 13 | type Terminal struct { 14 | EventChan chan termbox.Event 15 | 16 | AltInputHandler InputHandler 17 | AltChan chan termbox.Event 18 | 19 | runehandlers map[rune]KeyHandler 20 | keyhandlers map[termbox.Key]KeyHandler 21 | 22 | m sync.Mutex 23 | } 24 | 25 | func (t *Terminal) Start() error { 26 | err := termbox.Init() 27 | if err != nil { 28 | panic(err) 29 | } 30 | 31 | t.EventChan = make(chan termbox.Event) 32 | 33 | // event generator 34 | go func(e chan termbox.Event) { 35 | for { 36 | e <- termbox.PollEvent() 37 | } 38 | }(t.EventChan) 39 | 40 | t.runehandlers = make(map[rune]KeyHandler) 41 | t.keyhandlers = make(map[termbox.Key]KeyHandler) 42 | 43 | return nil 44 | } 45 | 46 | func (t *Terminal) End() { 47 | termbox.Close() 48 | } 49 | 50 | func (t *Terminal) Clear() { 51 | termbox.Clear(termbox.ColorDefault, termbox.ColorDefault) 52 | } 53 | 54 | func (t *Terminal) Flush() { 55 | termbox.Flush() 56 | } 57 | 58 | // Change the panel which handles input. 59 | // This should probably be push/pop. 60 | func (t *Terminal) SetInputHandler(ih InputHandler) (old InputHandler) { 61 | t.m.Lock() 62 | defer t.m.Unlock() 63 | 64 | log.Printf("Changing InputHandler") 65 | 66 | old = t.AltInputHandler 67 | t.AltInputHandler = ih 68 | 69 | return 70 | } 71 | 72 | func (t *Terminal) RunInputHandlers() error { 73 | select { 74 | case ev := <-t.EventChan: 75 | 76 | switch ev.Type { 77 | case termbox.EventKey: 78 | log.Printf("Keypress: %s", tulib.KeyToString(ev.Key, ev.Ch, ev.Mod)) 79 | 80 | if t.AltInputHandler != nil { 81 | log.Printf("Diverting keypress") 82 | t.AltInputHandler.HandleInput(ev) 83 | } else { 84 | 85 | if ev.Ch != 0 { // this is a character 86 | if handler, ok := t.runehandlers[ev.Ch]; ok { 87 | handler(ev) 88 | } 89 | } else { 90 | if handler, ok := t.keyhandlers[ev.Key]; ok { 91 | handler(ev) 92 | } 93 | } 94 | } 95 | case termbox.EventResize: 96 | // handle resize event 97 | t.Resize(ev.Width, ev.Height) 98 | 99 | case termbox.EventError: 100 | return fmt.Errorf("Terminal: EventError: %s", ev.Err) 101 | } 102 | 103 | default: 104 | } 105 | 106 | return nil 107 | } 108 | 109 | // Resize the terminal 110 | func (t *Terminal) Resize(neww, newh int) { 111 | } 112 | 113 | func (t *Terminal) HandleRune(r rune, h KeyHandler) { 114 | t.m.Lock() 115 | defer t.m.Unlock() 116 | t.runehandlers[r] = h 117 | } 118 | 119 | func (t *Terminal) HandleKey(k termbox.Key, h KeyHandler) { 120 | t.m.Lock() 121 | defer t.m.Unlock() 122 | t.keyhandlers[k] = h 123 | } 124 | 125 | func (t *Terminal) PrintCell(x, y int, ch termbox.Cell) { 126 | termbox.SetCell(x, y, ch.Ch, ch.Fg, ch.Bg) 127 | } 128 | 129 | func (t *Terminal) Print(x, y int, fg, bg termbox.Attribute, msg string) { 130 | for _, c := range msg { 131 | termbox.SetCell(x, y, c, fg, bg) 132 | x++ 133 | } 134 | } 135 | 136 | func (t *Terminal) Printf(x, y int, fg, bg termbox.Attribute, format string, args ...interface{}) { 137 | s := fmt.Sprintf(format, args...) 138 | t.Print(x, y, fg, bg, s) 139 | } 140 | -------------------------------------------------------------------------------- /game/map.go: -------------------------------------------------------------------------------- 1 | // Game map functions 2 | package game 3 | 4 | import ( 5 | "bufio" 6 | "encoding/gob" 7 | "fmt" 8 | "github.com/nsf/termbox-go" 9 | "github.com/nsf/tulib" 10 | "image" 11 | "log" 12 | "math/rand" 13 | "os" 14 | ) 15 | 16 | type TerrainType uint32 17 | type Action int 18 | 19 | func (a Action) String() string { 20 | return fmt.Sprintf("%s", DirTable[a]) 21 | } 22 | 23 | const ( 24 | MAP_WIDTH = 256 25 | MAP_HEIGHT = 256 26 | 27 | T_EMPTY TerrainType = iota 28 | T_WALL // can't pass/see through wall 29 | T_GROUND // passable/visible 30 | T_UNIT 31 | 32 | DIR_UP Action = iota // player movement instructions 33 | DIR_DOWN 34 | DIR_LEFT 35 | DIR_RIGHT 36 | 37 | ACTION_ITEM_PICKUP 38 | ACTION_ITEM_DROP 39 | ACTION_ITEM_LIST_INVENTORY 40 | ) 41 | 42 | var ( 43 | DirTable = map[Action]image.Point{ 44 | DIR_UP: image.Point{0, -1}, 45 | DIR_DOWN: image.Point{0, 1}, 46 | DIR_LEFT: image.Point{-1, 0}, 47 | DIR_RIGHT: image.Point{1, 0}, 48 | } 49 | 50 | GLYPH_EMPTY = termbox.Cell{Ch: ' '} 51 | GLYPH_WALL = termbox.Cell{Ch: '#', Fg: termbox.ColorDefault, Bg: termbox.ColorBlack | termbox.AttrUnderline | termbox.AttrBold} 52 | GLYPH_GROUND = termbox.Cell{Ch: '.', Fg: termbox.ColorGreen} 53 | GLYPH_FLAG = termbox.Cell{Ch: '%', Fg: termbox.ColorCyan} 54 | GLYPH_ITEM = termbox.Cell{Ch: '?', Fg: termbox.ColorCyan} 55 | GLYPH_HUMAN = termbox.Cell{Ch: '@'} 56 | 57 | // convert a rune to a terrain square 58 | glyphTable = map[rune]*Terrain{ 59 | ' ': &Terrain{GLYPH_EMPTY, T_EMPTY}, 60 | '#': &Terrain{GLYPH_WALL, T_WALL}, 61 | '.': &Terrain{GLYPH_GROUND, T_GROUND}, 62 | '@': &Terrain{GLYPH_HUMAN, T_UNIT}, 63 | } 64 | ) 65 | 66 | func init() { 67 | gob.Register(DIR_UP) 68 | gob.Register(&MapChunk{}) 69 | gob.Register(&Terrain{}) 70 | gob.Register(T_EMPTY) 71 | } 72 | 73 | func (tt *TerrainType) String() string { 74 | switch *tt { 75 | case T_EMPTY: 76 | return "empty" 77 | case T_WALL: 78 | return "wall" 79 | case T_GROUND: 80 | return "ground" 81 | case T_UNIT: 82 | return "unit" 83 | } 84 | 85 | return "unknown" 86 | } 87 | 88 | func GlyphToTerrain(g rune) (t *Terrain, ok bool) { 89 | t, ok = glyphTable[g] 90 | if !ok { 91 | t = glyphTable[' '] 92 | } 93 | return 94 | } 95 | 96 | type Terrain struct { 97 | //*GameObject 98 | Glyph termbox.Cell 99 | Type TerrainType 100 | } 101 | 102 | func (t Terrain) String() string { 103 | return fmt.Sprintf("(%c %s)", t.Glyph.Ch, t.Type) 104 | } 105 | 106 | func (t *Terrain) Draw(b *tulib.Buffer, pt image.Point) { 107 | b.Set(pt.X, pt.Y, t.Glyph) 108 | } 109 | 110 | func (t *Terrain) IsEmpty() bool { 111 | return t.Type == T_EMPTY 112 | } 113 | 114 | func (t *Terrain) IsWall() bool { 115 | return t.Type == T_WALL 116 | } 117 | 118 | func (t *Terrain) IsGround() bool { 119 | return t.Type == T_GROUND 120 | } 121 | 122 | type MapChunk struct { 123 | Size image.Point 124 | Rect image.Rectangle 125 | Locations [][]*Terrain // land features 126 | GameObjects []*GameObject // active game objects 127 | Players []*Player // active players 128 | } 129 | 130 | func (mc *MapChunk) String() string { 131 | return fmt.Sprintf("(%s %s objs %d players %d)", mc.Size, mc.Rect, len(mc.GameObjects), len(mc.Players)) 132 | } 133 | 134 | func NewMapChunk() *MapChunk { 135 | ch := MapChunk{Size: image.Pt(MAP_WIDTH, MAP_HEIGHT)} 136 | ch.Rect = image.Rect(0, 0, MAP_WIDTH, MAP_HEIGHT) 137 | 138 | ch.Locations = make([][]*Terrain, MAP_WIDTH) 139 | for row := range ch.Locations { 140 | ch.Locations[row] = make([]*Terrain, MAP_HEIGHT) 141 | } 142 | 143 | for x := 0; x < MAP_WIDTH; x++ { 144 | for y := 0; y < MAP_HEIGHT; y++ { 145 | g, _ := GlyphToTerrain('.') 146 | ch.Locations[x][y] = g 147 | } 148 | } 149 | 150 | return &ch 151 | } 152 | 153 | // return true if the map chunk has a cell with coordinates v.X, v.Y 154 | func (mc *MapChunk) HasCell(pt image.Point) bool { 155 | return pt.In(mc.Rect) 156 | } 157 | 158 | // get terrain at v. returns nil, false if it is not present 159 | func (mc *MapChunk) GetTerrain(pt image.Point) (t *Terrain, ok bool) { 160 | if ok = mc.HasCell(pt); !ok { 161 | return 162 | } 163 | return mc.Locations[pt.X][pt.Y], true 164 | } 165 | 166 | func (mc *MapChunk) CheckCollision(gob *GameObject, pos image.Point) bool { 167 | t, ok := mc.GetTerrain(pos) 168 | if ok { 169 | return !t.IsWall() 170 | } 171 | 172 | return false 173 | } 174 | 175 | // Generates an array of (x,y) tuples of open 176 | // spots on the map, called open, and selects 177 | // random(1, len(open)) 178 | func (mc *MapChunk) RandCell() image.Point { 179 | var open []image.Point 180 | 181 | for x := 0; x < MAP_WIDTH; x++ { 182 | for y := 0; y < MAP_HEIGHT; y++ { 183 | if !mc.Locations[x][y].IsWall() { 184 | open = append(open, image.Pt(x, y)) 185 | } 186 | } 187 | } 188 | 189 | // choose random location in range or len(open) 190 | i := rand.Intn(len(open)) 191 | return open[i] 192 | } 193 | 194 | func MapChunkFromFile(mapfile string) *MapChunk { 195 | mfh, err := os.Open(mapfile) 196 | if err != nil { 197 | log.Printf("Error loading map chunk file '%s': %s", mapfile, err) 198 | return nil 199 | } 200 | 201 | defer mfh.Close() 202 | 203 | r := bufio.NewReader(mfh) 204 | 205 | mc := NewMapChunk() 206 | 207 | for y := 0; y < MAP_HEIGHT; y++ { 208 | str, err := r.ReadString('\n') 209 | if err != nil { 210 | log.Printf("map read error: %s", err) 211 | return nil 212 | } 213 | 214 | for x := 0; x < MAP_WIDTH; x++ { 215 | g, ok := GlyphToTerrain(rune(str[x])) 216 | if !ok { 217 | log.Printf("invalid map tile '%c' at %s:%d:%d", str[x], mapfile, y, x) 218 | return nil 219 | } 220 | 221 | mc.Locations[x][y] = g 222 | } 223 | } 224 | 225 | return mc 226 | } 227 | -------------------------------------------------------------------------------- /game/gameobject.go: -------------------------------------------------------------------------------- 1 | // Core game object interfaces 2 | package game 3 | 4 | import ( 5 | "bytes" 6 | "encoding/gob" 7 | "fmt" 8 | "github.com/nsf/termbox-go" 9 | "github.com/nsf/tulib" 10 | // uuid "github.com/nu7hatch/gouuid" 11 | "image" 12 | //"log" 13 | "sync" 14 | "time" 15 | ) 16 | 17 | var ( 18 | idchan chan int 19 | ) 20 | 21 | func init() { 22 | gob.Register(&GameObject{}) 23 | gob.Register(&GameObjectMap{}) 24 | 25 | idchan = make(chan int) 26 | 27 | go func() { 28 | var id int 29 | id = 0 30 | for { 31 | id++ 32 | idchan <- id 33 | } 34 | }() 35 | } 36 | 37 | // TODO: remove need for this when drawing terrain with camera.Draw 38 | type Renderable interface { 39 | // Draw this object on the buffer at pos 40 | Draw(buf *tulib.Buffer, pos image.Point) 41 | } 42 | 43 | type Object interface { 44 | // Setter/getter for ID 45 | SetID(id int) 46 | GetID() int 47 | 48 | SetName(name string) 49 | GetName() string 50 | 51 | // Setter/getter for position 52 | SetPos(x, y int) bool 53 | GetPos() (x, y int) 54 | 55 | // Setter/getter for the glyph 56 | SetGlyph(termbox.Cell) 57 | GetGlyph() termbox.Cell 58 | 59 | // Setter/getter for tags 60 | SetTag(tag string, val bool) bool // returns old value 61 | GetTag(tag string) bool 62 | 63 | GetSubObjects() *GameObjectMap 64 | AddSubObject(obj Object) 65 | RemoveSubObject(obj Object) Object 66 | 67 | // update this object with delta 68 | Update(delta time.Duration) 69 | 70 | Renderable 71 | } 72 | 73 | type GameObject struct { 74 | ID int // game object id 75 | ItemID int // id if from game/data/itemdb.lua, else -1 76 | Name string // object name 77 | Pos image.Point // object world coordinates 78 | Glyph termbox.Cell // character for this object 79 | Tags map[string]bool // object tags 80 | SubObjects *GameObjectMap // objects associated with this one 81 | 82 | m sync.Mutex // lock, ew 83 | } 84 | 85 | func NewGameObject(name string) Object { 86 | gob := &GameObject{ 87 | ID: <-idchan, 88 | ItemID: -1, 89 | Name: name, 90 | Pos: image.ZP, 91 | Glyph: termbox.Cell{'¡', termbox.ColorRed, termbox.ColorDefault}, 92 | Tags: make(map[string]bool), 93 | SubObjects: NewGameObjectMap(), 94 | } 95 | 96 | return gob 97 | } 98 | 99 | func (gob GameObject) String() string { 100 | gob.m.Lock() 101 | defer gob.m.Unlock() 102 | 103 | var buf bytes.Buffer 104 | 105 | for key, value := range gob.Tags { 106 | buf.WriteString(fmt.Sprintf(" %s:%t", key, value)) 107 | } 108 | 109 | return fmt.Sprintf("%s (%c) %s %d tags:%s", gob.Name, gob.Glyph.Ch, 110 | gob.Pos, gob.ID, buf.String()) 111 | } 112 | 113 | func (gob *GameObject) SetID(id int) { 114 | gob.m.Lock() 115 | defer gob.m.Unlock() 116 | 117 | gob.ID = id 118 | } 119 | 120 | func (gob *GameObject) GetID() int { 121 | gob.m.Lock() 122 | defer gob.m.Unlock() 123 | 124 | return gob.ID 125 | } 126 | 127 | func (gob *GameObject) SetName(name string) { 128 | gob.m.Lock() 129 | defer gob.m.Unlock() 130 | 131 | gob.Name = name 132 | } 133 | 134 | func (gob *GameObject) GetName() string { 135 | gob.m.Lock() 136 | defer gob.m.Unlock() 137 | 138 | return gob.Name 139 | } 140 | 141 | func (gob *GameObject) SetPos(x, y int) bool { 142 | gob.m.Lock() 143 | defer gob.m.Unlock() 144 | 145 | gob.Pos.X = x 146 | gob.Pos.Y = y 147 | return true 148 | } 149 | 150 | func (gob *GameObject) GetPos() (x, y int) { 151 | gob.m.Lock() 152 | defer gob.m.Unlock() 153 | 154 | return gob.Pos.X, gob.Pos.Y 155 | } 156 | 157 | func (gob *GameObject) SetGlyph(glyph termbox.Cell) { 158 | gob.m.Lock() 159 | defer gob.m.Unlock() 160 | 161 | gob.Glyph = glyph 162 | } 163 | 164 | func (gob *GameObject) GetGlyph() termbox.Cell { 165 | gob.m.Lock() 166 | defer gob.m.Unlock() 167 | 168 | return gob.Glyph 169 | } 170 | 171 | func (gob *GameObject) SetTag(tag string, val bool) (old bool) { 172 | gob.m.Lock() 173 | defer gob.m.Unlock() 174 | 175 | old = gob.Tags[tag] 176 | gob.Tags[tag] = val 177 | return 178 | } 179 | 180 | func (gob *GameObject) GetTag(tag string) bool { 181 | gob.m.Lock() 182 | defer gob.m.Unlock() 183 | 184 | return gob.Tags[tag] 185 | } 186 | 187 | func (gob *GameObject) GetSubObjects() *GameObjectMap { 188 | gob.m.Lock() 189 | defer gob.m.Unlock() 190 | 191 | return gob.SubObjects 192 | } 193 | 194 | func (gob *GameObject) AddSubObject(obj Object) { 195 | gob.SubObjects.Add(obj) 196 | } 197 | 198 | func (gob *GameObject) RemoveSubObject(obj Object) Object { 199 | gob.SubObjects.RemoveObject(obj) 200 | return obj 201 | } 202 | 203 | func (gob *GameObject) Update(delta time.Duration) { 204 | } 205 | 206 | func (gob *GameObject) Draw(buf *tulib.Buffer, pos image.Point) { 207 | buf.Set(pos.X, pos.Y, gob.Glyph) 208 | } 209 | 210 | // handy interface for a collection of game objects 211 | type GameObjectMap struct { 212 | Objs map[int]Object 213 | 214 | m sync.Mutex 215 | } 216 | 217 | func NewGameObjectMap() *GameObjectMap { 218 | g := GameObjectMap{Objs: make(map[int]Object)} 219 | return &g 220 | } 221 | 222 | func (gom *GameObjectMap) Add(obj Object) { 223 | // make sure we don't double insert 224 | gom.m.Lock() 225 | if _, ok := gom.Objs[obj.GetID()]; !ok { 226 | gom.Objs[obj.GetID()] = obj 227 | } 228 | gom.m.Unlock() 229 | } 230 | 231 | func (gom *GameObjectMap) RemoveObject(obj Object) { 232 | gom.m.Lock() 233 | delete(gom.Objs, obj.GetID()) 234 | gom.m.Unlock() 235 | } 236 | 237 | func (gom *GameObjectMap) FindObjectByID(id int) Object { 238 | gom.m.Lock() 239 | defer gom.m.Unlock() 240 | 241 | o, ok := gom.Objs[id] 242 | 243 | if !ok { 244 | return nil 245 | } 246 | 247 | return o 248 | } 249 | 250 | func (gom *GameObjectMap) Chan() <-chan Object { 251 | gom.m.Lock() 252 | defer gom.m.Unlock() 253 | 254 | ch := make(chan Object, len(gom.Objs)) 255 | 256 | for _, o := range gom.Objs { 257 | ch <- o 258 | } 259 | 260 | close(ch) 261 | 262 | return ch 263 | } 264 | 265 | // return a slice containing the objects 266 | // XXX: crappy hack so lua can iterate the contents 267 | func (gom *GameObjectMap) GetSlice() []Object { 268 | gom.m.Lock() 269 | defer gom.m.Unlock() 270 | 271 | r := make([]Object, 1) 272 | for _, o := range gom.Objs { 273 | r = append(r, o) 274 | } 275 | return r 276 | } 277 | 278 | func SamePos(ob1, ob2 Object) bool { 279 | x1, y1 := ob1.GetPos() 280 | x2, y2 := ob2.GetPos() 281 | return x1 == x2 && y1 == y2 282 | } 283 | -------------------------------------------------------------------------------- /client/game.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/errnoh/termbox/panel" 5 | "github.com/mischief/gochanio" 6 | "github.com/mischief/goland/game" 7 | "github.com/mischief/goland/game/gnet" 8 | "github.com/mischief/goland/game/gutil" 9 | "github.com/nsf/termbox-go" 10 | "image" 11 | "io" 12 | "log" 13 | "net" 14 | "reflect" 15 | "sync" 16 | "time" 17 | ) 18 | 19 | const ( 20 | FPS_LIMIT = 23 21 | ) 22 | 23 | var ( 24 | CARDINALS = map[rune]game.Action{ 25 | 'w': game.DIR_UP, 26 | 'k': game.DIR_UP, 27 | 'a': game.DIR_LEFT, 28 | 'h': game.DIR_LEFT, 29 | 's': game.DIR_DOWN, 30 | 'j': game.DIR_DOWN, 31 | 'd': game.DIR_RIGHT, 32 | 'l': game.DIR_RIGHT, 33 | ',': game.ACTION_ITEM_PICKUP, 34 | 'x': game.ACTION_ITEM_DROP, 35 | 'i': game.ACTION_ITEM_LIST_INVENTORY, 36 | } 37 | ) 38 | 39 | type Game struct { 40 | player game.Object 41 | pm sync.Mutex 42 | 43 | Terminal 44 | logpanel *LogPanel 45 | chatpanel *ChatPanel 46 | 47 | panels map[string]panel.Panel 48 | mainpanel *panel.Buffered 49 | 50 | CloseChan chan bool 51 | 52 | Objects *game.GameObjectMap 53 | Map *game.MapChunk 54 | 55 | config *gutil.LuaConfig 56 | 57 | ServerCon net.Conn 58 | 59 | ServerRChan <-chan interface{} 60 | ServerWChan chan<- interface{} 61 | } 62 | 63 | func NewGame(config *gutil.LuaConfig) *Game { 64 | g := Game{config: config} 65 | g.Objects = game.NewGameObjectMap() 66 | 67 | g.CloseChan = make(chan bool, 1) 68 | 69 | g.player = game.NewGameObject("") 70 | 71 | g.mainpanel = panel.MainScreen() 72 | g.panels = make(map[string]panel.Panel) 73 | 74 | g.panels["stats"] = NewStatsPanel() 75 | g.panels["view"] = NewViewPanel(&g) 76 | g.panels["log"] = NewLogPanel() 77 | g.panels["player"] = NewPlayerPanel(&g) 78 | g.panels["chat"] = NewChatPanel(&g, &g.Terminal) 79 | 80 | g.logpanel = g.panels["log"].(*LogPanel) 81 | g.chatpanel = g.panels["chat"].(*ChatPanel) 82 | 83 | //g.chatbox = NewChatBuffer(&g, &g.Terminal) 84 | 85 | //g.Objects = append(g.Objects, g.Player.GameObject) 86 | 87 | return &g 88 | } 89 | 90 | func (g *Game) SendPacket(p *gnet.Packet) { 91 | log.Printf("Game: SendPacket: %s", p) 92 | g.ServerWChan <- p 93 | } 94 | 95 | func (g *Game) GetPlayer() game.Object { 96 | g.pm.Lock() 97 | defer g.pm.Unlock() 98 | 99 | return g.player 100 | } 101 | 102 | func (g *Game) Run() { 103 | 104 | g.Start() 105 | 106 | timer := game.NewDeltaTimer() 107 | ticker := time.NewTicker(time.Second / FPS_LIMIT) 108 | 109 | run := true 110 | 111 | for run { 112 | select { 113 | case <-ticker.C: 114 | // frame tick 115 | delta := timer.DeltaTime() 116 | 117 | if delta.Seconds() > 0.25 { 118 | delta = time.Duration(250 * time.Millisecond) 119 | } 120 | 121 | g.Update(delta) 122 | g.Draw() 123 | 124 | g.Flush() 125 | 126 | case <-g.CloseChan: 127 | run = false 128 | } 129 | } 130 | 131 | g.End() 132 | 133 | } 134 | 135 | func (g *Game) Start() { 136 | log.Print("Game: Starting") 137 | 138 | // network setup 139 | server, err := g.config.Get("server", reflect.String) 140 | if err != nil { 141 | log.Fatal("Game: Start: missing server in config: %s", err) 142 | } 143 | 144 | con, err := net.Dial("tcp", server.(string)) 145 | if err != nil { 146 | log.Fatalf("Game: Start: Dial: %s", err) 147 | } 148 | 149 | g.ServerCon = con 150 | 151 | g.ServerRChan = chanio.NewReader(g.ServerCon) 152 | g.ServerWChan = chanio.NewWriter(g.ServerCon) 153 | 154 | if g.ServerRChan == nil || g.ServerWChan == nil { 155 | log.Fatal("Game: Start: can't establish channels") 156 | } 157 | 158 | // login 159 | username, err := g.config.Get("username", reflect.String) 160 | if err != nil { 161 | log.Fatal("Game: Start: missing username in config: %s", err) 162 | } 163 | 164 | g.ServerWChan <- gnet.NewPacket("Tconnect", username) 165 | 166 | // request the map from server 167 | g.ServerWChan <- gnet.NewPacket("Tloadmap", nil) 168 | 169 | // request the object we control 170 | // XXX: the delay is to fix a bug regarding ordering of packets. 171 | // if the client gets the response to this before he is notified 172 | // that the object exists, it will barf, so we delay this request. 173 | time.AfterFunc(50*time.Millisecond, func() { 174 | g.ServerWChan <- gnet.NewPacket("Tgetplayer", nil) 175 | }) 176 | 177 | // anonymous function that reads packets from the server 178 | go func(r <-chan interface{}) { 179 | for x := range r { 180 | p, ok := x.(*gnet.Packet) 181 | if !ok { 182 | log.Printf("Game: Read: Bogus server packet %#v", x) 183 | continue 184 | } 185 | 186 | g.HandlePacket(p) 187 | } 188 | log.Println("Game: Read: Disconnected from server!") 189 | io.WriteString(g.logpanel, "Disconnected from server!") 190 | }(g.ServerRChan) 191 | 192 | // terminal/keyhandling setup 193 | g.Terminal.Start() 194 | 195 | // chat dialog 196 | //g.TermLog = NewTermLog(image.Pt(g.Terminal.Rect.Width-VIEW_START_X-VIEW_PAD_X, 5)) 197 | 198 | // ESC to quit 199 | g.HandleKey(termbox.KeyEsc, func(ev termbox.Event) { g.CloseChan <- false }) 200 | 201 | // Enter to chat 202 | g.HandleKey(termbox.KeyEnter, func(ev termbox.Event) { g.SetInputHandler(g.chatpanel) }) 203 | 204 | // convert to func SetupDirections() 205 | for k, v := range CARDINALS { 206 | func(c rune, d game.Action) { 207 | g.HandleRune(c, func(_ termbox.Event) { 208 | // lol collision 209 | p := &gnet.Packet{"Taction", CARDINALS[c]} 210 | g.SendPacket(p) 211 | offset := game.DirTable[d] 212 | g.pm.Lock() 213 | defer g.pm.Unlock() 214 | oldposx, oldposy := g.player.GetPos() 215 | newpos := image.Pt(oldposx+offset.X, oldposy+offset.Y) 216 | if g.Map.CheckCollision(nil, newpos) { 217 | g.player.SetPos(newpos.X, newpos.Y) 218 | } 219 | }) 220 | 221 | /* 222 | scale := PLAYER_RUN_SPEED 223 | upperc := unicode.ToUpper(c) 224 | g.HandleRune(upperc, func(_ termbox.Event) { 225 | for i := 0; i < scale; i++ { 226 | g.Player.Move(d) 227 | } 228 | }) 229 | */ 230 | }(k, v) 231 | } 232 | 233 | } 234 | 235 | func (g *Game) End() { 236 | log.Print("Game: Ending") 237 | g.Terminal.End() 238 | } 239 | 240 | func (g *Game) Update(delta time.Duration) { 241 | // collect stats 242 | 243 | for _, p := range g.panels { 244 | if v, ok := p.(InputHandler); ok { 245 | v.HandleInput(termbox.Event{Type: termbox.EventResize}) 246 | } 247 | 248 | if v, ok := p.(gutil.Updater); ok { 249 | v.Update(delta) 250 | } 251 | } 252 | 253 | g.RunInputHandlers() 254 | 255 | for o := range g.Objects.Chan() { 256 | o.Update(delta) 257 | } 258 | 259 | } 260 | 261 | func (g *Game) Draw() { 262 | 263 | g.Terminal.Clear() 264 | g.mainpanel.Clear() 265 | 266 | // draw panels 267 | for _, p := range g.panels { 268 | if v, ok := p.(panel.Drawer); ok { 269 | v.Draw() 270 | } 271 | } 272 | 273 | } 274 | 275 | // deal with gnet.Packets received from the server 276 | func (g *Game) HandlePacket(pk *gnet.Packet) { 277 | defer func() { 278 | if err := recover(); err != nil { 279 | log.Printf("Game: HandlePacket: %s", err) 280 | } 281 | }() 282 | 283 | log.Printf("Game: HandlePacket: %s", pk) 284 | switch pk.Tag { 285 | 286 | // Rchat: we got a text message 287 | case "Rchat": 288 | chatline := pk.Data.(string) 289 | io.WriteString(g.logpanel, chatline) 290 | 291 | // Raction: something moved on the server 292 | // Need to update the objects (sync client w/ srv) 293 | case "Raction": 294 | robj := pk.Data.(game.Object) // remote object 295 | 296 | for o := range g.Objects.Chan() { 297 | if o.GetID() == robj.GetID() { 298 | o.SetPos(robj.GetPos()) 299 | } /*else if o.GetTag("item") { 300 | item := g.Objects.FindObjectByID(o.GetID()) 301 | if item.GetTag("gettable") { 302 | item.SetPos(o.GetPos()) 303 | } else { 304 | g.Objects.RemoveObject(item) 305 | } 306 | } */ 307 | } 308 | 309 | // Rnewobject: new object we need to track 310 | case "Rnewobject": 311 | obj := pk.Data.(game.Object) 312 | g.Objects.Add(obj) 313 | 314 | // Rdelobject: some object went away 315 | case "Rdelobject": 316 | obj := pk.Data.(game.Object) 317 | g.Objects.RemoveObject(obj) 318 | 319 | // Rgetplayer: find out who we control 320 | case "Rgetplayer": 321 | playerid := pk.Data.(int) 322 | 323 | pl := g.Objects.FindObjectByID(playerid) 324 | if pl != nil { 325 | g.pm.Lock() 326 | g.player = pl 327 | g.pm.Unlock() 328 | } else { 329 | log.Printf("Game: HandlePacket: can't find our player %s", playerid) 330 | 331 | // just try again 332 | // XXX: find a better way 333 | time.AfterFunc(50*time.Millisecond, func() { 334 | g.ServerWChan <- gnet.NewPacket("Tgetplayer", nil) 335 | }) 336 | } 337 | 338 | // Rloadmap: get the map data from the server 339 | case "Rloadmap": 340 | gmap := pk.Data.(*game.MapChunk) 341 | g.Map = gmap 342 | 343 | default: 344 | log.Printf("bad packet tag %s", pk.Tag) 345 | } 346 | 347 | } 348 | -------------------------------------------------------------------------------- /server/gameserver.go: -------------------------------------------------------------------------------- 1 | // GameServer: main gameserver struct and functions 2 | // does not know or care about where Packets come from, 3 | // they just arrive on our In port. 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "github.com/aarzilli/golua/lua" 9 | "github.com/mischief/goland/game" 10 | "github.com/mischief/goland/game/gnet" 11 | "github.com/mischief/goland/game/gutil" 12 | "github.com/stevedonovan/luar" 13 | "github.com/trustmaster/goflow" 14 | "image" 15 | "log" 16 | "net" 17 | "reflect" 18 | ) 19 | 20 | var ( 21 | Actions = map[game.Action]func(*GameServer, *ClientPacket){ 22 | game.ACTION_ITEM_PICKUP: Action_ItemPickup, 23 | game.ACTION_ITEM_DROP: Action_ItemDrop, 24 | game.ACTION_ITEM_LIST_INVENTORY: Action_Inventory, 25 | } 26 | 27 | GS *GameServer 28 | ) 29 | 30 | type GameServer struct { 31 | flow.Graph // graph for our procs; see goflow 32 | 33 | Listener net.Listener // acceptor of client connections 34 | PacketChan chan *ClientPacket // channel where clients packets arrive 35 | 36 | *game.DefaultSubject 37 | 38 | Sessions map[int]*WorldSession //client list 39 | 40 | Objects *game.GameObjectMap 41 | Map *game.MapChunk 42 | 43 | config *gutil.LuaConfig 44 | 45 | Lua *lua.State 46 | } 47 | 48 | func NewGameServer(config *gutil.LuaConfig, ls *lua.State) (*GameServer, error) { 49 | gs := &GameServer{ 50 | config: config, 51 | } 52 | 53 | GS = gs 54 | 55 | gs.InitGraphState() 56 | 57 | // add nodes 58 | gs.Add(NewPacketRouter(gs), "router") 59 | gs.Add(new(PacketLogger), "logger") 60 | 61 | // connect processes 62 | // Used to be this, was throwing an error about too many arguments to gs.Graph.Connect: 63 | // gs.Connect("router", "Log", "logger", "In", make(chan *ClientPacket)) 64 | gs.Connect("router", "Log", "logger", "In") 65 | 66 | // map external ports 67 | gs.MapInPort("In", "router", "In") 68 | 69 | gs.PacketChan = make(chan *ClientPacket, 5) 70 | gs.SetInPort("In", gs.PacketChan) 71 | 72 | // observers setup 73 | gs.DefaultSubject = game.NewDefaultSubject() 74 | 75 | // objects setup 76 | gs.Objects = game.NewGameObjectMap() 77 | 78 | // lua state 79 | gs.Lua = ls 80 | 81 | return gs, nil 82 | } 83 | 84 | func (gs *GameServer) Debug() bool { 85 | if debug, err := gs.config.Get("debug", reflect.Bool); err != nil { 86 | log.Println("GameServer: 'debug' not found in config. defaulting to false") 87 | return false 88 | } else { 89 | return debug.(bool) 90 | } 91 | } 92 | 93 | func (gs *GameServer) Run() { 94 | gs.Start() 95 | 96 | for { 97 | conn, err := gs.Listener.Accept() 98 | if err != nil { 99 | log.Println("GameServer: acceptor: ", err) 100 | continue 101 | } 102 | 103 | ws := NewWorldSession(gs, conn) 104 | gs.Attach(ws) 105 | 106 | log.Printf("GameServer: New connection from %s", ws.Con.RemoteAddr()) 107 | 108 | go ws.ReceiveProc() 109 | } 110 | 111 | gs.End() 112 | } 113 | 114 | func (gs *GameServer) Start() { 115 | var err error 116 | 117 | // load assets 118 | log.Print("GameServer: Loading assets") 119 | if gs.LoadAssets() != true { 120 | log.Printf("GameServer: LoadAssets failed") 121 | return 122 | } 123 | 124 | // setup tcp listener 125 | log.Printf("GameServer: Starting listener") 126 | 127 | var dialstr string 128 | defaultdialstr := ":61507" 129 | if dialconf, err := gs.config.Get("listener", reflect.String); err != nil { 130 | log.Println("GameServer: 'listen' not found in config. defaulting to ", defaultdialstr) 131 | dialstr = defaultdialstr 132 | } else { 133 | dialstr = dialconf.(string) 134 | } 135 | 136 | if gs.Listener, err = net.Listen("tcp", dialstr); err != nil { 137 | log.Fatalf("GameServer: %s", err) 138 | } 139 | 140 | // setup goflow network 141 | log.Print("GameServer: Starting flow") 142 | 143 | flow.RunNet(gs) 144 | } 145 | 146 | func (gs *GameServer) End() { 147 | } 148 | 149 | func (gs *GameServer) LoadMap(file string) bool { 150 | if gs.Map = game.MapChunkFromFile(file); gs.Map == nil { 151 | log.Printf("GameServer: LoadMap: failed loading %s", file) 152 | return false 153 | } 154 | 155 | log.Printf("GameServer: LoadMap: loaded map %s", file) 156 | return true 157 | } 158 | 159 | func (gs *GameServer) AddObject(obj game.Object) { 160 | log.Printf("Adding object %s", obj) 161 | 162 | // tell clients about new object 163 | gs.SendPkStrAll("Rnewobject", obj) 164 | gs.Objects.Add(obj) 165 | } 166 | 167 | func (gs *GameServer) LuaLog(fmt string, args ...interface{}) { 168 | log.Printf("GameServer: Lua: "+fmt, args...) 169 | } 170 | 171 | func (gs *GameServer) GetScriptPath() string { 172 | defaultpath := "../scripts/?.lua" 173 | if scriptconf, err := gs.config.Get("scriptpath", reflect.String); err != nil { 174 | log.Printf("GameServer: GetScriptPath defaulting to %s: %s", defaultpath, err) 175 | return defaultpath 176 | } else { 177 | return scriptconf.(string) 178 | } 179 | } 180 | 181 | // TODO: move these bindings into another file 182 | func (gs *GameServer) BindLua() { 183 | luar.Register(gs.Lua, "", luar.Map{ 184 | "gs": gs, 185 | }) 186 | 187 | // add our script path here.. 188 | pkgpathscript := `package.path = package.path .. ";" .. gs.GetScriptPath() --";../?.lua"` 189 | if err := gs.Lua.DoString(pkgpathscript); err != nil { 190 | } 191 | 192 | Lua_OpenObjectLib(gs.Lua) 193 | } 194 | 195 | // load everything from lua scripts 196 | func (gs *GameServer) LoadAssets() bool { 197 | gs.BindLua() 198 | 199 | if err := gs.Lua.DoString("require('system')"); err != nil { 200 | log.Printf("GameServer: LoadAssets: %s", err) 201 | return false 202 | } 203 | 204 | return true 205 | } 206 | 207 | func (gs *GameServer) SendPkStrAll(tag string, data interface{}) { 208 | gs.SendPacketAll(gnet.NewPacket(tag, data)) 209 | } 210 | 211 | // send a packet to all clients 212 | func (gs *GameServer) SendPacketAll(pk *gnet.Packet) { 213 | gs.DefaultSubject.Lock() 214 | defer gs.DefaultSubject.Unlock() 215 | for s := gs.DefaultSubject.Observers.Front(); s != nil; s = s.Next() { 216 | s.Value.(*WorldSession).SendPacket(pk) 217 | } 218 | } 219 | 220 | func (gs *GameServer) HandlePacket(cp *ClientPacket) { 221 | 222 | switch cp.Tag { 223 | 224 | // Tchat: chat message from a client 225 | case "Tchat": 226 | // broadcast chat 227 | chatline := cp.Data.(string) 228 | gs.SendPacketAll(gnet.NewPacket("Rchat", fmt.Sprintf("[chat] %s: %s", cp.Client.Username, chatline))) 229 | 230 | // Taction: movement request 231 | case "Taction": 232 | gs.HandleActionPacket(cp) 233 | 234 | // Tconnect: user establishes new connection 235 | case "Tconnect": 236 | username, ok := cp.Data.(string) 237 | 238 | if !ok { 239 | cp.Reply(gnet.NewPacket("Rerror", "invalid username or conversion failed")) 240 | break 241 | } else { 242 | cp.Client.Username = username 243 | } 244 | 245 | // make new player for client 246 | var newplayer game.Object 247 | newplayer = game.NewGameObject(username) 248 | newplayer.SetTag("player", true) 249 | newplayer.SetTag("visible", true) 250 | 251 | // setting this lets players pick up other players, lol 252 | //newplayer.SetTag("gettable", true) 253 | newplayer.SetGlyph(game.GLYPH_HUMAN) 254 | newplayer.SetPos(256/2, 256/2) 255 | 256 | // set the session's object 257 | cp.Client.Player = newplayer 258 | 259 | // put player object in world 260 | gs.Objects.Add(newplayer) 261 | 262 | // tell client about all other objects 263 | for o := range gs.Objects.Chan() { 264 | if o.GetID() != newplayer.GetID() { 265 | cp.Reply(gnet.NewPacket("Rnewobject", o)) 266 | } 267 | } 268 | 269 | // tell all clients about the new player 270 | gs.SendPacketAll(gnet.NewPacket("Rnewobject", newplayer)) 271 | 272 | // greet our new player 273 | cp.Reply(gnet.NewPacket("Rchat", "Welcome to Goland!")) 274 | 275 | case "Tdisconnect": 276 | // notify clients this player went away 277 | Action_ItemDrop(gs, cp) 278 | gs.Objects.RemoveObject(cp.Client.Player) 279 | gs.Detach(cp.Client) 280 | gs.SendPacketAll(gnet.NewPacket("Rdelobject", cp.Client.Player)) 281 | 282 | case "Tgetplayer": 283 | if cp.Client.Player != nil { 284 | cp.Reply(gnet.NewPacket("Rgetplayer", cp.Client.Player.GetID())) 285 | } else { 286 | cp.Reply(gnet.NewPacket("Rerror", "nil Player in WorldSession")) 287 | } 288 | 289 | case "Tloadmap": 290 | cp.Reply(gnet.NewPacket("Rloadmap", gs.Map)) 291 | 292 | default: 293 | log.Printf("GameServer: HandlePacket: unknown packet type %s", cp.Tag) 294 | } 295 | } 296 | 297 | // Prevent User from re-adding / picking up item 298 | // Disassociate item with map after action successful 299 | func Action_ItemPickup(gs *GameServer, cp *ClientPacket) { 300 | p := cp.Client.Player 301 | 302 | // we assume our cp.Data is a game.Action of type ACTION_ITEM_PICKUP 303 | // act accordingly 304 | 305 | for o := range gs.Objects.Chan() { 306 | // if same pos.. and gettable 307 | if game.SamePos(o, p) && o.GetTag("gettable") { 308 | // pickup item. 309 | log.Printf("GameServer: Action_ItemPickup: %s picking up %s", p, o) 310 | o.SetTag("visible", false) 311 | o.SetTag("gettable", false) 312 | o.SetPos(0, 0) 313 | p.AddSubObject(o) 314 | 315 | // update clients with the new state of this object 316 | gs.SendPacketAll(gnet.NewPacket("Raction", o)) 317 | cp.Reply(gnet.NewPacket("Rchat", fmt.Sprintf("You pick up a %s.", o.GetName()))) 318 | } 319 | } 320 | } 321 | 322 | // Player drops the item indicated by the ID from their inventory 323 | // TODO: this drops all items right now. make it drop individual items 324 | func Action_ItemDrop(gs *GameServer, cp *ClientPacket) { 325 | p := cp.Client.Player 326 | for sub := range p.GetSubObjects().Chan() { 327 | log.Printf("GameServer: Action_ItemDrop: %s dropping %s", p, sub) 328 | 329 | // remove item from player 330 | p.RemoveSubObject(sub) 331 | // put it where the player was 332 | sub.SetPos(p.GetPos()) 333 | // make it visible 334 | sub.SetTag("visible", true) 335 | sub.SetTag("gettable", true) 336 | 337 | // update clients with the new state of this object 338 | gs.SendPacketAll(gnet.NewPacket("Raction", sub)) 339 | cp.Reply(gnet.NewPacket("Rchat", fmt.Sprintf("You drop a %s.", sub.GetName()))) 340 | } 341 | } 342 | 343 | // List items in Player's inventory 344 | func Action_Inventory(gs *GameServer, cp *ClientPacket) { 345 | plobj := cp.Client.Player 346 | 347 | inv := plobj.GetSubObjects().Chan() 348 | 349 | if len(inv) == 0 { 350 | cp.Reply(gnet.NewPacket("Rchat", "You have 0 items.")) 351 | } else { 352 | counts := make(map[string]int) 353 | for sub := range inv { 354 | n := sub.GetName() 355 | if _, ok := counts[n]; ok { 356 | counts[n]++ 357 | } else { 358 | counts[n] = 1 359 | } 360 | } 361 | 362 | for n, c := range counts { 363 | if c == 1 { 364 | cp.Reply(gnet.NewPacket("Rchat", fmt.Sprintf("You have a %s.", n))) 365 | } else { 366 | cp.Reply(gnet.NewPacket("Rchat", fmt.Sprintf("You have %d %ss.", c, n))) 367 | } 368 | 369 | } 370 | } 371 | 372 | } 373 | 374 | // Top level handler for Taction packets 375 | func (gs *GameServer) HandleActionPacket(cp *ClientPacket) { 376 | action := cp.Data.(game.Action) 377 | p := cp.Client.Player 378 | 379 | _, isdir := game.DirTable[action] 380 | if isdir { 381 | gs.HandleMovementPacket(cp) 382 | } 383 | 384 | // check if this action is in our Actions table, if so execute it 385 | if f, ok := Actions[action]; ok { 386 | f(gs, cp) 387 | } 388 | 389 | gs.SendPacketAll(gnet.NewPacket("Raction", p)) 390 | } 391 | 392 | // Handle Directionals 393 | func (gs *GameServer) HandleMovementPacket(cp *ClientPacket) { 394 | action := cp.Data.(game.Action) 395 | p := cp.Client.Player 396 | offset := game.DirTable[action] 397 | oldposx, oldposy := p.GetPos() 398 | newpos := image.Pt(oldposx+offset.X, oldposy+offset.Y) 399 | valid := true 400 | 401 | // check terrain collision 402 | if !gs.Map.CheckCollision(nil, newpos) { 403 | valid = false 404 | cp.Reply(gnet.NewPacket("Rchat", "Ouch! You bump into a wall.")) 405 | } 406 | 407 | // check gameobject collision 408 | for o := range gs.Objects.Chan() { 409 | 410 | // check if collision with Item and item name is flag 411 | px, py := o.GetPos() 412 | if px == newpos.X && py == newpos.Y { 413 | collfn := luar.NewLuaObjectFromName(gs.Lua, "collide") 414 | res, err := collfn.Call(p, o) 415 | if err != nil { 416 | log.Printf("GameServer: HandleMovementPacket: Lua error: %s", err) 417 | return 418 | } 419 | 420 | // only update position if collide returns true 421 | if thebool, ok := res.(bool); !ok || !thebool { 422 | log.Printf("GameServer: HandleMovementPacket: Lua collision failed") 423 | valid = false 424 | } else { 425 | // tell everyone that the colliders changed 426 | gs.SendPacketAll(gnet.NewPacket("Raction", o)) 427 | } 428 | 429 | if o.GetTag("player") { 430 | cp.Reply(gnet.NewPacket("Rchat", fmt.Sprintf("Ouch! You bump into %s.", o.GetName()))) 431 | 432 | // check if other player's got the goods 433 | for sub := range o.GetSubObjects().Chan() { 434 | if sub.GetTag("item") == true { 435 | // swap pop'n'lock 436 | 437 | // remove item from player 438 | swap := o.RemoveSubObject(sub) 439 | p.AddSubObject(swap) 440 | cp.Reply(gnet.NewPacket("Rchat", fmt.Sprintf("You steal a %s!", swap.GetName()))) 441 | } 442 | } 443 | } 444 | 445 | if o.GetTag("item") && o.GetTag("gettable") && valid { 446 | cp.Reply(gnet.NewPacket("Rchat", fmt.Sprintf("You see a %s here.", o.GetName()))) 447 | } 448 | } 449 | } 450 | 451 | if valid { 452 | cp.Client.Player.SetPos(newpos.X, newpos.Y) 453 | //gs.SendPacketAll(gnet.NewPacket("Raction", p)) 454 | } 455 | 456 | } 457 | -------------------------------------------------------------------------------- /server/map: -------------------------------------------------------------------------------- 1 | ################################################################################################################################################################################################################################################################ 2 | ################################################################################################################################################################################################################################################################ 3 | ################################################################################################################################################################################################################################################################ 4 | ################################################################################################################################################################################################################################################################ 5 | ################################################################################################################################################################################################################################################################ 6 | ################################################################################################################################################################################################################################################################ 7 | ################################################################################################################################################################################################################################################################ 8 | ################################################################################################################################################################################################################################################################ 9 | ################################################################################################################################################################################################################################################################ 10 | ################################################################################################################################################################################################################################################################ 11 | ################################################################################################################################################################################################################################################################ 12 | ################################################################################################################################################################################################################################################################ 13 | ################################################################################################################################################################################################################################################################ 14 | ################################################################################################################################################################################################################################################################ 15 | ################################################################################################################################################################################################################################################################ 16 | ################################################################################################################################################################################################################################################################ 17 | ################################################################################################################################################################################################################################################################ 18 | ################################################################################################################################################################################################################################################################ 19 | ################################################################################################################################################################################################################################################################ 20 | ################################################################################################################################################################################################################################################################ 21 | ################################################################################################################################################################################################################################################################ 22 | ################################################################################################################################################################################################################################################################ 23 | ################################################################################################################################################################################################################################################################ 24 | ################################################################################################################################################################################################################################################################ 25 | ################################################################################################################################################################################################################################################################ 26 | ################################################################################################################################################################################################################################################################ 27 | ################################################################################################################################################################################################################################################################ 28 | ################################################################################################################################################################################################################################################################ 29 | ################################################################################################################################################################################################################################################################ 30 | ################################################################################################################################################################################################################################################################ 31 | ################################################################################################################################################################################################################################################################ 32 | ################################################################################################################################################################################################################################################################ 33 | ################################################################################################################################################################################################################################################################ 34 | ################################################################################################################################################################################################################################################################ 35 | ################################################################################################################################################################################################################################################################ 36 | ################################################################################################################################################################################################################################################################ 37 | ################################################################################################################################################################################################################################################################ 38 | ################################################################################################################################################################################################################################################################ 39 | ################################################################################################################################################################################################################################################################ 40 | ################################################################################################################################################################################################################################################################ 41 | ################################################################################################################################################################################################################################################################ 42 | ################################################################################################################################################################################################################################################################ 43 | ################################################################################################################################################################################################################################################################ 44 | ################################################################################################################################################################################################################################################################ 45 | ################################################################################################################################################################################################################################################################ 46 | ################################################################################################################################################################################################################################################################ 47 | ################################################################################################################################################################################################################################################################ 48 | ################################################################################################################################################################################################################################################################ 49 | ################################################################################################################################################################################################################################################################ 50 | ################################################################################################################################################################################################################################################################ 51 | ################################################################################################################################################################################################################################################################ 52 | ################################################################################################################################################################################################################################################################ 53 | ################################################################################################################################################################################################################################################################ 54 | ################################################################################################################################################################################################################################################################ 55 | ################################################################################################################################################################################################################################################################ 56 | ################################################################################################################################################################################################################################################################ 57 | ################################################################################################################################################################################################################################################################ 58 | ################################################################################################################################################################################################################################################################ 59 | ################################################################################################################################################################################################################################################################ 60 | ################################################################################################################################################################################################################################################################ 61 | ################################################################################################################################################################################################################################################################ 62 | ################################################################################################################################################################################################################################################################ 63 | ################################################################################################################################################################################################################################################################ 64 | ################################################################################################################################################################################################################################################################ 65 | ################################################################################################################################################################################################################################################################ 66 | ################################################################################################################################################################################################################################################################ 67 | ################################################################################################################################################################################################################################################################ 68 | ################################################################################################################################################################################################################################################################ 69 | ################################################################################################################################################################################################################################################################ 70 | ################################################################################################################################################################################################################################################################ 71 | ################################################################################################################################################################################################################################################################ 72 | ################################################################################################################################################################################################################################################################ 73 | ################################################################################################################################################################################################################################################################ 74 | ################################################################################################################################################################################################################################################################ 75 | ################################################################################################################################################################################################################################################################ 76 | ################################################################################################################################################################################################################################################################ 77 | ################################################################################################################################################################################################################################################################ 78 | ################################################################################################################################################################################################################################################################ 79 | ################################################################################################################################################################################################################################################################ 80 | ################################################################################################################################################################################################################################################################ 81 | ################################################################################################################################################################################################################################################################ 82 | ################################################################################################################################################################################################################################################################ 83 | ################################################################################################################################################################################################################################################################ 84 | ################################################################################################################################################################################################################################################################ 85 | ################################################################################################################################################################################################################################################################ 86 | ################################################################################################################################################################################################################################################################ 87 | ################################################################################################################################################################################################################################################################ 88 | ################################################################################################################################################################################################################################################################ 89 | ################################################################################################################################################################################################################################################################ 90 | ################################################################################################################################################################################################################################################################ 91 | ################################################################################################################################################################################################################################################################ 92 | ################################################################################################################################################################################################################################################################ 93 | ################################################################################################################################################################################################################################################################ 94 | ################################################################################################################################################################################################################################################################ 95 | ################################################################################################################################################################################################################################################################ 96 | ################################################################################################################################################################################################################################################################ 97 | ################################################################################################################################################################################################################################################################ 98 | ################################################################################################################################################################################################################################################################ 99 | ################################################################################################################################################################################################################################################################ 100 | ################################################################################################################################################################################################################################################################ 101 | ################################################################################################################################################################################################################################################################ 102 | ################################################################################################################################################################################################################################################################ 103 | ################################################################################################################################################################################################################################################################ 104 | ################################################################################################################################################################################################################################################################ 105 | ################################################################################################################################################################################################################################################################ 106 | ################################################################################################################################################################################################################################################################ 107 | ################################################################################################################################################################################################################################################################ 108 | ################################################################################################################################################################################################################################################################ 109 | ################################################################################################################################################################################################################################################################ 110 | ##################################################################################################################################.###.#.#.#.#####.#.###.####################################################################################################### 111 | ##############################################################################################################################...#.#.#.......#...#.....#...##################################################################################################### 112 | ################################################################################################################################.#.#.#.#.#.#####.#.#.#.#.#.##################################################################################################### 113 | ###########################################################################################.............######################.#...#...#...#.#.............#######.###.######################################################################################### 114 | ###########################################################################################.............######################.#.###.#####.#.#.###.#####.#########.###.######################################################################################### 115 | ###########################################################################################..................................#.........#...#.....#.#.#.#.#########.......####################################################################################### 116 | ###########################################################################################.............##################.#.#.#####.#.#.###.###.#.#.#.###########.###.#.####################################################################################### 117 | ###########################################################################################.............##################.....#.#...#...........#.......#####.....#.#.#.#.##################################################################################### 118 | ###########################################################################################.............####################.###.###.#.#.#.#####.###.#.#.#######.#.#.#.#.#.##################################################################################### 119 | ###########################################################################################.............################.......#.............#.#.....#...#...#.............##################################################################################### 120 | ###########################################################################################.............##################.#.#.#.#.###.#.#.###.#.#.###...#.#.#.#.#####.#.####################################################################################### 121 | ################################################################################################.#.#####################...#.........#.....#.#.....#...............#.......##################################################################################### 122 | ################################################################################################...#####################.#.#.###.###.#.#.#.#.###.###.#...#.#.#.#####.#.#.#.##################################################################################### 123 | ################################################################################################...#################.............#...........#...#.............#.#..######.##################################################################################### 124 | ################################################################################################...#####################.#.#####.#.#.#.#####.#.#.#.#.#...#.#####.############################################################################################### 125 | ################################################################################################...###############.#.#...............#.....#.......#.......#.#.....############################################################################################# 126 | ################################################################################################...###############.#.#.............#.#.#.#.#.###.###.#...#.#.#.#.#.############################################################################################# 127 | ################################################################################################.....#.............................................#.....####################################################################################################### 128 | ################################################################################################...#...#.........................................#...#...####################################################################################################### 129 | ################################################################################################.....#.............................................#.....####################################################################################################### 130 | ################################################################################################...###################.............###################...####################################################################################################### 131 | ################################################################################################...#############.#.#...............###################...####################################################################################################### 132 | ################################################################################################...#############.#.###.............#.#.#.#.#.###.#.#.#...#.#.#####.#######.##################################################################################### 133 | ################################################################################################...###########...#.#.........................#.............#.#.#.#.#...#...##################################################################################### 134 | ################################################################################################...#############.#.###.............#####.#.###.#.#.#.#...#.#.#.#.###.#####.##################################################################################### 135 | ################################################################################################...#########.#.......................#...........#.......#.......#...#...#.#.#.#.############################################################################### 136 | ################################################################################################...#########.###.#.#.###.###...#.#.###.#.###.#.#.#.#.#.#.#######.#.#.#.#.#.#.#.#.############################################################################### 137 | ################################################################################################...#########...#...#...............#...#.#....................##.................############################################################################### 138 | ################################################################################################...###########.#.#.#.#.#####...#.###.#.###.#.###.#............######.#####.###.################################################################################# 139 | ################################################################################################.#.................#.#........................................####.....#...#.....############################################################################### 140 | ################################################################################################...........#.###.#.###.#.#.#...###.#.#.###.#.#.#.#............######.#.#####.################################################################################### 141 | ########################################################################################################.#.#.......#...................#.#...#.#.#............#....#...#.......################################################################################# 142 | ########################################################################################################.#.###.###.#######.#...#.#.###.#.#####.#.#............##.#.#.########################################################################################### 143 | ########################################################################################################.........#.#.............#...#.....#.#...#............#..#...#.#.####################################################################################### 144 | ##########################################################################################################.###.#.#####.#.#.#...#.#.#.#.#.#.#.#.#.#............####.###.#.####################################################################################### 145 | ########################################################################################################...#...........#.........................###############.#.#.....####################################################################################### 146 | ########################################################################################################.###.###.###.#.###.#..##.#.#.###.#.###.#.#####.#.#.#.#.#.#.#.###.####################################################################################### 147 | ######################################################################################################...#...#...#.#.#.....#...#.......#.....#.#.###.................#...####################################################################################### 148 | ############################################################################################################.###.#.#.#.#.#.#...#.#.#.#.#####.###.###.#.#######.#.###.########################################################################################### 149 | ##########################################################################################################...#...#.......#.......#.#.................#.#.#.#...#.#...########################################################################################### 150 | ##########################################################################################################.###.###.#.#.#.#.#...#.###.#####.#.#.#####.#.#.#.###.#.############################################################################################### 151 | ########################################################################################################...###.###.#...................#...................#...#.############################################################################################### 152 | ################################################################################################################################################################################################################################################################ 153 | ################################################################################################################################################################################################################################################################ 154 | ################################################################################################################################################################################################################################################################ 155 | ################################################################################################################################################################################################################################################################ 156 | ################################################################################################################################################################################################################################################################ 157 | ################################################################################################################################################################################################################################################################ 158 | ################################################################################################################################################################################################################################################################ 159 | ################################################################################################################################################################################################################################################################ 160 | ################################################################################################################################################################################################################################################################ 161 | ################################################################################################################################################################################################################################################################ 162 | ################################################################################################################################################################################################################################################################ 163 | ################################################################################################################################################################################################################################################################ 164 | ################################################################################################################################################################################################################################################################ 165 | ################################################################################################################################################################################################################################################################ 166 | ################################################################################################################################################################################################################################################################ 167 | ################################################################################################################################################################################################################################################################ 168 | ################################################################################################################################################################################################################################################################ 169 | ################################################################################################################################################################################################################################################################ 170 | ################################################################################################################################################################################################################################################################ 171 | ################################################################################################################################################################################################################################################################ 172 | ################################################################################################################################################################################################################################################################ 173 | ################################################################################################################################################################################################################################################################ 174 | ################################################################################################################################################################################################################################################################ 175 | ################################################################################################################################################################################################################################################################ 176 | ################################################################################################################################################################################################################################################################ 177 | ################################################################################################################################################################################################################################################################ 178 | ################################################################################################################################################################################################################################################################ 179 | ################################################################################################################################################################################################################################################################ 180 | ################################################################################################################################################################################################################################################################ 181 | ################################################################################################################################################################################################################################################################ 182 | ################################################################################################################################################################################################################################################################ 183 | ################################################################################################################################################################################################################################################################ 184 | ################################################################################################################################################################################################################################################################ 185 | ################################################################################################################################################################################################################################################################ 186 | ################################################################################################################################################################################################################################################################ 187 | ################################################################################################################################################################################################################################################################ 188 | ################################################################################################################################################################################################################################################################ 189 | ################################################################################################################################################################################################################################################################ 190 | ################################################################################################################################################################################################################################################################ 191 | ################################################################################################################################################################################################################################################################ 192 | ################################################################################################################################################################################################################################################################ 193 | ################################################################################################################################################################################################################################################################ 194 | ################################################################################################################################################################################################################################################################ 195 | ################################################################################################################################################################################################################################################################ 196 | ################################################################################################################################################################################################################################################################ 197 | ################################################################################################################################################################################################################################################################ 198 | ################################################################################################################################################################################################################################################################ 199 | ################################################################################################################################################################################################################################################################ 200 | ################################################################################################################################################################################################################################################################ 201 | ################################################################################################################################################################################################################################################################ 202 | ################################################################################################################################################################################################################################################################ 203 | ################################################################################################################################################################################################################################################################ 204 | ################################################################################################################################################################################################################################################################ 205 | ################################################################################################################################################################################################################################################################ 206 | ################################################################################################################################################################################################################################################################ 207 | ################################################################################################################################################################################################################################################################ 208 | ################################################################################################################################################################################################################################################################ 209 | ################################################################################################################################################################################################################################################################ 210 | ################################################################################################################################################################################################################################################################ 211 | ################################################################################################################################################################################################################################################################ 212 | ################################################################################################################################################################################################################################################################ 213 | ################################################################################################################################################################################################################################################################ 214 | ################################################################################################################################################################################################################################################################ 215 | ################################################################################################################################################################################################################################################################ 216 | ################################################################################################################################################################################################################################################################ 217 | ################################################################################################################################################################################################################################################################ 218 | ################################################################################################################################################################################################################################################################ 219 | ################################################################################################################################################################################################################################################################ 220 | ################################################################################################################################################################################################################################################################ 221 | ################################################################################################################################################################################################################################################################ 222 | ################################################################################################################################################################################################################################################################ 223 | ################################################################################################################################################################################################################################################################ 224 | ################################################################################################################################################################################################################################################################ 225 | ################################################################################################################################################################################################################################################################ 226 | ################################################################################################################################################################################################################################################################ 227 | ################################################################################################################################################################################################################################################################ 228 | ################################################################################################################################################################################################################################################################ 229 | ################################################################################################################################################################################################################################################################ 230 | ################################################################################################################################################################################################################################################################ 231 | ################################################################################################################################################################################################################################################################ 232 | ################################################################################################################################################################################################################################################################ 233 | ################################################################################################################################################################################################################################################################ 234 | ################################################################################################################################################################################################################################################################ 235 | ################################################################################################################################################################################################################################################################ 236 | ################################################################################################################################################################################################################################################################ 237 | ################################################################################################################################################################################################################################################################ 238 | ################################################################################################################################################################################################################################################################ 239 | ################################################################################################################################################################################################################################################################ 240 | ################################################################################################################################################################################################################################################################ 241 | ################################################################################################################################################################################################################################################################ 242 | ################################################################################################################################################################################################################################################################ 243 | ################################################################################################################################################################################################################################################################ 244 | ################################################################################################################################################################################################################################################################ 245 | ################################################################################################################################################################################################################################################################ 246 | ################################################################################################################################################################################################################################################################ 247 | ################################################################################################################################################################################################################################################################ 248 | ################################################################################################################################################################################################################################################################ 249 | ################################################################################################################################################################################################################################################################ 250 | ################################################################################################################################################################################################################################################################ 251 | ################################################################################################################################################################################################################################################################ 252 | ################################################################################################################################################################################################################################################################ 253 | ################################################################################################################################################################################################################################################################ 254 | ################################################################################################################################################################################################################################################################ 255 | ################################################################################################################################################################################################################################################################ 256 | ################################################################################################################################################################################################################################################################ 257 | 258 | --------------------------------------------------------------------------------