Permalink
Browse files

Added the classic look/examine command, which can be accessed by hitting

'x'. This command creates a cursor (which moves like normal), which
takes no actions to move, and will list out any entities or interesting
tile properties at the location it is resting.
  • Loading branch information...
jcerise committed Aug 6, 2017
1 parent 7217993 commit 8ac31fe02a6134920e8f38a421003a5bd24c6651
Showing with 188 additions and 17 deletions.
  1. +80 −14 bearrogue.go
  2. +10 −0 camera/camera.go
  3. +33 −0 ecs/utils.go
  4. +45 −0 examinecursor/examinecursor.go
  5. +8 −0 gamemap/gamemap.go
  6. +12 −3 ui/messageLog.go
@@ -10,15 +10,16 @@ import (
"fmt"
"math/rand"
"strconv"
"bearrogue/examinecursor"
)
const (
WindowSizeX = 100
WindowSizeY = 35
ViewAreaX = 75
ViewAreaY = 30
MapWidth = 150
MapHeight = 150
MapWidth = 100
MapHeight = 30
Title = "BearRogue"
Font = "fonts/UbuntuMono.ttf"
FontSize = 24
@@ -37,6 +38,8 @@ var (
fieldOfView *fov.FieldOfVision
gameTurn int
messageLog ui.MessageLog
examining bool
examineCursor *examinecursor.XCursor
)
func init() {
@@ -105,6 +108,10 @@ func init() {
// Set up the messageLog, and output a "welcome" message
messageLog = ui.MessageLog{MaxLength: 100}
messageLog.InitMessages()
// Set the default examining state to false, which means movement is normal. If this is true, only the examinecursor will
// be moved, until the player cancels examine mode
examining = false
}
func main() {
@@ -113,9 +120,10 @@ func main() {
renderSideBar()
messageLog.SendMessage("You find yourself in the caverns of eternal sadness...you start to feel a little more sad.")
messageLog.PrintMessages(ViewAreaY, WindowSizeX, WindowSizeY)
renderMap()
ecs.SystemRender(entities, gameCamera, gameMap)
messageLog.PrintMessages(ViewAreaY, WindowSizeX, WindowSizeY)
for {
blt.Refresh()
@@ -151,7 +159,13 @@ func main() {
renderMap()
ecs.SystemRender(entities, gameCamera, gameMap)
messageLog.PrintMessages(ViewAreaY, WindowSizeX, WindowSizeY)
if examining {
examineCursor.Draw(gameCamera)
} else {
// Only print messages if the player is not examining
messageLog.PrintMessages(ViewAreaY, WindowSizeX, WindowSizeY)
}
renderSideBar()
}
@@ -165,6 +179,8 @@ func handleInput(key int, entity *ecs.GameEntity) {
dx, dy int
)
actionTaken := true
switch key {
case blt.TK_RIGHT, blt.TK_L:
dx, dy = 1, 0
@@ -182,25 +198,49 @@ func handleInput(key int, entity *ecs.GameEntity) {
dx, dy = -1, 1
case blt.TK_N:
dx, dy = 1, 1
case blt.TK_X:
// Look command - toggle the examining flag, and notify that this will not consume an action
actionTaken = false
examining = !examining
if player.HasComponent("position") && examining {
pos, _ := player.Components["position"].(ecs.PositionComponent)
examineCursor = &examinecursor.XCursor{X: pos.X, Y: pos.Y, Character: "_", Layer: 2}
} else {
examineCursor.Clear(gameCamera)
}
}
// Fire off the movement system
ecs.SystemMovement(entity, dx, dy, entities, gameMap, &messageLog)
if examining {
// Fire off examinecursor movement
examine(dx, dy)
} else {
// Fire off the movement system
ecs.SystemMovement(entity, dx, dy, entities, gameMap, &messageLog)
}
// Switch the game turn to the Mobs turn
gameTurn = MobTurn
// Switch the game turn to the Mobs turn, if an action was taken. Some commands, like examine, or checking inventory
// do not cost an action
if actionTaken && !examining {
gameTurn = MobTurn
}
}
func renderMap() {
// Render the game map. If a tile is blocked and blocks sight, draw a '#', if it is not blocked, and does not block
// sight, draw a '.'
// First, set the entire map to not visible. We'll decide what is visible based on the torch radius.
// In the process, clear every Tile on the map as well
for x := 0; x < gameMap.Width; x++ {
for y := 0; y < gameMap.Height; y++ {
gameMap.Tiles[x][y].Visible = false
blt.Print(x, y, " ")
// First, set the every portion of the map seen by the camera to not visible. We'll decide what is visible based on
// the torch radius. In the process, clear every camera visible Tile on the map as well
for x := 0; x < gameCamera.Width; x++ {
for y := 0; y < gameCamera.Height; y++ {
// Clear both our primary layers, so we don't get any strange artifacts from one layer or the other getting
// cleared.
for i := 0; i <= 1; i++ {
blt.Layer(i)
gameMap.Tiles[x][y].Visible = false
blt.Print(x, y, " ")
}
}
}
@@ -251,6 +291,32 @@ func renderSideBar() {
}
}
func examine(dx, dy int) {
// Examine command - Creates a new cursor, that moves independantly of the player, takes no actions, and will list
// out any entities present at the location it is position on.
examineCursor.Clear(gameCamera)
examineCursor.Move(dx, dy, ViewAreaX, ViewAreaY, gameCamera)
examineCursor.Draw(gameCamera)
if gameMap.IsVisibleOrExplored(examineCursor.X, examineCursor.Y) {
presentEntities := ecs.GetEntitiesPresentAtLocation(entities, examineCursor.X, examineCursor.Y)
if presentEntities != "" {
ui.PrintToMessageArea(presentEntities, ViewAreaY, WindowSizeX, WindowSizeY, examineCursor.Layer)
} else {
tile := gameMap.Tiles[examineCursor.X][examineCursor.Y]
if tile.IsWall() {
ui.PrintToMessageArea("A cavern wall, made of some kind of rock", ViewAreaY, WindowSizeX, WindowSizeY, examineCursor.Layer)
} else {
ui.PrintToMessageArea("A cavern floor, covered in dirt and stones", ViewAreaY, WindowSizeX, WindowSizeY, examineCursor.Layer)
}
}
} else {
ui.PrintToMessageArea("You cannot see here...", ViewAreaY, WindowSizeX, WindowSizeY, examineCursor.Layer)
}
}
/* Generator functions */
func GenerateAndPopulateCavern() (int, int, []*ecs.GameEntity) {
gameMap := gameMap.GenerateCavern()
@@ -41,3 +41,13 @@ func (c *GameCamera) ToCameraCoordinates(mapX int, mapY int) (cameraX int, camer
return x, y
}
func (c *GameCamera) ToMapCoordinates(cameraX, cameraY int) (mapX, mapY int) {
x, y := cameraX + c.X, cameraY + c.Y
if x < 0 || y < 0 || x >= c.Width || y >= c.Height {
return -1, -1
}
return x, y
}
@@ -20,6 +20,39 @@ func GetBlockingEntitiesAtLocation(entities []*GameEntity, destinationX, destina
return nil
}
func GetEntitiesPresentAtLocation(entities []*GameEntity, x, y int) string {
entitiesPresent := []string{}
for _, e := range entities {
if e != nil {
if e.HasComponents([]string{"position", "appearance"}) {
pos, _ := e.Components["position"].(PositionComponent)
appearance, _ := e.Components["appearance"].(AppearanceComponent)
if pos.X == x && pos.Y == y {
// This entity is present at the currently examined location, so add its name to the list of present
// entities
entitiesPresent = append(entitiesPresent, appearance.Name)
}
}
}
}
entitiesList := ""
if len(entitiesPresent) > 0 {
listLen := len(entitiesPresent)
for i := 0; i < len(entitiesPresent); i++ {
if listLen == 1 || i == listLen - 1 {
entitiesList += entitiesPresent[i]
} else {
entitiesList += entitiesPresent[i] + ", "
}
}
}
return entitiesList
}
func getPlayerEntity(entities []*GameEntity) *GameEntity {
// Searches through the game entity list, and returns the entity representing the player
for _, e := range entities {
@@ -0,0 +1,45 @@
package examinecursor
import (
blt "bearlibterminal"
"bearrogue/camera"
)
type XCursor struct {
X int
Y int
Character string
Layer int
}
func (c *XCursor) Move(dx, dy, maxX, maxY int, gameCamera *camera.GameCamera) {
c.X += dx
c.Y += dy
if c.X < 0 {
c.X = 0
} else if c.X >= maxX {
c.X = maxX - 2
}
if c.Y < 0 {
c.Y = 0
} else if c.Y >= maxY {
c.Y = maxY - 2
}
}
func (c *XCursor) Draw(gameCamera *camera.GameCamera) {
blt.Layer(c.Layer)
blt.Color(blt.ColorFromName("white"))
cameraX, cameraY := gameCamera.ToCameraCoordinates(c.X, c.Y)
blt.Print(cameraX, cameraY, c.Character)
}
func (c *XCursor) Clear(gameCamera *camera.GameCamera) {
layer := blt.TK_LAYER
blt.Layer(c.Layer)
cameraX, cameraY := gameCamera.ToCameraCoordinates(c.X, c.Y)
blt.Print(cameraX, cameraY, " ")
blt.Layer(layer)
}
@@ -71,3 +71,11 @@ func (m *Map) IsVisibleToPlayer(x, y int) bool {
return false
}
}
func (m *Map) IsVisibleOrExplored(x, y int) bool {
if m.Tiles[x][y].Visible || m.Tiles[x][y].Explored {
return true
} else {
return false
}
}
@@ -25,7 +25,7 @@ func (ml *MessageLog) SendMessage(message string) {
func (ml *MessageLog) PrintMessages(viewAreaY, windowSizeX, windowSizeY int) {
// Print the latest five messages from the messageLog. These will be printed in reverse order (newest at the top),
// to make it appear they are scrolling down the screen
clearMessages(viewAreaY, windowSizeX, windowSizeY)
clearMessages(viewAreaY, windowSizeX, windowSizeY, 1)
toShow := 0
@@ -44,7 +44,16 @@ func (ml *MessageLog) PrintMessages(viewAreaY, windowSizeX, windowSizeY int) {
}
}
func clearMessages(viewAreaY, windowSizeX, windowSizeY int) {
func clearMessages(viewAreaY, windowSizeX, windowSizeY, layer int) {
// Clear the message area, so our messages do not overlap
blt.ClearArea(0, viewAreaY, windowSizeX, windowSizeY-viewAreaY)
for i := 0; i <= 2; i++ {
blt.Layer(i)
blt.ClearArea(0, viewAreaY, windowSizeX, windowSizeY-viewAreaY)
}
}
func PrintToMessageArea(message string, viewAreaY, windowSizeX, windowSizeY, layer int) {
// Clear the message area, and print a single message at the top
clearMessages(viewAreaY, windowSizeX, windowSizeY, layer)
blt.Print(1, viewAreaY, message)
}

0 comments on commit 8ac31fe

Please sign in to comment.