mirror of
https://github.com/mvvasilev/last_light.git
synced 2025-04-19 12:49:52 +03:00
Create player inventory menu
This commit is contained in:
parent
b7b269e8b8
commit
5d1416bb07
30 changed files with 460 additions and 300 deletions
|
@ -1,4 +1,4 @@
|
|||
package render
|
||||
package engine
|
||||
|
||||
import (
|
||||
"github.com/gdamore/tcell/v2/views"
|
|
@ -1,4 +1,4 @@
|
|||
package render
|
||||
package engine
|
||||
|
||||
import (
|
||||
"mvvasilev/last_light/util"
|
||||
|
@ -119,6 +119,10 @@ func (g *Grid) Unhighlight() {
|
|||
g.isHighlighted = false
|
||||
}
|
||||
|
||||
func (g *Grid) Position() util.Position {
|
||||
return g.position
|
||||
}
|
||||
|
||||
// C###T###T###C
|
||||
// # # # #
|
||||
// # # # #
|
|
@ -1,4 +1,4 @@
|
|||
package render
|
||||
package engine
|
||||
|
||||
import (
|
||||
"slices"
|
|
@ -1,4 +1,4 @@
|
|||
package render
|
||||
package engine
|
||||
|
||||
import (
|
||||
"mvvasilev/last_light/util"
|
|
@ -1,4 +1,4 @@
|
|||
package render
|
||||
package engine
|
||||
|
||||
import (
|
||||
"mvvasilev/last_light/util"
|
|
@ -1,4 +1,4 @@
|
|||
package render
|
||||
package engine
|
||||
|
||||
import (
|
||||
"errors"
|
|
@ -1,4 +1,4 @@
|
|||
package render
|
||||
package engine
|
||||
|
||||
import (
|
||||
"mvvasilev/last_light/util"
|
|
@ -1,4 +1,4 @@
|
|||
package render
|
||||
package engine
|
||||
|
||||
import (
|
||||
"mvvasilev/last_light/util"
|
|
@ -1,8 +1,8 @@
|
|||
package game
|
||||
|
||||
import (
|
||||
"mvvasilev/last_light/engine"
|
||||
"mvvasilev/last_light/game/state"
|
||||
"mvvasilev/last_light/render"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
)
|
||||
|
@ -46,6 +46,6 @@ func (g *Game) Tick(dt int64) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (g *Game) CollectDrawables() []render.Drawable {
|
||||
func (g *Game) CollectDrawables() []engine.Drawable {
|
||||
return g.state.CollectDrawables()
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package game
|
|||
|
||||
import (
|
||||
"log"
|
||||
"mvvasilev/last_light/render"
|
||||
"mvvasilev/last_light/engine"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
@ -10,7 +10,7 @@ import (
|
|||
const TICK_RATE int64 = 50 // tick every 50ms ( 20 ticks per second )
|
||||
|
||||
type GameContext struct {
|
||||
renderContext *render.RenderContext
|
||||
renderContext *engine.RenderContext
|
||||
|
||||
game *Game
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ type GameContext struct {
|
|||
func CreateGameContext() *GameContext {
|
||||
gc := new(GameContext)
|
||||
|
||||
rc, err := render.CreateRenderContext()
|
||||
rc, err := engine.CreateRenderContext()
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("%~v", err)
|
||||
|
|
|
@ -2,13 +2,21 @@ package model
|
|||
|
||||
import "mvvasilev/last_light/util"
|
||||
|
||||
type Inventory struct {
|
||||
type Inventory interface {
|
||||
Items() []*Item
|
||||
Shape() util.Size
|
||||
Push(item Item) bool
|
||||
Drop(x, y int) *Item
|
||||
ItemAt(x, y int) *Item
|
||||
}
|
||||
|
||||
type BasicInventory struct {
|
||||
contents []*Item
|
||||
shape util.Size
|
||||
}
|
||||
|
||||
func CreateInventory(shape util.Size) *Inventory {
|
||||
inv := new(Inventory)
|
||||
func CreateInventory(shape util.Size) *BasicInventory {
|
||||
inv := new(BasicInventory)
|
||||
|
||||
inv.contents = make([]*Item, 0, shape.Height()*shape.Width())
|
||||
inv.shape = shape
|
||||
|
@ -16,15 +24,15 @@ func CreateInventory(shape util.Size) *Inventory {
|
|||
return inv
|
||||
}
|
||||
|
||||
func (i *Inventory) Items() (items []*Item) {
|
||||
func (i *BasicInventory) Items() (items []*Item) {
|
||||
return i.contents
|
||||
}
|
||||
|
||||
func (i *Inventory) Shape() util.Size {
|
||||
func (i *BasicInventory) Shape() util.Size {
|
||||
return i.shape
|
||||
}
|
||||
|
||||
func (i *Inventory) Push(item Item) (success bool) {
|
||||
func (i *BasicInventory) Push(item Item) (success bool) {
|
||||
if len(i.contents) == i.shape.Area() {
|
||||
return false
|
||||
}
|
||||
|
@ -60,17 +68,21 @@ func (i *Inventory) Push(item Item) (success bool) {
|
|||
return true
|
||||
}
|
||||
|
||||
func (i *Inventory) Drop(x, y int) {
|
||||
func (i *BasicInventory) Drop(x, y int) *Item {
|
||||
index := y*i.shape.Width() + x
|
||||
|
||||
if index > len(i.contents)-1 {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
item := i.contents[index]
|
||||
|
||||
i.contents[index] = nil
|
||||
|
||||
return item
|
||||
}
|
||||
|
||||
func (i *Inventory) ItemAt(x, y int) (item *Item) {
|
||||
func (i *BasicInventory) ItemAt(x, y int) (item *Item) {
|
||||
index := y*i.shape.Width() + x
|
||||
|
||||
if index > len(i.contents)-1 {
|
||||
|
|
|
@ -1,126 +1,9 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
)
|
||||
|
||||
type ItemType struct {
|
||||
name string
|
||||
description string
|
||||
tileIcon rune
|
||||
itemIcon string
|
||||
maxStack int
|
||||
|
||||
style tcell.Style
|
||||
}
|
||||
|
||||
func (it *ItemType) Name() string {
|
||||
return it.name
|
||||
}
|
||||
|
||||
func (it *ItemType) Description() string {
|
||||
return it.description
|
||||
}
|
||||
|
||||
func (it *ItemType) TileIcon() rune {
|
||||
return it.tileIcon
|
||||
}
|
||||
|
||||
func (it *ItemType) Icon() string {
|
||||
return it.itemIcon
|
||||
}
|
||||
|
||||
func (it *ItemType) Style() tcell.Style {
|
||||
return it.style
|
||||
}
|
||||
|
||||
func (it *ItemType) MaxStack() int {
|
||||
return it.maxStack
|
||||
}
|
||||
|
||||
func ItemTypeFish() *ItemType {
|
||||
return &ItemType{
|
||||
name: "Fish",
|
||||
description: "What's a fish doing down here?",
|
||||
tileIcon: '>',
|
||||
itemIcon: "»o>",
|
||||
style: tcell.StyleDefault.Foreground(tcell.ColorDarkCyan),
|
||||
maxStack: 16,
|
||||
}
|
||||
}
|
||||
|
||||
func ItemTypeGold() *ItemType {
|
||||
return &ItemType{
|
||||
name: "Gold",
|
||||
description: "Not all those who wander are lost",
|
||||
tileIcon: '¤',
|
||||
itemIcon: " ¤ ",
|
||||
style: tcell.StyleDefault.Foreground(tcell.ColorGoldenrod),
|
||||
maxStack: 255,
|
||||
}
|
||||
}
|
||||
|
||||
func ItemTypeArrow() *ItemType {
|
||||
return &ItemType{
|
||||
name: "Arrow",
|
||||
description: "Ammunition for a bow",
|
||||
tileIcon: '-',
|
||||
itemIcon: "»->",
|
||||
style: tcell.StyleDefault.Foreground(tcell.ColorGoldenrod),
|
||||
maxStack: 32,
|
||||
}
|
||||
}
|
||||
|
||||
func ItemTypeBow() *ItemType {
|
||||
return &ItemType{
|
||||
name: "Bow",
|
||||
description: "To shoot arrows with",
|
||||
tileIcon: ')',
|
||||
itemIcon: " |)",
|
||||
style: tcell.StyleDefault.Foreground(tcell.ColorBrown),
|
||||
maxStack: 1,
|
||||
}
|
||||
}
|
||||
|
||||
func ItemTypeLongsword() *ItemType {
|
||||
return &ItemType{
|
||||
name: "Longsword",
|
||||
description: "You know nothing.",
|
||||
tileIcon: '/',
|
||||
itemIcon: "╪══",
|
||||
style: tcell.StyleDefault.Foreground(tcell.ColorSilver),
|
||||
maxStack: 1,
|
||||
}
|
||||
}
|
||||
|
||||
func ItemTypeKey() *ItemType {
|
||||
return &ItemType{
|
||||
name: "Key",
|
||||
description: "Indispensable for unlocking things",
|
||||
tileIcon: '¬',
|
||||
itemIcon: " o╖",
|
||||
style: tcell.StyleDefault.Foreground(tcell.ColorDarkGoldenrod),
|
||||
maxStack: 1,
|
||||
}
|
||||
}
|
||||
|
||||
type ItemTypeGenTable struct {
|
||||
}
|
||||
|
||||
func GenerateItemType(genTable map[float32]*ItemType) *ItemType {
|
||||
num := rand.Float32()
|
||||
|
||||
for k, v := range genTable {
|
||||
if num > k {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type Item struct {
|
||||
name string
|
||||
description string
|
||||
|
|
119
game/model/item_type.go
Normal file
119
game/model/item_type.go
Normal file
|
@ -0,0 +1,119 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
)
|
||||
|
||||
type ItemType struct {
|
||||
name string
|
||||
description string
|
||||
tileIcon rune
|
||||
itemIcon string
|
||||
maxStack int
|
||||
|
||||
style tcell.Style
|
||||
}
|
||||
|
||||
func (it *ItemType) Name() string {
|
||||
return it.name
|
||||
}
|
||||
|
||||
func (it *ItemType) Description() string {
|
||||
return it.description
|
||||
}
|
||||
|
||||
func (it *ItemType) TileIcon() rune {
|
||||
return it.tileIcon
|
||||
}
|
||||
|
||||
func (it *ItemType) Icon() string {
|
||||
return it.itemIcon
|
||||
}
|
||||
|
||||
func (it *ItemType) Style() tcell.Style {
|
||||
return it.style
|
||||
}
|
||||
|
||||
func (it *ItemType) MaxStack() int {
|
||||
return it.maxStack
|
||||
}
|
||||
|
||||
func ItemTypeFish() *ItemType {
|
||||
return &ItemType{
|
||||
name: "Fish",
|
||||
description: "What's a fish doing down here?",
|
||||
tileIcon: '>',
|
||||
itemIcon: "»o>",
|
||||
style: tcell.StyleDefault.Foreground(tcell.ColorDarkCyan),
|
||||
maxStack: 16,
|
||||
}
|
||||
}
|
||||
|
||||
func ItemTypeGold() *ItemType {
|
||||
return &ItemType{
|
||||
name: "Gold",
|
||||
description: "Not all those who wander are lost",
|
||||
tileIcon: '¤',
|
||||
itemIcon: " ¤ ",
|
||||
style: tcell.StyleDefault.Foreground(tcell.ColorGoldenrod),
|
||||
maxStack: 255,
|
||||
}
|
||||
}
|
||||
|
||||
func ItemTypeArrow() *ItemType {
|
||||
return &ItemType{
|
||||
name: "Arrow",
|
||||
description: "Ammunition for a bow",
|
||||
tileIcon: '-',
|
||||
itemIcon: "»->",
|
||||
style: tcell.StyleDefault.Foreground(tcell.ColorGoldenrod),
|
||||
maxStack: 32,
|
||||
}
|
||||
}
|
||||
|
||||
func ItemTypeBow() *ItemType {
|
||||
return &ItemType{
|
||||
name: "Bow",
|
||||
description: "To shoot arrows with",
|
||||
tileIcon: ')',
|
||||
itemIcon: " |)",
|
||||
style: tcell.StyleDefault.Foreground(tcell.ColorBrown),
|
||||
maxStack: 1,
|
||||
}
|
||||
}
|
||||
|
||||
func ItemTypeLongsword() *ItemType {
|
||||
return &ItemType{
|
||||
name: "Longsword",
|
||||
description: "You know nothing.",
|
||||
tileIcon: '/',
|
||||
itemIcon: "╪══",
|
||||
style: tcell.StyleDefault.Foreground(tcell.ColorSilver),
|
||||
maxStack: 1,
|
||||
}
|
||||
}
|
||||
|
||||
func ItemTypeKey() *ItemType {
|
||||
return &ItemType{
|
||||
name: "Key",
|
||||
description: "Indispensable for unlocking things",
|
||||
tileIcon: '¬',
|
||||
itemIcon: " o╖",
|
||||
style: tcell.StyleDefault.Foreground(tcell.ColorDarkGoldenrod),
|
||||
maxStack: 1,
|
||||
}
|
||||
}
|
||||
|
||||
func GenerateItemType(genTable map[float32]*ItemType) *ItemType {
|
||||
num := rand.Float32()
|
||||
|
||||
for k, v := range genTable {
|
||||
if num > k {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -11,7 +11,7 @@ type Player struct {
|
|||
id uuid.UUID
|
||||
position util.Position
|
||||
|
||||
inventory *Inventory
|
||||
inventory *EquippedInventory
|
||||
}
|
||||
|
||||
func CreatePlayer(x, y int) *Player {
|
||||
|
@ -19,7 +19,7 @@ func CreatePlayer(x, y int) *Player {
|
|||
|
||||
p.id = uuid.New()
|
||||
p.position = util.PositionAt(x, y)
|
||||
p.inventory = CreateInventory(util.SizeOf(8, 4))
|
||||
p.inventory = CreatePlayerInventory()
|
||||
|
||||
return p
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ func (p *Player) Transparent() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (p *Player) Inventory() *Inventory {
|
||||
func (p *Player) Inventory() *EquippedInventory {
|
||||
return p.inventory
|
||||
}
|
||||
|
||||
|
|
72
game/model/player_inventory.go
Normal file
72
game/model/player_inventory.go
Normal file
|
@ -0,0 +1,72 @@
|
|||
package model
|
||||
|
||||
import "mvvasilev/last_light/util"
|
||||
|
||||
type EquippedSlot int
|
||||
|
||||
const (
|
||||
EquippedSlotOffhand EquippedSlot = iota
|
||||
EquippedSlotDominantHand
|
||||
EquippedSlotHead
|
||||
EquippedSlotChestplate
|
||||
EquippedSlotLeggings
|
||||
EquippedSlotShoes
|
||||
)
|
||||
|
||||
type EquippedInventory struct {
|
||||
offHand *Item
|
||||
dominantHand *Item
|
||||
|
||||
head *Item
|
||||
chestplate *Item
|
||||
leggings *Item
|
||||
shoes *Item
|
||||
|
||||
*BasicInventory
|
||||
}
|
||||
|
||||
func CreatePlayerInventory() *EquippedInventory {
|
||||
return &EquippedInventory{
|
||||
BasicInventory: CreateInventory(util.SizeOf(8, 4)),
|
||||
}
|
||||
}
|
||||
|
||||
func (ei *EquippedInventory) AtSlot(slot EquippedSlot) *Item {
|
||||
switch slot {
|
||||
case EquippedSlotOffhand:
|
||||
return ei.offHand
|
||||
case EquippedSlotDominantHand:
|
||||
return ei.dominantHand
|
||||
case EquippedSlotHead:
|
||||
return ei.head
|
||||
case EquippedSlotChestplate:
|
||||
return ei.chestplate
|
||||
case EquippedSlotLeggings:
|
||||
return ei.leggings
|
||||
case EquippedSlotShoes:
|
||||
return ei.shoes
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (ei *EquippedInventory) Equip(item Item, slot EquippedSlot) *Item {
|
||||
ref := &item
|
||||
|
||||
switch slot {
|
||||
case EquippedSlotOffhand:
|
||||
ei.offHand = ref
|
||||
case EquippedSlotDominantHand:
|
||||
ei.dominantHand = ref
|
||||
case EquippedSlotHead:
|
||||
ei.head = ref
|
||||
case EquippedSlotChestplate:
|
||||
ei.chestplate = ref
|
||||
case EquippedSlotLeggings:
|
||||
ei.leggings = ref
|
||||
case EquippedSlotShoes:
|
||||
ei.shoes = ref
|
||||
}
|
||||
|
||||
return ref
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package state
|
||||
|
||||
import (
|
||||
"mvvasilev/last_light/render"
|
||||
"mvvasilev/last_light/engine"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
)
|
||||
|
@ -9,7 +9,7 @@ import (
|
|||
type GameState interface {
|
||||
OnInput(e *tcell.EventKey)
|
||||
OnTick(dt int64) GameState
|
||||
CollectDrawables() []render.Drawable
|
||||
CollectDrawables() []engine.Drawable
|
||||
}
|
||||
|
||||
type PausableState interface {
|
||||
|
|
|
@ -1,36 +1,24 @@
|
|||
package state
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"mvvasilev/last_light/engine"
|
||||
"mvvasilev/last_light/game/model"
|
||||
"mvvasilev/last_light/render"
|
||||
"mvvasilev/last_light/ui"
|
||||
"mvvasilev/last_light/game/ui/menu"
|
||||
"mvvasilev/last_light/util"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/gdamore/tcell/v2/views"
|
||||
)
|
||||
|
||||
type InventoryScreenState struct {
|
||||
prevState PausableState
|
||||
exitMenu bool
|
||||
|
||||
inventoryMenu *ui.UIWindow
|
||||
armourLabel *ui.UILabel
|
||||
armourGrid *render.Grid
|
||||
leftHandLabel *ui.UILabel
|
||||
leftHandBox render.Rectangle
|
||||
rightHandLabel *ui.UILabel
|
||||
rightHandBox render.Rectangle
|
||||
inventoryGrid *render.Grid
|
||||
playerItems *render.ArbitraryDrawable
|
||||
selectedItem *render.ArbitraryDrawable
|
||||
help *ui.UILabel
|
||||
inventoryMenu *menu.PlayerInventoryMenu
|
||||
selectedInventorySlot util.Position
|
||||
|
||||
player *model.Player
|
||||
|
||||
moveInventorySlotDirection model.Direction
|
||||
selectedInventorySlot util.Position
|
||||
dropSelectedInventorySlot bool
|
||||
}
|
||||
|
||||
|
@ -39,88 +27,9 @@ func CreateInventoryScreenState(player *model.Player, prevState PausableState) *
|
|||
|
||||
iss.prevState = prevState
|
||||
iss.player = player
|
||||
iss.exitMenu = false
|
||||
iss.selectedInventorySlot = util.PositionAt(0, 0)
|
||||
|
||||
iss.inventoryMenu = ui.CreateWindow(43, 0, 37, 24, "INVENTORY", tcell.StyleDefault)
|
||||
|
||||
iss.armourLabel = ui.CreateSingleLineUILabel(58, 1, "ARMOUR", tcell.StyleDefault)
|
||||
|
||||
iss.armourGrid = render.CreateGrid(
|
||||
53, 2, 3, 1, 4, 1, '┌', '─', '┬', '┐', '│', ' ', '│', '│', '├', '─', '┼', '┤', '└', '─', '┴', '┘', tcell.StyleDefault, tcell.StyleDefault.Background(tcell.ColorDarkSlateGray),
|
||||
)
|
||||
|
||||
iss.leftHandLabel = ui.CreateUILabel(
|
||||
46, 1, 5, 1, "OFF", tcell.StyleDefault,
|
||||
)
|
||||
|
||||
iss.leftHandBox = render.CreateRectangle(
|
||||
45, 2, 5, 3,
|
||||
'┌', '─', '┐',
|
||||
'│', ' ', '│',
|
||||
'└', '─', '┘',
|
||||
false, true,
|
||||
tcell.StyleDefault,
|
||||
)
|
||||
|
||||
iss.rightHandLabel = ui.CreateUILabel(
|
||||
74, 1, 5, 1, "DOM", tcell.StyleDefault,
|
||||
)
|
||||
|
||||
iss.rightHandBox = render.CreateRectangle(
|
||||
73, 2, 5, 3,
|
||||
'┌', '─', '┐',
|
||||
'│', ' ', '│',
|
||||
'└', '─', '┘',
|
||||
false, true,
|
||||
tcell.StyleDefault,
|
||||
)
|
||||
|
||||
iss.inventoryGrid = render.CreateGrid(
|
||||
45, 5, 3, 1, 8, 4, '┌', '─', '┬', '┐', '│', ' ', '│', '│', '├', '─', '┼', '┤', '└', '─', '┴', '┘', tcell.StyleDefault, tcell.StyleDefault.Background(tcell.ColorDarkSlateGray),
|
||||
)
|
||||
|
||||
iss.playerItems = render.CreateDrawingInstructions(func(v views.View) {
|
||||
for y := range player.Inventory().Shape().Height() {
|
||||
for x := range player.Inventory().Shape().Width() {
|
||||
item := player.Inventory().ItemAt(x, y)
|
||||
isHighlighted := x == iss.selectedInventorySlot.X() && y == iss.selectedInventorySlot.Y()
|
||||
|
||||
if item == nil {
|
||||
|
||||
if isHighlighted {
|
||||
ui.CreateSingleLineUILabel(45+1+x*4, 5+1+y*2, " ", tcell.StyleDefault.Background(tcell.ColorDarkSlateGray)).Draw(v)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
style := item.Type().Style()
|
||||
|
||||
if isHighlighted {
|
||||
style = style.Background(tcell.ColorDarkSlateGray)
|
||||
}
|
||||
|
||||
ui.CreateSingleLineUILabel(45+1+x*4, 5+y*2, fmt.Sprintf("%03d", item.Quantity()), style).Draw(v)
|
||||
ui.CreateSingleLineUILabel(45+1+x*4, 5+1+y*2, item.Type().Icon(), style).Draw(v)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
iss.selectedItem = render.CreateDrawingInstructions(func(v views.View) {
|
||||
ui.CreateWindow(45, 14, 33, 8, "ITEM", tcell.StyleDefault).Draw(v)
|
||||
|
||||
item := player.Inventory().ItemAt(iss.selectedInventorySlot.XY())
|
||||
|
||||
if item == nil {
|
||||
return
|
||||
}
|
||||
|
||||
ui.CreateSingleLineUILabel(46, 15, fmt.Sprintf("Name: %v", item.Name()), tcell.StyleDefault).Draw(v)
|
||||
ui.CreateSingleLineUILabel(46, 16, fmt.Sprintf("Desc: %v", item.Description()), tcell.StyleDefault).Draw(v)
|
||||
})
|
||||
|
||||
iss.help = ui.CreateSingleLineUILabel(45, 22, "hjkl - move, x - drop, e - equip", tcell.StyleDefault)
|
||||
iss.exitMenu = false
|
||||
iss.inventoryMenu = menu.CreatePlayerInventoryMenu(43, 0, player.Inventory(), tcell.StyleDefault, tcell.StyleDefault.Background(tcell.ColorDarkSlateGray))
|
||||
|
||||
return iss
|
||||
}
|
||||
|
@ -190,27 +99,17 @@ func (iss *InventoryScreenState) OnTick(dt int64) GameState {
|
|||
iss.selectedInventorySlot = iss.selectedInventorySlot.WithOffset(+1, 0)
|
||||
}
|
||||
|
||||
iss.inventoryGrid.Highlight(iss.selectedInventorySlot)
|
||||
iss.inventoryMenu.SelectSlot(iss.selectedInventorySlot.XY())
|
||||
iss.moveInventorySlotDirection = model.DirectionNone
|
||||
}
|
||||
|
||||
return iss
|
||||
}
|
||||
|
||||
func (iss *InventoryScreenState) CollectDrawables() []render.Drawable {
|
||||
func (iss *InventoryScreenState) CollectDrawables() []engine.Drawable {
|
||||
drawables := append(
|
||||
iss.prevState.CollectDrawables(),
|
||||
iss.inventoryMenu,
|
||||
iss.armourLabel,
|
||||
iss.armourGrid,
|
||||
iss.leftHandLabel,
|
||||
iss.leftHandBox,
|
||||
iss.rightHandLabel,
|
||||
iss.rightHandBox,
|
||||
iss.inventoryGrid,
|
||||
iss.playerItems,
|
||||
iss.selectedItem,
|
||||
iss.help,
|
||||
)
|
||||
|
||||
return drawables
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package state
|
||||
|
||||
import (
|
||||
"mvvasilev/last_light/render"
|
||||
"mvvasilev/last_light/engine"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
)
|
||||
|
@ -17,6 +17,6 @@ func (ls *LookState) OnTick(dt int64) GameState {
|
|||
panic("not implemented") // TODO: Implement
|
||||
}
|
||||
|
||||
func (ls *LookState) CollectDrawables() []render.Drawable {
|
||||
func (ls *LookState) CollectDrawables() []engine.Drawable {
|
||||
panic("not implemented") // TODO: Implement
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
package state
|
||||
|
||||
import (
|
||||
"mvvasilev/last_light/render"
|
||||
"mvvasilev/last_light/ui"
|
||||
"mvvasilev/last_light/engine"
|
||||
"mvvasilev/last_light/game/ui"
|
||||
"mvvasilev/last_light/util"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
)
|
||||
|
||||
type MainMenuState struct {
|
||||
menuTitle *render.Raw
|
||||
menuTitle *engine.Raw
|
||||
buttons []*ui.UISimpleButton
|
||||
currButtonSelected int
|
||||
|
||||
|
@ -22,7 +22,7 @@ func NewMainMenuState() *MainMenuState {
|
|||
|
||||
highlightStyle := tcell.StyleDefault.Attributes(tcell.AttrBold)
|
||||
|
||||
state.menuTitle = render.CreateRawDrawable(
|
||||
state.menuTitle = engine.CreateRawDrawable(
|
||||
11, 1, tcell.StyleDefault.Attributes(tcell.AttrBold).Foreground(tcell.ColorYellow),
|
||||
" | | | _) | | ",
|
||||
" | _` | __| __| | | _` | __ \\ __|",
|
||||
|
@ -77,8 +77,8 @@ func (mms *MainMenuState) OnTick(dt int64) GameState {
|
|||
return mms
|
||||
}
|
||||
|
||||
func (mms *MainMenuState) CollectDrawables() []render.Drawable {
|
||||
arr := make([]render.Drawable, 0)
|
||||
func (mms *MainMenuState) CollectDrawables() []engine.Drawable {
|
||||
arr := make([]engine.Drawable, 0)
|
||||
|
||||
arr = append(arr, mms.menuTitle)
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package state
|
||||
|
||||
import (
|
||||
"mvvasilev/last_light/render"
|
||||
"mvvasilev/last_light/ui"
|
||||
"mvvasilev/last_light/engine"
|
||||
"mvvasilev/last_light/game/ui"
|
||||
"mvvasilev/last_light/util"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
|
@ -26,7 +26,7 @@ func PauseGame(prevState PausableState) *PauseGameState {
|
|||
|
||||
highlightStyle := tcell.StyleDefault.Attributes(tcell.AttrBold)
|
||||
|
||||
s.pauseMenuWindow = ui.CreateWindow(int(render.TERMINAL_SIZE_WIDTH)/2-15, int(render.TERMINAL_SIZE_HEIGHT)/2-7, 30, 14, "PAUSED", tcell.StyleDefault)
|
||||
s.pauseMenuWindow = ui.CreateWindow(int(engine.TERMINAL_SIZE_WIDTH)/2-15, int(engine.TERMINAL_SIZE_HEIGHT)/2-7, 30, 14, "PAUSED", tcell.StyleDefault)
|
||||
s.buttons = make([]*ui.UISimpleButton, 0)
|
||||
s.buttons = append(
|
||||
s.buttons,
|
||||
|
@ -96,8 +96,8 @@ func (pg *PauseGameState) OnTick(dt int64) GameState {
|
|||
return pg
|
||||
}
|
||||
|
||||
func (pg *PauseGameState) CollectDrawables() []render.Drawable {
|
||||
arr := make([]render.Drawable, 0)
|
||||
func (pg *PauseGameState) CollectDrawables() []engine.Drawable {
|
||||
arr := make([]engine.Drawable, 0)
|
||||
|
||||
arr = append(arr, pg.prevState.CollectDrawables()...)
|
||||
|
||||
|
|
|
@ -2,9 +2,9 @@ package state
|
|||
|
||||
import (
|
||||
"math/rand"
|
||||
"mvvasilev/last_light/engine"
|
||||
"mvvasilev/last_light/game/model"
|
||||
"mvvasilev/last_light/game/world"
|
||||
"mvvasilev/last_light/render"
|
||||
"mvvasilev/last_light/util"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
|
@ -16,7 +16,7 @@ type PlayingState struct {
|
|||
entityMap *world.EntityMap
|
||||
level *world.MultilevelMap
|
||||
|
||||
viewport *render.Viewport
|
||||
viewport *engine.Viewport
|
||||
|
||||
movePlayerDirection model.Direction
|
||||
pauseGame bool
|
||||
|
@ -51,7 +51,7 @@ func BeginPlayingState() *PlayingState {
|
|||
|
||||
s.entityMap.AddEntity(s.player, '@', tcell.StyleDefault)
|
||||
|
||||
s.viewport = render.CreateViewport(
|
||||
s.viewport = engine.CreateViewport(
|
||||
util.PositionAt(0, 0),
|
||||
dungeonLevel.PlayerSpawnPoint(),
|
||||
util.SizeOf(80, 24),
|
||||
|
@ -207,8 +207,8 @@ func (ps *PlayingState) OnTick(dt int64) GameState {
|
|||
return ps
|
||||
}
|
||||
|
||||
func (ps *PlayingState) CollectDrawables() []render.Drawable {
|
||||
return render.Multidraw(render.CreateDrawingInstructions(func(v views.View) {
|
||||
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)
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package state
|
||||
|
||||
import (
|
||||
"mvvasilev/last_light/render"
|
||||
"mvvasilev/last_light/engine"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
)
|
||||
|
@ -17,6 +17,6 @@ func (q *QuitState) OnTick(dt int64) GameState {
|
|||
return q
|
||||
}
|
||||
|
||||
func (q *QuitState) CollectDrawables() []render.Drawable {
|
||||
return render.Multidraw(nil)
|
||||
func (q *QuitState) CollectDrawables() []engine.Drawable {
|
||||
return engine.Multidraw(nil)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package ui
|
||||
|
||||
import (
|
||||
"mvvasilev/last_light/render"
|
||||
"mvvasilev/last_light/engine"
|
||||
"mvvasilev/last_light/util"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
|
@ -12,8 +12,8 @@ import (
|
|||
type UIBorderedButton struct {
|
||||
id uuid.UUID
|
||||
|
||||
text render.Text
|
||||
border render.Rectangle
|
||||
text engine.Text
|
||||
border engine.Rectangle
|
||||
|
||||
isSelected bool
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package ui
|
||||
|
||||
import (
|
||||
"mvvasilev/last_light/render"
|
||||
"mvvasilev/last_light/engine"
|
||||
"mvvasilev/last_light/util"
|
||||
"unicode/utf8"
|
||||
|
||||
|
@ -12,14 +12,14 @@ import (
|
|||
|
||||
type UILabel struct {
|
||||
id uuid.UUID
|
||||
text *render.Text
|
||||
text *engine.Text
|
||||
}
|
||||
|
||||
func CreateUILabel(x, y int, width, height int, content string, style tcell.Style) *UILabel {
|
||||
label := new(UILabel)
|
||||
|
||||
label.id = uuid.New()
|
||||
label.text = render.CreateText(x, y, width, height, content, style)
|
||||
label.text = engine.CreateText(x, y, width, height, content, style)
|
||||
|
||||
return label
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ func CreateSingleLineUILabel(x, y int, content string, style tcell.Style) *UILab
|
|||
label := new(UILabel)
|
||||
|
||||
label.id = uuid.New()
|
||||
label.text = render.CreateText(x, y, int(utf8.RuneCountInString(content)), 1, content, style)
|
||||
label.text = engine.CreateText(x, y, int(utf8.RuneCountInString(content)), 1, content, style)
|
||||
|
||||
return label
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ func (t *UILabel) UniqueId() uuid.UUID {
|
|||
}
|
||||
|
||||
func (t *UILabel) MoveTo(x int, y int) {
|
||||
t.text = render.CreateText(x, y, int(t.text.Size().Width()), int(t.Size().Height()), t.text.Content(), t.text.Style())
|
||||
t.text = engine.CreateText(x, y, int(t.text.Size().Width()), int(t.Size().Height()), t.text.Content(), t.text.Style())
|
||||
}
|
||||
|
||||
func (t *UILabel) Position() util.Position {
|
175
game/ui/menu/player_inventory_menu.go
Normal file
175
game/ui/menu/player_inventory_menu.go
Normal file
|
@ -0,0 +1,175 @@
|
|||
package menu
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"mvvasilev/last_light/engine"
|
||||
"mvvasilev/last_light/game/model"
|
||||
"mvvasilev/last_light/game/ui"
|
||||
"mvvasilev/last_light/util"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/gdamore/tcell/v2/views"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type PlayerInventoryMenu struct {
|
||||
inventory *model.EquippedInventory
|
||||
|
||||
inventoryMenu *ui.UIWindow
|
||||
armourLabel *ui.UILabel
|
||||
armourGrid *engine.Grid
|
||||
leftHandLabel *ui.UILabel
|
||||
leftHandBox engine.Rectangle
|
||||
rightHandLabel *ui.UILabel
|
||||
rightHandBox engine.Rectangle
|
||||
inventoryGrid *engine.Grid
|
||||
playerItems *engine.ArbitraryDrawable
|
||||
selectedItem *engine.ArbitraryDrawable
|
||||
help *ui.UILabel
|
||||
|
||||
selectedInventorySlot util.Position
|
||||
}
|
||||
|
||||
func CreatePlayerInventoryMenu(x, y int, playerInventory *model.EquippedInventory, style tcell.Style, highlightStyle tcell.Style) *PlayerInventoryMenu {
|
||||
menu := new(PlayerInventoryMenu)
|
||||
|
||||
menu.inventory = playerInventory
|
||||
|
||||
menu.inventoryMenu = ui.CreateWindow(x, y, 37, 24, "INVENTORY", style)
|
||||
|
||||
menu.armourLabel = ui.CreateSingleLineUILabel(x+15, y+1, "ARMOUR", style)
|
||||
|
||||
menu.armourGrid = engine.CreateGrid(
|
||||
x+10, y+2, 3, 1, 4, 1, '┌', '─', '┬', '┐', '│', ' ', '│', '│', '├', '─', '┼', '┤', '└', '─', '┴', '┘', style, highlightStyle, //style.Background(tcell.ColorDarkSlateGray),
|
||||
)
|
||||
|
||||
menu.leftHandLabel = ui.CreateUILabel(
|
||||
x+3, y+1, 5, 1, "OFF", style,
|
||||
)
|
||||
|
||||
menu.leftHandBox = engine.CreateRectangle(
|
||||
x+2, y+2, 5, 3,
|
||||
'┌', '─', '┐',
|
||||
'│', ' ', '│',
|
||||
'└', '─', '┘',
|
||||
false, true,
|
||||
style,
|
||||
)
|
||||
|
||||
menu.rightHandLabel = ui.CreateUILabel(
|
||||
x+31, y+1, 5, 1, "DOM", style,
|
||||
)
|
||||
|
||||
menu.rightHandBox = engine.CreateRectangle(
|
||||
x+30, y+2, 5, 3,
|
||||
'┌', '─', '┐',
|
||||
'│', ' ', '│',
|
||||
'└', '─', '┘',
|
||||
false, true,
|
||||
style,
|
||||
)
|
||||
|
||||
menu.inventoryGrid = engine.CreateGrid(
|
||||
x+2, y+5, 3, 1, 8, 4, '┌', '─', '┬', '┐', '│', ' ', '│', '│', '├', '─', '┼', '┤', '└', '─', '┴', '┘', style, highlightStyle,
|
||||
)
|
||||
|
||||
menu.playerItems = engine.CreateDrawingInstructions(func(v views.View) {
|
||||
for y := range playerInventory.Shape().Height() {
|
||||
for x := range playerInventory.Shape().Width() {
|
||||
item := playerInventory.ItemAt(x, y)
|
||||
isHighlighted := x == menu.selectedInventorySlot.X() && y == menu.selectedInventorySlot.Y()
|
||||
|
||||
if item == nil {
|
||||
|
||||
if isHighlighted {
|
||||
ui.CreateSingleLineUILabel(
|
||||
menu.inventoryGrid.Position().X()+1+x*4,
|
||||
menu.inventoryGrid.Position().Y()+1+y*2,
|
||||
" ",
|
||||
highlightStyle,
|
||||
).Draw(v)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
style := item.Type().Style()
|
||||
|
||||
if isHighlighted {
|
||||
style = highlightStyle
|
||||
}
|
||||
|
||||
ui.CreateSingleLineUILabel(
|
||||
menu.inventoryGrid.Position().X()+1+x*4,
|
||||
menu.inventoryGrid.Position().Y()+y*2,
|
||||
fmt.Sprintf("%03d", item.Quantity()),
|
||||
style,
|
||||
).Draw(v)
|
||||
|
||||
ui.CreateSingleLineUILabel(
|
||||
menu.inventoryGrid.Position().X()+1+x*4,
|
||||
menu.inventoryGrid.Position().Y()+1+y*2,
|
||||
item.Type().Icon(),
|
||||
style,
|
||||
).Draw(v)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
menu.selectedItem = engine.CreateDrawingInstructions(func(v views.View) {
|
||||
ui.CreateWindow(x+2, y+14, 33, 8, "ITEM", style).Draw(v)
|
||||
|
||||
item := playerInventory.ItemAt(menu.selectedInventorySlot.XY())
|
||||
|
||||
if item == nil {
|
||||
return
|
||||
}
|
||||
|
||||
ui.CreateSingleLineUILabel(x+3, y+15, fmt.Sprintf("Name: %v", item.Name()), style).Draw(v)
|
||||
ui.CreateSingleLineUILabel(x+3, y+16, fmt.Sprintf("Desc: %v", item.Description()), style).Draw(v)
|
||||
})
|
||||
|
||||
menu.help = ui.CreateSingleLineUILabel(x+2, y+22, "hjkl - move, x - drop, e - equip", style)
|
||||
|
||||
return menu
|
||||
}
|
||||
|
||||
func (pim *PlayerInventoryMenu) MoveTo(x int, y int) {
|
||||
|
||||
}
|
||||
|
||||
func (pim *PlayerInventoryMenu) Position() util.Position {
|
||||
return pim.inventoryMenu.Position()
|
||||
}
|
||||
|
||||
func (pim *PlayerInventoryMenu) Size() util.Size {
|
||||
return pim.inventoryMenu.Size()
|
||||
}
|
||||
|
||||
func (pim *PlayerInventoryMenu) Input(e *tcell.EventKey) {
|
||||
|
||||
}
|
||||
|
||||
func (pim *PlayerInventoryMenu) UniqueId() uuid.UUID {
|
||||
return pim.inventoryMenu.UniqueId()
|
||||
}
|
||||
|
||||
func (pim *PlayerInventoryMenu) SelectSlot(x, y int) {
|
||||
pim.inventoryGrid.Unhighlight()
|
||||
pim.selectedInventorySlot = util.PositionAt(x, y)
|
||||
pim.inventoryGrid.Highlight(pim.selectedInventorySlot)
|
||||
}
|
||||
|
||||
func (pim *PlayerInventoryMenu) Draw(v views.View) {
|
||||
pim.inventoryMenu.Draw(v)
|
||||
pim.armourLabel.Draw(v)
|
||||
pim.armourGrid.Draw(v)
|
||||
pim.leftHandLabel.Draw(v)
|
||||
pim.leftHandBox.Draw(v)
|
||||
pim.rightHandLabel.Draw(v)
|
||||
pim.rightHandBox.Draw(v)
|
||||
pim.inventoryGrid.Draw(v)
|
||||
pim.playerItems.Draw(v)
|
||||
pim.selectedItem.Draw(v)
|
||||
pim.help.Draw(v)
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package ui
|
||||
|
||||
import (
|
||||
"mvvasilev/last_light/render"
|
||||
"mvvasilev/last_light/engine"
|
||||
"mvvasilev/last_light/util"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
@ -14,7 +14,7 @@ import (
|
|||
type UISimpleButton struct {
|
||||
id uuid.UUID
|
||||
isHighlighted bool
|
||||
text *render.Text
|
||||
text *engine.Text
|
||||
selectHandler func()
|
||||
unhighlightedStyle tcell.Style
|
||||
highlightedStyle tcell.Style
|
||||
|
@ -24,7 +24,7 @@ func CreateSimpleButton(x, y int, text string, unhighlightedStyle, highlightedSt
|
|||
sb := new(UISimpleButton)
|
||||
|
||||
sb.id = uuid.New()
|
||||
sb.text = render.CreateText(x, y, int(utf8.RuneCountInString(text)), 1, text, unhighlightedStyle)
|
||||
sb.text = engine.CreateText(x, y, int(utf8.RuneCountInString(text)), 1, text, unhighlightedStyle)
|
||||
sb.isHighlighted = false
|
||||
sb.selectHandler = onSelect
|
||||
sb.highlightedStyle = highlightedStyle
|
||||
|
@ -50,7 +50,7 @@ func (sb *UISimpleButton) Highlight() {
|
|||
|
||||
newContent := "[ " + sb.text.Content() + " ]"
|
||||
|
||||
sb.text = render.CreateText(
|
||||
sb.text = engine.CreateText(
|
||||
int(sb.Position().X()-2), int(sb.Position().Y()),
|
||||
int(utf8.RuneCountInString(newContent)), 1,
|
||||
newContent,
|
||||
|
@ -65,7 +65,7 @@ func (sb *UISimpleButton) Unhighlight() {
|
|||
content = strings.Trim(content, "[ ")
|
||||
contentLen := utf8.RuneCountInString(content)
|
||||
|
||||
sb.text = render.CreateText(
|
||||
sb.text = engine.CreateText(
|
||||
int(sb.Position().X()+2), int(sb.Position().Y()),
|
||||
int(contentLen), 1,
|
||||
content,
|
||||
|
@ -82,7 +82,7 @@ func (sb *UISimpleButton) UniqueId() uuid.UUID {
|
|||
}
|
||||
|
||||
func (sb *UISimpleButton) MoveTo(x int, y int) {
|
||||
sb.text = render.CreateText(x, y, int(utf8.RuneCountInString(sb.text.Content())), 1, sb.text.Content(), sb.highlightedStyle)
|
||||
sb.text = engine.CreateText(x, y, int(utf8.RuneCountInString(sb.text.Content())), 1, sb.text.Content(), sb.highlightedStyle)
|
||||
}
|
||||
|
||||
func (sb *UISimpleButton) Position() util.Position {
|
|
@ -1,7 +1,7 @@
|
|||
package ui
|
||||
|
||||
import (
|
||||
"mvvasilev/last_light/render"
|
||||
"mvvasilev/last_light/engine"
|
||||
"mvvasilev/last_light/util"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
|
@ -13,7 +13,7 @@ type UIElement interface {
|
|||
Size() util.Size
|
||||
Input(e *tcell.EventKey)
|
||||
|
||||
render.Drawable
|
||||
engine.Drawable
|
||||
}
|
||||
|
||||
type UIHighlightableElement interface {
|
|
@ -1,7 +1,7 @@
|
|||
package ui
|
||||
|
||||
import (
|
||||
"mvvasilev/last_light/render"
|
||||
"mvvasilev/last_light/engine"
|
||||
"mvvasilev/last_light/util"
|
||||
"unicode/utf8"
|
||||
|
||||
|
@ -13,8 +13,8 @@ import (
|
|||
type UIWindow struct {
|
||||
id uuid.UUID
|
||||
|
||||
title *render.Text
|
||||
box render.Rectangle
|
||||
title *engine.Text
|
||||
box engine.Rectangle
|
||||
}
|
||||
|
||||
func CreateWindow(x, y, width, height int, title string, style tcell.Style) *UIWindow {
|
||||
|
@ -24,9 +24,9 @@ func CreateWindow(x, y, width, height int, title string, style tcell.Style) *UIW
|
|||
|
||||
titlePos := (width / 2) - int(titleLen/2)
|
||||
|
||||
w.title = render.CreateText(x+titlePos, y, int(titleLen), 1, title, style)
|
||||
w.title = engine.CreateText(x+titlePos, y, int(titleLen), 1, title, style)
|
||||
|
||||
w.box = render.CreateRectangle(
|
||||
w.box = engine.CreateRectangle(
|
||||
x, y, width, height,
|
||||
'┌', '─', '┐',
|
||||
'│', ' ', '│',
|
|
@ -1,15 +1,11 @@
|
|||
package world
|
||||
|
||||
import "mvvasilev/last_light/game/model"
|
||||
|
||||
type dungeonLevel struct {
|
||||
groundLevel Map
|
||||
groundLevel *Map
|
||||
entityLevel *EntityMap
|
||||
itemLevel *Map
|
||||
}
|
||||
|
||||
type Dungeon struct {
|
||||
player *model.Player
|
||||
|
||||
levels []*dungeonLevel
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue