can move between rooms now!!!

master
Jordan Orelli 4 years ago
parent afd17fc6c4
commit e8b82f4b3f

@ -139,6 +139,9 @@ func (ui *UI) handleNotification(v wire.Value) bool {
if ui.room == nil { if ui.room == nil {
ui.room = new(wire.Room) ui.room = new(wire.Room)
} }
ui.room.Name = n.RoomName
ui.room.Rect = n.RoomSize
ui.room.Entities = n.Entities ui.room.Entities = n.Entities
return true return true

@ -10,20 +10,94 @@ type door struct {
*blammo.Log *blammo.Log
to string to string
exit int exit int
arrived int
} }
func (d *door) update(time.Duration) {} func (d *door) update(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)
dest, ok := w.rooms[d.to]
if !ok {
p.Error("door destination %q does not exist", d.to)
return result{}
}
p.Info("found destination room %q", d.to)
exit := dest.findEntity(d.exit)
if exit == nil {
p.Error("door exit %d does not exist", d.exit)
return result{}
}
exitDoor, ok := exit.behavior.(*door)
if !ok {
p.Error("exit entity %d is not a door", d.exit)
return result{}
}
p.Info("found exit door %v", exitDoor)
t := dest.getTile(exit.Position)
p.Info("exit tile: %v", t)
if t.isOccupied() {
p.Error("destination tile %v is occupied", t)
return result{}
}
p.Info("removing player from room %s", r.name)
r.removePlayer(p.name)
p.Info("adding player to room %s", dest.name)
if t.addEntity(p.avatar) {
p.Info("added player avatar to tile %v", t)
exitDoor.arrived = p.avatar.ID
p.avatar.Position = exit.Position
} else {
p.Error("failed to add player avatar to tile %v", t)
}
dest.addPlayer(p)
return result{}
}
func (d *door) onStartOverlap(e *entity) { func (d *door) onStartOverlap(e *entity) {
d.Info("start overlap: %v", e) if e.ID == d.arrived {
return
}
if p, ok := e.behavior.(*player); ok {
d.Info("player %s start overlap on door to %s", p.name, d.to)
if p.pending != nil {
d.Info("player %s starting overlap on door to %s has a pending request", p.name, d.to)
} else {
d.Info("player %s starting overlap on door to %s has NO pending request", p.name, d.to)
p.pending = &Request{Wants: d}
}
}
} }
func (d *door) onOverlap(e *entity) { func (d *door) onOverlap(e *entity) {
d.Info("overlap: %v", e) if e.ID == d.arrived {
return
}
// d.Info("overlap: %v", e)
if p, ok := e.behavior.(*player); ok {
d.Info("player %s is continuing overlap on door to %s", p.name, d.to)
if p.pending != nil {
d.Info("player %s continuing to overlap door to %s has a pending request", p.name, d.to)
} else {
d.Info("player %s continuing to overlap door to %s has NO pending request", p.name, d.to)
p.pending = &Request{Wants: d}
}
}
} }
func (d *door) onStopOverlap(e *entity) { func (d *door) onStopOverlap(e *entity) {
d.Info("stop overlap: %v", e) if e.ID == d.arrived {
d.arrived = 0
}
// d.Info("stop overlap: %v", e)
if p, ok := e.behavior.(*player); ok {
d.Info("player %s stepped off of door to %s", p.name, d.to)
}
} }
/* /*

@ -6,6 +6,10 @@ type Effect interface {
exec(*world, *room, *player, int) result exec(*world, *room, *player, int) result
} }
type effect func(*world, *room, *player, int) result
func (f effect) exec(w *world, r *room, p *player, seq int) result { return f(w, r, p, seq) }
type result struct { type result struct {
reply wire.Value reply wire.Value
} }

@ -97,6 +97,9 @@ func (p *player) runLoop(conn *websocket.Conn) {
for { for {
select { select {
case res := <-p.outbox: case res := <-p.outbox:
if err, ok := res.Body.(error); ok {
p.Error("sending error: %s", err)
}
if err := sendResponse(conn, res); err != nil { if err := sendResponse(conn, res); err != nil {
p.Error(err.Error()) p.Error(err.Error())
} }
@ -152,6 +155,8 @@ func sendResponse(conn *websocket.Conn, res wire.Response) error {
return nil return nil
} }
func (p *player) update(dt time.Duration) {}
type spawnPlayer struct{} type spawnPlayer struct{}
func (s spawnPlayer) exec(w *world, r *room, p *player, seq int) result { func (s spawnPlayer) exec(w *world, r *room, p *player, seq int) result {
@ -159,14 +164,16 @@ func (s spawnPlayer) exec(w *world, r *room, p *player, seq int) result {
ID: <-w.nextID, ID: <-w.nextID,
Glyph: '@', Glyph: '@',
solid: true, solid: true,
behavior: doNothing{}, behavior: p,
} }
p.avatar = &e p.avatar = &e
for n, t := range r.tiles { for n, _ := range r.tiles {
t := &r.tiles[n]
x, y := n%r.Width, n/r.Width x, y := n%r.Width, n/r.Width
e.Position = math.Vec{x, y} e.Position = math.Vec{x, y}
if t.addEntity(&e) { if t.addEntity(&e) {
p.Info("player added to tile at %s", e.Position)
return result{} return result{}
} }
} }
@ -182,15 +189,26 @@ func (m *Move) exec(w *world, r *room, p *player, seq int) result {
target := pos.Add(math.Vec(*m)) target := pos.Add(math.Vec(*m))
p.Info("running move for player %s from %v to %v", p.name, p.avatar.Position, target) p.Info("running move for player %s from %v to %v", p.name, p.avatar.Position, target)
if !r.Contains(target) { if !r.Contains(target) {
p.Error("target cell (%d, %d) is out of bounds", target.X, target.Y)
return result{reply: wire.Errorf("target cell (%d, %d) is out of bounds", target.X, target.Y)} return result{reply: wire.Errorf("target cell (%d, %d) is out of bounds", target.X, target.Y)}
} }
currentTile := r.getTile(pos) currentTile := r.getTile(pos)
if !currentTile.hasEntity(p.avatar.ID) {
p.Error("player cannot move off of %s because they were not actually there", pos)
p.Error("tile %d: %v", pos, currentTile)
return result{reply: wire.Errorf("player cannot move off of %s because they were not actually there", pos)}
}
nextTile := r.getTile(target) nextTile := r.getTile(target)
if !nextTile.addEntity(p.avatar) { if nextTile.isOccupied() {
p.Error("target cell (%d, %d) is occupied", target.X, target.Y)
return result{reply: wire.Errorf("target cell (%d, %d) is occupied", target.X, target.Y)} return result{reply: wire.Errorf("target cell (%d, %d) is occupied", target.X, target.Y)}
} }
currentTile.removeEntity(p.avatar.ID) currentTile.removeEntity(p.avatar.ID)
nextTile.addEntity(p.avatar)
p.avatar.Position = target p.avatar.Position = target
return result{reply: wire.OK{}} return result{reply: wire.OK{}}
} }

@ -36,6 +36,17 @@ func (r *room) playerAvatars() map[string]int {
return all return all
} }
func (r *room) findEntity(id int) *entity {
for _, t := range r.tiles {
for _, e := range t.here {
if e.ID == id {
return e
}
}
}
return nil
}
func (r *room) addEntity(e *entity) bool { func (r *room) addEntity(e *entity) bool {
t := r.getTile(e.Position) t := r.getTile(e.Position)
if t == nil { if t == nil {
@ -49,8 +60,12 @@ func (r *room) addPlayer(p *player) {
} }
func (r *room) removePlayer(name string) bool { func (r *room) removePlayer(name string) bool {
if _, ok := r.players[name]; ok { if p, ok := r.players[name]; ok {
delete(r.players, name) delete(r.players, name)
t := r.getTile(p.avatar.Position)
if t != nil {
t.removeEntity(p.avatar.ID)
}
return true return true
} }
return false return false

@ -1,6 +1,7 @@
package sim package sim
import ( import (
"fmt"
"time" "time"
) )
@ -9,6 +10,14 @@ type tile struct {
here []*entity here []*entity
} }
func (t tile) String() string {
ids := make([]int, len(t.here))
for i, e := range t.here {
ids[i] = e.ID
}
return fmt.Sprintf("{%c %v}", t.floor, ids)
}
func (t *tile) addEntity(e *entity) bool { func (t *tile) addEntity(e *entity) bool {
if e.solid { if e.solid {
for _, other := range t.here { for _, other := range t.here {
@ -21,7 +30,8 @@ func (t *tile) addEntity(e *entity) bool {
return true return true
} }
func (t *tile) removeEntity(id int) { func (t *tile) removeEntity(id int) bool {
start := len(t.here)
here := t.here[:0] here := t.here[:0]
for _, e := range t.here { for _, e := range t.here {
if e.ID != id { if e.ID != id {
@ -29,6 +39,25 @@ func (t *tile) removeEntity(id int) {
} }
} }
t.here = here t.here = here
return len(t.here) != start
}
func (t *tile) hasEntity(id int) bool {
for _, e := range t.here {
if e.ID == id {
return true
}
}
return false
}
func (t *tile) isOccupied() bool {
for _, e := range t.here {
if e.solid {
return true
}
}
return false
} }
func (t *tile) update(d time.Duration) { func (t *tile) update(d time.Duration) {

@ -247,6 +247,8 @@ func (w *world) tick(d time.Duration) {
// send frame data to all players // send frame data to all players
for _, r := range w.rooms { for _, r := range w.rooms {
frame := wire.Frame{ frame := wire.Frame{
RoomName: r.name,
RoomSize: r.Rect,
Entities: r.allEntities(), Entities: r.allEntities(),
Players: r.playerAvatars(), Players: r.playerAvatars(),
} }

@ -1,6 +1,10 @@
package wire package wire
import "github.com/jordanorelli/astro-domu/internal/math"
type Frame struct { type Frame struct {
RoomName string `json:"room_name"`
RoomSize math.Rect `json:"room_size"`
Entities map[int]Entity `json:"entities"` Entities map[int]Entity `json:"entities"`
Players map[string]int `json:"players"` Players map[string]int `json:"players"`
} }

Loading…
Cancel
Save