From bf05df3292d42a6d7bf49fc594198849e9eedf61 Mon Sep 17 00:00:00 2001 From: Jordan Orelli Date: Wed, 11 Nov 2020 02:49:13 +0000 Subject: [PATCH] howwwwwwww do you put objects DOWN --- internal/app/game_view.go | 9 ++++++ internal/app/inventory.go | 25 +++++++++++++-- internal/math/vec.go | 3 ++ internal/sim/door.go | 2 +- internal/sim/entity.go | 4 +-- internal/sim/player.go | 67 ++++++++++++++++++++++++++++++++++++++- internal/sim/potato.go | 38 ++++++++++++++++++++++ internal/sim/tile.go | 2 +- internal/sim/world.go | 20 ++++++++++++ 9 files changed, 163 insertions(+), 7 deletions(-) create mode 100644 internal/sim/potato.go diff --git a/internal/app/game_view.go b/internal/app/game_view.go index ab43b74..dcd4c52 100644 --- a/internal/app/game_view.go +++ b/internal/app/game_view.go @@ -51,6 +51,9 @@ func (v *gameView) walkHandler(e *tcell.EventKey) change { case 'p': v.keyHandler = v.pickupHandler v.statusLine = "(pickup)" + case 'P': + v.keyHandler = v.putdownHandler + v.statusLine = "(put down)" } } return nil @@ -116,6 +119,12 @@ func (v *gameView) pickupHandler(e *tcell.EventKey) change { return nil } +func (v *gameView) putdownHandler(e *tcell.EventKey) change { + v.keyHandler = v.walkHandler + v.statusLine = "(walk)" + return nil +} + func (v *gameView) draw(img canvas, st *state) { fill(img, tcell.StyleDefault.Background(tcell.NewRGBColor(0, 0, 12))) v.drawHeader(img, st) diff --git a/internal/app/inventory.go b/internal/app/inventory.go index 464587a..0592d87 100644 --- a/internal/app/inventory.go +++ b/internal/app/inventory.go @@ -16,11 +16,27 @@ type item struct { } type inventoryView struct { + highlight int + *inventory } func (v *inventoryView) handleEvent(e tcell.Event) change { - if k, ok := e.(*tcell.EventKey); ok { - if k.Key() == tcell.KeyESC { + switch t := e.(type) { + case *tcell.EventKey: + key := t.Key() + switch key { + case tcell.KeyEnter: + case tcell.KeyDown: + if len(v.items) > 0 { + v.highlight = (v.highlight + 1) % len(v.items) + } + + case tcell.KeyUp: + if len(v.items) > 0 { + v.highlight = (v.highlight - 1 + len(v.items)) % len(v.items) + } + + case tcell.KeyESC: return changeFn(func(ui *UI) { if ui.root == inGameView { inGameView.focus(0) @@ -28,13 +44,18 @@ func (v *inventoryView) handleEvent(e tcell.Event) change { }) } } + return nil } func (v *inventoryView) draw(img canvas, st *state) { + v.inventory = &st.inventory writeString(img, "Inventory", math.Vec{0, 0}, tcell.StyleDefault) for i, item := range st.inventory.items { line := fmt.Sprintf("- %s", item.name) + if i == v.highlight { + line = fmt.Sprintf("+ %s", item.name) + } writeString(img, line, math.Vec{0, i + 2}, tcell.StyleDefault) } } diff --git a/internal/math/vec.go b/internal/math/vec.go index 140928b..0b03201 100644 --- a/internal/math/vec.go +++ b/internal/math/vec.go @@ -45,3 +45,6 @@ func (v Vec) Unit() Vec { } return out } + +// MDist calculates the manhattan distance between two vectors. +func (v Vec) MDist(v2 Vec) int { return Abs(v.X-v2.X) + Abs(v.Y-v2.Y) } diff --git a/internal/sim/door.go b/internal/sim/door.go index a7a44b6..3404178 100644 --- a/internal/sim/door.go +++ b/internal/sim/door.go @@ -13,7 +13,7 @@ type door struct { arrived int } -func (d *door) update(time.Duration) {} +func (d *door) update(*entity, time.Duration) {} func (d *door) exec(w *world, r *room, p *player, seq int) result { p.Info("executing door to %q for player %s", d.to, p.name) diff --git a/internal/sim/entity.go b/internal/sim/entity.go index 1faa833..06ae1b6 100644 --- a/internal/sim/entity.go +++ b/internal/sim/entity.go @@ -79,9 +79,9 @@ func (e *entity) stopOverlap(e2 *entity) { type behavior interface { // update is the standard tick function - update(time.Duration) + update(*entity, time.Duration) } type doNothing struct{} -func (d doNothing) update(time.Duration) {} +func (d doNothing) update(*entity, time.Duration) {} diff --git a/internal/sim/player.go b/internal/sim/player.go index bf34c7a..8fbc022 100644 --- a/internal/sim/player.go +++ b/internal/sim/player.go @@ -165,7 +165,26 @@ func sendResponse(conn *websocket.Conn, res wire.Response) error { return nil } -func (p *player) update(dt time.Duration) {} +func (p *player) removeItem(id int) *entity { + for i, e := range p.inventory { + if e.ID == id { + p.inventory = append(p.inventory[:i], p.inventory[i+1:]...) + return e + } + } + return nil +} + +func (p *player) peekItem(id int) *entity { + for _, e := range p.inventory { + if e.ID == id { + return e + } + } + return nil +} + +func (p *player) update(*entity, time.Duration) {} type spawnPlayer struct{} @@ -179,6 +198,16 @@ func (s spawnPlayer) exec(w *world, r *room, p *player, seq int) result { } p.avatar = &e + p.inventory = append(p.inventory, &entity{ + ID: <-w.nextID, + Glyph: 'p', + solid: false, + name: "a potato", + description: "it's a potato, what more information could you need?", + pickupable: true, + behavior: &potato{}, + }) + for n, _ := range r.tiles { t := &r.tiles[n] x, y := n%r.Width, n/r.Width @@ -277,6 +306,41 @@ type Pickedup struct { func (p Pickedup) NetTag() string { return "pickedup" } +type Putdown struct { + ID int `json:"id"` + Location math.Vec `json:"loc"` +} + +func (pd *Putdown) exec(w *world, r *room, pl *player, seq int) result { + pos := pl.avatar.Position + if pos.MDist(pd.Location) > 1 { + return result{reply: wire.Errorf("destination tile %v is too far from your current location at %v", pd.Location, pos)} + } + + nextTile := r.getTile(pd.Location) + if nextTile == nil { + return result{reply: wire.Errorf("no tile at location %v", pd.Location)} + } + + item := pl.peekItem(pd.ID) + if item == nil { + return result{reply: wire.Errorf("you're not holding an item with ID %d", pd.ID)} + } + + if item.solid { + for _, e := range nextTile.here { + if e.solid { + return result{reply: wire.Errorf("you can't put a %s on top of a %s", item.name, e.name)} + } + } + } + + nextTile.addEntity(pl.removeItem(pd.ID)) + return result{reply: wire.OK{}} +} + +func (Putdown) NetTag() string { return "put-down" } + var lastEntityID = 0 func init() { @@ -285,4 +349,5 @@ func init() { wire.Register(func() wire.Value { return new(LookAt) }) wire.Register(func() wire.Value { return new(Pickup) }) wire.Register(func() wire.Value { return new(Pickedup) }) + wire.Register(func() wire.Value { return new(Putdown) }) } diff --git a/internal/sim/potato.go b/internal/sim/potato.go new file mode 100644 index 0000000..f8297c6 --- /dev/null +++ b/internal/sim/potato.go @@ -0,0 +1,38 @@ +package sim + +import ( + "time" +) + +type stageOfGrowth int + +const ( + unborn stageOfGrowth = iota + planted + sapling + unripe + ripe + overripe + rotting + dead +) + +type potato struct { + planted time.Duration + stage stageOfGrowth +} + +func (p *potato) update(e *entity, dt time.Duration) { + if p.stage > unborn { + p.planted += dt + } +} + +type percent int + +func (p *potato) progress() percent { + if p.stage <= unborn { + return 0 + } + return 100 +} diff --git a/internal/sim/tile.go b/internal/sim/tile.go index 872951c..5d8b345 100644 --- a/internal/sim/tile.go +++ b/internal/sim/tile.go @@ -62,7 +62,7 @@ func (t *tile) isOccupied() bool { func (t *tile) update(d time.Duration) { for _, e := range t.here { - e.update(d) + e.update(e, d) } } diff --git a/internal/sim/world.go b/internal/sim/world.go index 5dc4cc8..334156d 100644 --- a/internal/sim/world.go +++ b/internal/sim/world.go @@ -49,6 +49,26 @@ func newWorld(log *blammo.Log) *world { behavior: doNothing{}, }) + foyer.addEntity(&entity{ + ID: -2, + Position: math.Vec{5, 5}, + Glyph: 'o', + solid: true, + pickupable: true, + name: "another rock", + behavior: doNothing{}, + }) + + foyer.addEntity(&entity{ + ID: -3, + Position: math.Vec{5, 6}, + Glyph: 'o', + solid: true, + pickupable: true, + name: "yet another rock (YAR)", + behavior: doNothing{}, + }) + foyer.addEntity(&entity{ ID: -4, Position: math.Vec{9, 5},