last_light/game/state/playing_state.go

186 lines
3.9 KiB
Go

package state
import (
"mvvasilev/last_light/engine"
engine1 "mvvasilev/last_light/engine"
"mvvasilev/last_light/game/model"
"mvvasilev/last_light/game/world"
"github.com/gdamore/tcell/v2"
"github.com/gdamore/tcell/v2/views"
)
type PlayingState struct {
player *model.Player
entityMap *world.EntityMap
level *world.MultilevelMap
viewport *engine.Viewport
movePlayerDirection model.Direction
pauseGame bool
openInventory bool
pickUpUnderPlayer bool
}
func BeginPlayingState() *PlayingState {
s := new(PlayingState)
mapSize := engine1.SizeOf(128, 128)
dungeonLevel := world.CreateBSPDungeonMap(mapSize.Width(), mapSize.Height(), 4)
genTable := make(map[float32]*model.ItemType, 0)
genTable[0.2] = model.ItemTypeFish()
genTable[0.05] = model.ItemTypeBow()
genTable[0.051] = model.ItemTypeLongsword()
genTable[0.052] = model.ItemTypeKey()
itemTiles := world.SpawnItems(dungeonLevel.Rooms(), 0.025, genTable)
itemLevel := world.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.entityMap = world.CreateEntityMap(mapSize.WH())
s.level = world.CreateMultilevelMap(
dungeonLevel,
itemLevel,
s.entityMap,
)
s.entityMap.AddEntity(s.player, '@', tcell.StyleDefault)
s.viewport = engine.CreateViewport(
engine1.PositionAt(0, 0),
dungeonLevel.PlayerSpawnPoint(),
engine1.SizeOf(80, 24),
tcell.StyleDefault,
)
return s
}
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() {
dx, dy := model.MovementDirectionOffset(ps.movePlayerDirection)
ps.entityMap.MoveEntity(ps.player.UniqueId(), dx, dy)
ps.viewport.SetCenter(ps.player.Position())
}
ps.movePlayerDirection = model.DirectionNone
}
func (ps *PlayingState) PickUpItemUnderPlayer() {
pos := ps.player.Position()
tile := ps.level.TileAtHeight(pos.X(), pos.Y(), 1)
itemTile, ok := tile.(*world.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
}
}
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() []engine.Drawable {
return engine.Multidraw(engine.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
})
}))
}