mirror of
https://github.com/mvvasilev/last_light.git
synced 2025-04-19 12:49:52 +03:00
231 lines
4.9 KiB
Go
231 lines
4.9 KiB
Go
package state
|
|
|
|
import (
|
|
"math/rand"
|
|
"mvvasilev/last_light/game/model"
|
|
"mvvasilev/last_light/render"
|
|
"mvvasilev/last_light/util"
|
|
|
|
"github.com/gdamore/tcell/v2"
|
|
"github.com/gdamore/tcell/v2/views"
|
|
)
|
|
|
|
type PlayingState struct {
|
|
player *model.Player
|
|
level *model.MultilevelMap
|
|
|
|
viewport *render.Viewport
|
|
|
|
movePlayerDirection model.Direction
|
|
pauseGame bool
|
|
openInventory bool
|
|
pickUpUnderPlayer bool
|
|
}
|
|
|
|
func BeginPlayingState() *PlayingState {
|
|
s := new(PlayingState)
|
|
|
|
mapSize := util.SizeOf(128, 128)
|
|
|
|
dungeonLevel := model.CreateBSPDungeonLevel(mapSize.Width(), mapSize.Height(), 4)
|
|
|
|
itemTiles := spawnItems(dungeonLevel)
|
|
|
|
itemLevel := model.CreateEmptyDungeonLevel(mapSize.Width(), mapSize.Height())
|
|
|
|
for _, it := range itemTiles {
|
|
itemLevel.SetTileAt(it.Position().X(), it.Position().Y(), it)
|
|
}
|
|
|
|
s.player = model.CreatePlayer(dungeonLevel.PlayerSpawnPoint().XY())
|
|
|
|
s.level = model.CreateMultilevelMap(
|
|
dungeonLevel,
|
|
itemLevel,
|
|
model.CreateEmptyDungeonLevel(mapSize.WH()),
|
|
)
|
|
|
|
s.level.SetTileAtHeight(dungeonLevel.PlayerSpawnPoint().X(), dungeonLevel.PlayerSpawnPoint().Y(), 2, s.player)
|
|
|
|
s.viewport = render.CreateViewport(
|
|
util.PositionAt(0, 0),
|
|
dungeonLevel.PlayerSpawnPoint(),
|
|
util.SizeOf(80, 24),
|
|
tcell.StyleDefault,
|
|
)
|
|
|
|
return s
|
|
}
|
|
|
|
func spawnItems(level *model.BSPDungeonLevel) []model.Tile {
|
|
rooms := level.Rooms()
|
|
|
|
genTable := make(map[float32]*model.ItemType)
|
|
|
|
genTable[0.2] = model.ItemTypeFish()
|
|
genTable[0.05] = model.ItemTypeBow()
|
|
genTable[0.051] = model.ItemTypeLongsword()
|
|
genTable[0.052] = model.ItemTypeKey()
|
|
|
|
itemTiles := make([]model.Tile, 0, 10)
|
|
|
|
for _, r := range rooms {
|
|
maxItems := int(0.10 * float64(r.Size().Area()))
|
|
|
|
if maxItems < 1 {
|
|
continue
|
|
}
|
|
|
|
numItems := rand.Intn(maxItems)
|
|
|
|
for range numItems {
|
|
itemType := model.GenerateItemType(genTable)
|
|
|
|
if itemType == nil {
|
|
continue
|
|
}
|
|
|
|
pos := util.PositionAt(
|
|
util.RandInt(r.Position().X()+1, r.Position().X()+r.Size().Width()-1),
|
|
util.RandInt(r.Position().Y()+1, r.Position().Y()+r.Size().Height()-1),
|
|
)
|
|
|
|
itemTiles = append(itemTiles, model.CreateItemTile(
|
|
pos, itemType, 1,
|
|
))
|
|
}
|
|
}
|
|
|
|
return itemTiles
|
|
}
|
|
|
|
func (ps *PlayingState) Pause() {
|
|
ps.pauseGame = true
|
|
}
|
|
|
|
func (ps *PlayingState) Unpause() {
|
|
ps.pauseGame = false
|
|
}
|
|
|
|
func (ps *PlayingState) SetPaused(paused bool) {
|
|
ps.pauseGame = paused
|
|
}
|
|
|
|
func (ps *PlayingState) MovePlayer() {
|
|
if ps.movePlayerDirection == model.DirectionNone {
|
|
return
|
|
}
|
|
|
|
newPlayerPos := ps.player.Position().WithOffset(model.MovementDirectionOffset(ps.movePlayerDirection))
|
|
|
|
tileAtMovePos := ps.level.TileAt(newPlayerPos.XY())
|
|
|
|
if tileAtMovePos.Passable() {
|
|
ps.level.SetTileAtHeight(ps.player.Position().X(), ps.player.Position().Y(), 2, nil)
|
|
ps.player.Move(ps.movePlayerDirection)
|
|
ps.viewport.SetCenter(ps.player.Position())
|
|
ps.level.SetTileAtHeight(ps.player.Position().X(), ps.player.Position().Y(), 2, ps.player)
|
|
}
|
|
|
|
ps.movePlayerDirection = model.DirectionNone
|
|
}
|
|
|
|
func (ps *PlayingState) PickUpItemUnderPlayer() {
|
|
pos := ps.player.Position()
|
|
tile := ps.level.TileAtHeight(pos.X(), pos.Y(), 1)
|
|
|
|
itemTile, ok := tile.(*model.ItemTile)
|
|
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
item := model.CreateItem(itemTile.Type(), itemTile.Quantity())
|
|
|
|
success := ps.player.Inventory().Push(item)
|
|
|
|
if !success {
|
|
return
|
|
}
|
|
|
|
ps.level.SetTileAtHeight(pos.X(), pos.Y(), 1, nil)
|
|
}
|
|
|
|
func (ps *PlayingState) OnInput(e *tcell.EventKey) {
|
|
ps.player.Input(e)
|
|
|
|
if e.Key() == tcell.KeyEsc {
|
|
ps.pauseGame = true
|
|
return
|
|
}
|
|
|
|
if e.Key() == tcell.KeyRune && e.Rune() == 'i' {
|
|
ps.openInventory = true
|
|
return
|
|
}
|
|
|
|
if e.Key() == tcell.KeyRune && e.Rune() == 'p' {
|
|
ps.pickUpUnderPlayer = true
|
|
return
|
|
}
|
|
|
|
switch e.Key() {
|
|
case tcell.KeyUp:
|
|
ps.movePlayerDirection = model.DirectionUp
|
|
case tcell.KeyDown:
|
|
ps.movePlayerDirection = model.DirectionDown
|
|
case tcell.KeyLeft:
|
|
ps.movePlayerDirection = model.DirectionLeft
|
|
case tcell.KeyRight:
|
|
ps.movePlayerDirection = model.DirectionRight
|
|
case tcell.KeyRune:
|
|
switch e.Rune() {
|
|
case 'w':
|
|
ps.movePlayerDirection = model.DirectionUp
|
|
case 'a':
|
|
ps.movePlayerDirection = model.DirectionLeft
|
|
case 's':
|
|
ps.movePlayerDirection = model.DirectionDown
|
|
case 'd':
|
|
ps.movePlayerDirection = model.DirectionRight
|
|
}
|
|
}
|
|
}
|
|
|
|
func (ps *PlayingState) OnTick(dt int64) GameState {
|
|
ps.player.Tick(dt)
|
|
|
|
if ps.pauseGame {
|
|
return PauseGame(ps)
|
|
}
|
|
|
|
if ps.openInventory {
|
|
ps.openInventory = false
|
|
return CreateInventoryScreenState(ps.player, ps)
|
|
}
|
|
|
|
if ps.movePlayerDirection != model.DirectionNone {
|
|
ps.MovePlayer()
|
|
}
|
|
|
|
if ps.pickUpUnderPlayer {
|
|
ps.pickUpUnderPlayer = false
|
|
ps.PickUpItemUnderPlayer()
|
|
}
|
|
|
|
return ps
|
|
}
|
|
|
|
func (ps *PlayingState) CollectDrawables() []render.Drawable {
|
|
return render.Multidraw(render.CreateDrawingInstructions(func(v views.View) {
|
|
ps.viewport.DrawFromProvider(v, func(x, y int) (rune, tcell.Style) {
|
|
tile := ps.level.TileAt(x, y)
|
|
|
|
if tile != nil {
|
|
return tile.Presentation()
|
|
}
|
|
|
|
return ' ', tcell.StyleDefault
|
|
})
|
|
}))
|
|
}
|