progress in part 5, but unresolved problems with flags

This commit is contained in:
gmzar 2019-07-24 17:03:53 -07:00
parent 696ccd216e
commit 733ffe3380
5 changed files with 116 additions and 21 deletions

View File

@ -6,20 +6,23 @@ import (
"github.com/kettek/goro" "github.com/kettek/goro"
) )
// Entity is a type that represents an active entity in the world.
type Entity struct { type Entity struct {
x, y int x, y int
rune rune rune rune
style goro.Style style goro.Style
name string
flags uint
} }
// NewEntity returns a pointer to a newly created Entity. // NewEntity returns an interface to a new populated Entity.
func NewEntity(x int, y int, r rune, s goro.Style) interfaces.Entity { func NewEntity(x int, y int, r rune, style goro.Style, name string, flags Flags) interfaces.Entity {
return &Entity{ return &Entity{
x: x, x: x,
y: y, y: y,
rune: r, rune: r,
style: s, style: style,
name: name,
flags: flags,
} }
} }
@ -34,7 +37,7 @@ func (e *Entity) X() int {
return e.x return e.x
} }
// SetX sets the entity's X value // SetX sets the entity's x value
func (e *Entity) SetX(x int) { func (e *Entity) SetX(x int) {
e.x = x e.x = x
} }
@ -65,6 +68,36 @@ func (e *Entity) Style() goro.Style {
} }
// SetStyle sets the entity's style. // SetStyle sets the entity's style.
func (e *Entity) SetStyle(s goro.Style) { func (e *Entity) SetStyle(style goro.Style) {
e.style = s e.style = style
}
// Name gets the entity's name.
func (e *Entity) Name() string {
return e.name
}
// SetName sets the entity's name.
func (e *Entity) SetName(n string) {
e.name = n
}
// Flags gets the entity's flags.
func (e *Entity) Flags() uint {
return e.flags
}
// SetFlags sets the entity's flags.
func (e *Entity) SetFlags(f uint) {
e.flags = f
}
// FindEntityAtLocation finds and returns the first entity at x and y matching the provided flags. If none exists, it returns nil.
func FindEntityAtLocation(entities []interfaces.Entity, x, y int, checkMask uint, matchFlags uint) interfaces.Entity {
for _, e := range entities {
if (e.Flags()&checkMask) == matchFlags && e.X() == x && e.Y() == y {
return e
}
}
return nil
} }

6
entity/flags.go Normal file
View File

@ -0,0 +1,6 @@
package entity
// Our entity flags.
const (
BlockMovement uint = 1 << iota
)

10
gamestate.go Normal file
View File

@ -0,0 +1,10 @@
package main
// GameState is a numerical representation of a game state.
type GameState = uint8
// Our various game states.
const (
PlayerTurnState GameState = iota
NPCTurnState
)

32
main.go
View File

@ -27,6 +27,8 @@ func main() {
// Our initial variables. // Our initial variables.
mapWidth, mapHeight := 80, 40 mapWidth, mapHeight := 80, 40
maxRooms, roomMinSize, roomMaxSize := 30, 6, 10 maxRooms, roomMinSize, roomMaxSize := 30, 6, 10
maxMonstersPerRoom := 3
gameState := PlayerTurnState
fovRadius := 10 fovRadius := 10
fovRecompute := true fovRecompute := true
@ -38,17 +40,15 @@ func main() {
"lightGround": goro.Color{R: 150, G: 150, B: 150, A: 255}, "lightGround": goro.Color{R: 150, G: 150, B: 150, A: 255},
} }
player := entity.NewEntity(screen.Columns/2, screen.Rows/2+5, '@', goro.Style{Foreground: goro.ColorWhite}) player := entity.NewEntity(0, 0, '@', goro.Style{Foreground: goro.ColorWhite}, "Player", entity.BlockMovement)
npc := entity.NewEntity(screen.Columns/2-5, screen.Rows/2, '@', goro.Style{Foreground: goro.ColorYellow})
entities := []interfaces.Entity{ entities := []interfaces.Entity{
player, player,
npc,
} }
gameMap := mapping.NewGameMap(mapWidth, mapHeight) gameMap := mapping.NewGameMap(mapWidth, mapHeight)
gameMap.MakeMap(maxRooms, roomMinSize, roomMaxSize, player) gameMap.MakeMap(maxRooms, roomMinSize, roomMaxSize, &entities, maxMonstersPerRoom)
fovMap := InitializeFoV(gameMap) fovMap := InitializeFoV(gameMap)
@ -70,9 +70,19 @@ func main() {
case goro.EventKey: case goro.EventKey:
switch action := handleKeyEvent(event).(type) { switch action := handleKeyEvent(event).(type) {
case ActionMove: case ActionMove:
if !gameMap.IsBlocked(player.X()+action.X, player.Y()+action.Y) { if gameState == PlayerTurnState {
x := player.X() + action.X
y := player.Y() + action.Y
if !gameMap.IsBlocked(x, y) {
otherEntity := entity.FindEntityAtLocation(entities, x, y, entity.BlockMovement, entity.BlockMovement)
if otherEntity != nil {
fmt.Printf("You lick the %s in the shins, much to its enjoyment!\n", otherEntity.Name())
} else {
player.Move(action.X, action.Y) player.Move(action.X, action.Y)
fovRecompute = true forRecompute = true
}
}
gameState = NPCTurnState
} }
case ActionQuit: case ActionQuit:
goro.Quit() goro.Quit()
@ -80,6 +90,16 @@ func main() {
case goro.EventQuit: case goro.EventQuit:
return return
} }
// Handle entity updates.
if gameState == NPCTurnState {
for i, e := range entities {
if i > 0 {
fmt.Printf("The &s punders.\n", e.Name())
}
}
gameState = PlayerTurnState
}
} }
}) })
} }

View File

@ -1,9 +1,10 @@
package mapping package mapping
import ( import (
"github.com/kettek/goro" "steel/entity"
"steel/interfaces" "steel/interfaces"
"github.com/kettek/goro"
) )
// GameMap is our map type for holding our tiles and dimensions. // GameMap is our map type for holding our tiles and dimensions.
@ -31,7 +32,7 @@ func NewGameMap(width, height int) interfaces.GameMap {
} }
// MakeMap creates a new randomized map. This is built according to the passed arguments. // MakeMap creates a new randomized map. This is built according to the passed arguments.
func (g *GameMap) MakeMap(maxRooms, roomMinSize, roomMaxSize int, player interfaces.Entity) { func (g *GameMap) MakeMap(maxRooms, roomMinSize, roomMaxSize int, entities *[]interfaces.Entity, maxMonsters int) {
var rooms []Rect var rooms []Rect
for r := 0; r < maxRooms; r++ { for r := 0; r < maxRooms; r++ {
@ -59,8 +60,8 @@ func (g *GameMap) MakeMap(maxRooms, roomMinSize, roomMaxSize int, player interfa
// Always place the player in the center of the first room. // Always place the player in the center of the first room.
if len(rooms) == 0 { if len(rooms) == 0 {
player.SetX(roomCenterX) (*entities)[0].SetX(roomCenterX)
player.SetY(roomCenterY) (*entities)[0].SetY(roomCenterY)
} else { } else {
prevCenterX, prevCenterY := rooms[len(rooms)-1].Center() prevCenterX, prevCenterY := rooms[len(rooms)-1].Center()
@ -73,6 +74,9 @@ func (g *GameMap) MakeMap(maxRooms, roomMinSize, roomMaxSize int, player interfa
g.CreateHTunnel(prevCenterX, roomCenterX, roomCenterY) g.CreateHTunnel(prevCenterX, roomCenterX, roomCenterY)
} }
} }
// Place random monsters in the room.
g.PlaceEntities(room, entities, maxMonsters)
// Append our new room to our rooms list. // Append our new room to our rooms list.
rooms = append(rooms, room) rooms = append(rooms, room)
} }
@ -108,6 +112,28 @@ func (g *GameMap) CreateVTunnel(y1, y2, x int) {
} }
} }
// PlaceEntities places 0 to maxMonsters monster entities in the provided room.
func (g *GameMap) PlaceEntities(room Rect, entities *[]interfaces.Entity, maxMonsters int) {
monstersCount := goro.Random.Intn(maxMonsters)
for i := 0; i < monstersCount; i++ {
var monster interfaces.Entity
// Acquire a random location within the room.
x := (1 + room.X1) + goro.Random.Intn(room.X2-room.X1-1)
y := (1 + room.Y1) + goro.Random.Intn(room.Y2-room.Y1-1)
if entity.FindEntityAtLocation(*entities, x, y, 0, 0) == nil {
// Generate an orc with 80% probably or a troll with 20%.
if goro.Random.Intn(100) < 80 {
monster = entity.NewEntity(x, y, 'o', goro.Style{Foreground: goro.ColorLime}, "Orc", entity.BlockMovement)
} else {
monster = entity.NewEntity(x, y, 'T', goro.Style{Foreground: goro.ColorGreen}, "Troll", entity.BlockMovement)
}
*entities = append(*entities, monster)
}
}
}
// Explored returns if the tile at x by y has been explored. // Explored returns if the tile at x by y has been explored.
func (g *GameMap) Explored(x, y int) bool { func (g *GameMap) Explored(x, y int) bool {
if g.InBounds(x, y) { if g.InBounds(x, y) {