Skip to content

Instantly share code, notes, and snippets.

@kierdavis
Created July 20, 2012 23:08
Show Gist options
  • Save kierdavis/3153789 to your computer and use it in GitHub Desktop.
Save kierdavis/3153789 to your computer and use it in GitHub Desktop.
Paste of my original Roguelike code
package main
import (
"fmt"
"github.com/kierdavis/goutil"
"github.com/nsf/termbox-go"
"math/rand"
"os"
"time"
)
const (
Up = iota
Down
Left
Right
)
type Signal chan struct{}
func (sig Signal) Trigger() {
sig <- struct{}{}
}
func (sig Signal) EmptyQueue() {
for {
select {
case <-sig:
default:
}
}
}
func RandInt(start, stop int) (result int) {
return int(rand.Int63n(int64(stop-start))) + start
}
func SetCell(x, y int, ch rune, style Style) {
termbox.SetCell(x, y, ch, style.FG, style.BG)
}
func DrawBox(startX, startY, width, height int, style Style) {
endX := startX + width - 1
endY := startY + height - 1
for x := startX + 1; x <= endX-1; x++ {
SetCell(x, startY, '-', style)
SetCell(x, endY, '-', style)
}
for y := startY + 1; y <= endY-1; y++ {
SetCell(startX, y, '|', style)
SetCell(endX, y, '|', style)
}
SetCell(startX, startY, '+', style)
SetCell(startX, endY, '+', style)
SetCell(endX, startY, '+', style)
SetCell(endX, endY, '+', style)
}
func DrawText(x, y int, style Style, s string, args ...interface{}) {
s = fmt.Sprintf(s, args...)
startX := x
for r := range util.DecodeUTF8Iter(s) {
SetCell(x, y, r, style)
x++
if x == ScreenWidth {
x = startX
}
}
}
func FillBox(startX, startY, width, height int, ch rune, style Style) {
for x := startX; x < startX+width; x++ {
for y := startY; y < startY+height; y++ {
SetCell(x, y, ch, style)
}
}
}
var TermboxIsInitialized = false
var BlinkOn = false
var (
ScreenWidth, ScreenHeight int
ScreenSize int
RightMargin, BottomMargin int
MapWidth, MapHeight int
CentreX, CentreY int
MaxRoomWidth, MaxRoomHeight int
MinRoomWidth, MinRoomHeight int
)
func CalcScreenSize() {
ScreenWidth, ScreenHeight = termbox.Size()
ScreenSize = ScreenWidth * ScreenHeight
RightMargin = ScreenWidth / 3
BottomMargin = 0
MapWidth = ScreenWidth - RightMargin
MapHeight = ScreenHeight - BottomMargin
CentreX = MapWidth / 2
CentreY = MapHeight / 2
MaxRoomWidth = MapWidth - 8
MaxRoomHeight = MapHeight - 4
MinRoomWidth = MapWidth / 2
MinRoomHeight = MapHeight / 2
}
type Style struct {
FG termbox.Attribute
BG termbox.Attribute
}
var RoomBorderStyle = Style{termbox.ColorWhite, termbox.ColorBlack}
var RoomFillStyle = Style{termbox.ColorWhite, termbox.ColorBlack}
var BackgroundStyle = Style{termbox.ColorWhite, termbox.ColorBlack}
var SidebarStyle = Style{termbox.ColorWhite, termbox.ColorBlack}
var SidebarTextStyle = Style{termbox.ColorBlack, termbox.ColorWhite}
type Entity interface {
ChangeRoom(*Room)
Draw(int, int)
Room() *Room
SetRoom(*Room)
SetX(int)
SetY(int)
X() int
Y() int
}
type SpawnableEntity interface {
Entity
RequiredDifficulty() int
}
type SpawnableMonster interface {
SpawnableEntity
}
type BaseEntity struct {
room *Room
x int
y int
}
func (entity *BaseEntity) Room() (room *Room) {
return entity.room
}
func (entity *BaseEntity) SetRoom(room *Room) {
entity.room = room
}
func (entity *BaseEntity) X() (x int) {
return entity.x
}
func (entity *BaseEntity) SetX(x int) {
entity.x = x
}
func (entity *BaseEntity) Y() (y int) {
return entity.y
}
func (entity *BaseEntity) SetY(y int) {
entity.y = y
}
type Player struct {
BaseEntity
}
func (entity *Player) ChangeRoom(to *Room) {
entity.Room().RemoveEntity(entity)
to.AddEntity(entity)
}
func (entity *Player) Draw(x, y int) {
if BlinkOn {
SetCell(x, y, '@', Style{termbox.ColorGreen, termbox.ColorBlack})
} else {
SetCell(x, y, ' ', Style{termbox.ColorGreen, termbox.ColorBlack})
}
}
func (entity *Player) Move(dx int, dy int) {
newX := entity.X() + dx
newY := entity.Y() + dy
if newX <= entity.Room().StartX {
newX = entity.Room().StartX + 1
}
if newX >= entity.Room().EndX {
newX = entity.Room().EndX - 1
}
if newY <= entity.Room().StartY {
newY = entity.Room().StartY + 1
}
if newY >= entity.Room().EndY {
newY = entity.Room().EndY - 1
}
entity.SetX(newX)
entity.SetY(newY)
}
type Coord struct {
X, Y int
}
type Level struct {
Rooms map[Coord]*Room
Entrances map[Coord][4]bool
Player *Player
Difficulty int
LX int
LY int
}
func NewLevel() (level *Level) {
level = new(Level)
level.Rooms = make(map[Coord]*Room)
level.Entrances = make(map[Coord][4]bool)
level.Difficulty = 1
level.Player = new(Player)
level.Player.SetX(CentreX)
level.Player.SetY(CentreY)
level.GetCurrentRoom().AddEntity(level.Player)
return level
}
func (level *Level) MoveRoom(dx, dy int) (room *Room) {
level.LX += dx
level.LY += dy
room = level.GetCurrentRoom()
room.Draw()
level.Player.ChangeRoom(room)
return room
}
func (level *Level) DrawSidebars() {
minimapY := ScreenHeight / 2
FillBox(MapWidth, 0, RightMargin, ScreenHeight, ' ', SidebarStyle)
FillBox(MapWidth, 0, RightMargin, minimapY, ' ', SidebarTextStyle)
for i := minimapY; i < ScreenHeight; i++ {
SetCell(MapWidth, i, '|', SidebarStyle)
}
col1 := MapWidth + 1
col2 := MapWidth + (RightMargin / 2)
DrawText(col1, 1, SidebarTextStyle, "Lx = %d", level.LX)
DrawText(col1, 2, SidebarTextStyle, "Ly = %d", level.LY)
DrawText(col1, 3, SidebarTextStyle, "Px = %d", level.Player.X())
DrawText(col1, 4, SidebarTextStyle, "Py = %d", level.Player.Y())
DrawText(col2, 1, SidebarTextStyle, "Sw = %d", ScreenWidth)
DrawText(col2, 2, SidebarTextStyle, "Sh = %d", ScreenHeight)
minimapCX := (MapWidth + (RightMargin / 2)) - 1
minimapCY := ((minimapY * 3) / 2) - 1
for coord, room := range level.Rooms {
x := minimapCX + (coord.X * 4)
y := minimapCY + (coord.Y * 3)
DrawBox(x-1, y-1, 5, 4, SidebarStyle)
if room.Entrances[Up] {
SetCell(x+1, y-1, ' ', SidebarStyle)
}
if room.Entrances[Down] {
SetCell(x+1, y+2, ' ', SidebarStyle)
}
if room.Entrances[Left] {
SetCell(x-1, y, '`', SidebarStyle)
SetCell(x-1, y+1, ',', SidebarStyle)
}
if room.Entrances[Right] {
SetCell(x+3, y, '`', SidebarStyle)
SetCell(x+3, y+1, ',', SidebarStyle)
}
for i, e := range room.Entities {
if e == level.Player {
e.Draw(x+1, y)
} else {
if i >= 5 {
continue
}
if i >= 1 {
i++
}
e.Draw(x+(i%3), y+(i/3))
}
}
}
}
func (level *Level) GetCurrentRoom() (room *Room) {
return level.GetRoom(level.LX, level.LY)
}
func (level *Level) GetRoom(x int, y int) (room *Room) {
coord := Coord{x, y}
room, ok := level.Rooms[coord]
if ok {
return room
}
room = GenerateRoom()
level.GenerateEntrances(x, y, room)
for !(room.Entrances[Up] || room.Entrances[Down] || room.Entrances[Left] || room.Entrances[Right]) {
level.GenerateEntrances(x, y, room)
}
level.Rooms[coord] = room
level.Entrances[coord] = room.Entrances
return room
}
func (level *Level) GenerateEntities() {
}
func (level *Level) GenerateEntrances(x int, y int, room *Room) {
upEntrances, ok := level.Entrances[Coord{x, y - 1}]
if ok {
room.Entrances[Up] = upEntrances[Down]
} else {
room.Entrances[Up] = RandInt(0, 2) == 0
}
downEntrances, ok := level.Entrances[Coord{x, y + 1}]
if ok {
room.Entrances[Down] = downEntrances[Up]
} else {
room.Entrances[Down] = RandInt(0, 2) == 0
}
leftEntrances, ok := level.Entrances[Coord{x - 1, y}]
if ok {
room.Entrances[Left] = leftEntrances[Right]
} else {
room.Entrances[Left] = RandInt(0, 2) == 0
}
rightEntrances, ok := level.Entrances[Coord{x + 1, y}]
if ok {
room.Entrances[Right] = rightEntrances[Left]
} else {
room.Entrances[Right] = RandInt(0, 2) == 0
}
}
type Room struct {
StartX int
StartY int
EndX int
EndY int
Width int
Height int
Entrances [4]bool
Entities []Entity
}
func GenerateRoom() (room *Room) {
room = new(Room)
room.Width = RandInt(MinRoomWidth, MaxRoomWidth)
room.Height = RandInt(MinRoomHeight, MaxRoomHeight)
room.StartX = CentreX - (room.Width / 2)
room.StartY = CentreY - (room.Height / 2)
room.EndX = room.StartX + room.Width - 1
room.EndY = room.StartY + room.Height - 1
return room
}
func (room *Room) AddEntity(entity Entity) {
room.Entities = append(room.Entities, entity)
entity.SetRoom(room)
}
func (room *Room) RemoveEntity(entity Entity) {
for i, e := range room.Entities {
if e == entity {
room.Entities = append(room.Entities[:i], room.Entities[i+1:]...)
entity.SetRoom(nil)
return
}
}
}
func (room *Room) Draw() {
FillBox(0, 0, MapWidth, MapHeight, ' ', BackgroundStyle)
DrawBox(room.StartX, room.StartY, room.Width, room.Height, RoomBorderStyle)
if room.Entrances[Up] {
SetCell(CentreX-2, room.StartY, '/', RoomBorderStyle)
SetCell(CentreX-1, room.StartY, ' ', RoomFillStyle)
SetCell(CentreX, room.StartY, ' ', RoomFillStyle)
SetCell(CentreX+1, room.StartY, ' ', RoomFillStyle)
SetCell(CentreX+2, room.StartY, '\\', RoomBorderStyle)
}
if room.Entrances[Down] {
SetCell(CentreX-2, room.EndY, '\\', RoomBorderStyle)
SetCell(CentreX-1, room.EndY, ' ', RoomFillStyle)
SetCell(CentreX, room.EndY, ' ', RoomFillStyle)
SetCell(CentreX+1, room.EndY, ' ', RoomFillStyle)
SetCell(CentreX+2, room.EndY, '/', RoomBorderStyle)
}
if room.Entrances[Left] {
SetCell(room.StartX, CentreY-2, '/', RoomBorderStyle)
SetCell(room.StartX, CentreY-1, ' ', RoomFillStyle)
SetCell(room.StartX, CentreY, ' ', RoomFillStyle)
SetCell(room.StartX, CentreY+1, ' ', RoomFillStyle)
SetCell(room.StartX, CentreY+2, '\\', RoomBorderStyle)
}
if room.Entrances[Right] {
SetCell(room.EndX, CentreY-2, '\\', RoomBorderStyle)
SetCell(room.EndX, CentreY-1, ' ', RoomFillStyle)
SetCell(room.EndX, CentreY, ' ', RoomFillStyle)
SetCell(room.EndX, CentreY+1, ' ', RoomFillStyle)
SetCell(room.EndX, CentreY+2, '/', RoomBorderStyle)
}
room.DrawContent()
}
func (room *Room) DrawContent() {
FillBox(room.StartX+1, room.StartY+1, room.Width-2, room.Height-2, ' ', RoomFillStyle)
for _, entity := range room.Entities {
entity.Draw(entity.X(), entity.Y())
}
}
func die(err error) {
if err != nil {
if TermboxIsInitialized {
termbox.Close()
}
fmt.Fprintf(os.Stderr, "Error: %s\n")
os.Exit(1)
}
}
func main() {
rand.Seed(time.Now().UnixNano())
err := termbox.Init()
die(err)
TermboxIsInitialized = true
defer termbox.Close()
CalcScreenSize()
level := NewLevel()
player := level.Player
room := level.GetCurrentRoom()
level.DrawSidebars()
room.Draw()
termbox.Flush()
blinkTicker := time.NewTicker(time.Second / 6)
eventChan := make(chan termbox.Event)
redraw := false
go func() {
for {
eventChan <- termbox.PollEvent()
}
}()
for {
if redraw {
level.DrawSidebars()
room.DrawContent()
termbox.Flush()
redraw = false
}
select {
case <-blinkTicker.C:
BlinkOn = !BlinkOn
redraw = true
case event := <-eventChan:
switch event.Type {
case termbox.EventResize:
CalcScreenSize()
redraw = true
case termbox.EventKey:
switch event.Ch {
case 'w':
if player.Y() == room.StartY+1 && player.X() >= CentreX-1 && player.X() <= CentreX+1 && room.Entrances[Up] {
room = level.MoveRoom(0, -1)
player.SetY(room.EndY - 1)
} else {
player.Move(0, -1)
}
redraw = true
case 's':
if player.Y() == room.EndY-1 && player.X() >= CentreX-1 && player.X() <= CentreX+1 && room.Entrances[Down] {
room = level.MoveRoom(0, 1)
player.SetY(room.StartY + 1)
} else {
player.Move(0, 1)
}
redraw = true
case 'a':
if player.X() == room.StartX+1 && player.Y() >= CentreY-1 && player.Y() <= CentreY+1 && room.Entrances[Left] {
room = level.MoveRoom(-1, 0)
player.SetX(room.EndX - 1)
} else {
player.Move(-1, 0)
}
redraw = true
case 'd':
if player.X() == room.EndX-1 && player.Y() >= CentreY-1 && player.Y() <= CentreY+1 && room.Entrances[Right] {
room = level.MoveRoom(1, 0)
player.SetX(room.StartX + 1)
} else {
player.Move(1, 0)
}
redraw = true
case 0:
switch event.Key {
case termbox.KeyEsc:
return
}
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment