Created
July 20, 2012 23:08
-
-
Save kierdavis/3153789 to your computer and use it in GitHub Desktop.
Paste of my original Roguelike code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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