diff --git a/game/save.go b/game/save.go index e69b065..038bd43 100644 --- a/game/save.go +++ b/game/save.go @@ -177,8 +177,48 @@ func (g *RogueGame) packIdx(obj *Object) int { // snapshot captures the complete game state. func (g *RogueGame) snapshot() *SaveState { - p := &g.Player - st := &SaveState{ + st := g.snapshotHeader() + + // the map, sans monster pointers (rebuilt on load) + st.Places = make([]savedPlace, len(g.Level.Places)) + for i := range g.Level.Places { + st.Places[i] = savedPlace{ + Ch: g.Level.Places[i].Ch, + Flags: g.Level.Places[i].Flags, + } + } + + // level objects by value; remember their pointers for dest encoding + objAt := make(map[*Object]int, len(g.Level.Objects)) + for i, o := range g.Level.Objects { + st.Objects = append(st.Objects, *o) + objAt[o] = i + } + + st.Player = g.snapshotPlayer() + + // monsters, with chase targets as (kind, index) references + for _, m := range g.Level.Monsters { + sc := savedCreature{ + Pos: m.Pos, Turn: m.Turn, Type: m.Type, Disguise: m.Disguise, + OldCh: m.OldCh, Flags: m.Flags, Stats: m.Stats, + RoomIdx: g.roomIdx(m.Room), + } + for _, o := range m.Pack { + sc.Pack = append(sc.Pack, *o) + } + + st.Monsters = append(st.Monsters, sc) + st.Dests = append(st.Dests, g.destRefFor(m, objAt)) + } + + return st +} + +// snapshotHeader captures the scalar game state (the field list of +// state.c rs_save_file). +func (g *RogueGame) snapshotHeader() *SaveState { + return &SaveState{ Version: saveFormatVersion, Seed: g.Rng.Seed, Dnum: g.Dnum, @@ -226,25 +266,14 @@ func (g *RogueGame) snapshot() *SaveState { AllScore: g.AllScore, Screen: g.scr.Std.Contents(), } +} - // the map, sans monster pointers (rebuilt on load) - st.Places = make([]savedPlace, len(g.Level.Places)) - for i := range g.Level.Places { - st.Places[i] = savedPlace{ - Ch: g.Level.Places[i].Ch, - Flags: g.Level.Places[i].Flags, - } - } +// snapshotPlayer captures the player, equipment as pack indices (the +// player half of snapshot). +func (g *RogueGame) snapshotPlayer() savedPlayer { + p := &g.Player - // level objects by value; remember their pointers for dest encoding - objAt := make(map[*Object]int, len(g.Level.Objects)) - for i, o := range g.Level.Objects { - st.Objects = append(st.Objects, *o) - objAt[o] = i - } - - // the player - st.Player = savedPlayer{ + sp := savedPlayer{ Body: savedCreature{ Pos: p.Pos, Turn: p.Turn, Type: p.Type, Disguise: p.Disguise, OldCh: p.OldCh, Flags: p.Flags, Stats: p.Stats, @@ -260,25 +289,10 @@ func (g *RogueGame) snapshot() *SaveState { MaxStats: p.MaxStats, VfHit: p.VfHit, } for _, o := range p.Pack { - st.Player.Body.Pack = append(st.Player.Body.Pack, *o) + sp.Body.Pack = append(sp.Body.Pack, *o) } - // monsters, with chase targets as (kind, index) references - for _, m := range g.Level.Monsters { - sc := savedCreature{ - Pos: m.Pos, Turn: m.Turn, Type: m.Type, Disguise: m.Disguise, - OldCh: m.OldCh, Flags: m.Flags, Stats: m.Stats, - RoomIdx: g.roomIdx(m.Room), - } - for _, o := range m.Pack { - sc.Pack = append(sc.Pack, *o) - } - - st.Monsters = append(st.Monsters, sc) - st.Dests = append(st.Dests, g.destRefFor(m, objAt)) - } - - return st + return sp } // destRefFor encodes a monster's chase target as a (kind, index) @@ -315,7 +329,32 @@ func (g *RogueGame) destRefFor(m *Monster, objAt map[*Object]int) destRef { // applySnapshot rebuilds live game state from a snapshot. func (g *RogueGame) applySnapshot(st *SaveState) { - p := &g.Player + g.applyHeader(st) + + for i := range g.Level.Places { + g.Level.Places[i] = Place{ + Ch: st.Places[i].Ch, + Flags: st.Places[i].Flags, + } + } + + // level objects + g.Level.Objects = nil + for i := range st.Objects { + o := st.Objects[i] + g.Level.Objects = append(g.Level.Objects, &o) + } + + g.applyPlayer(st) + g.applyMonsters(st) + g.applyDests(st) + + g.scr.Std.SetContents(st.Screen) +} + +// applyHeader restores the scalar game state (the field list of +// applySnapshot). +func (g *RogueGame) applyHeader(st *SaveState) { g.Rng.Seed = st.Seed g.Dnum = st.Dnum g.Whoami = st.Whoami @@ -360,22 +399,12 @@ func (g *RogueGame) applySnapshot(st *SaveState) { g.LastScore = st.LastScore g.AllScore = st.AllScore g.Playing = true +} - for i := range g.Level.Places { - g.Level.Places[i] = Place{ - Ch: st.Places[i].Ch, - Flags: st.Places[i].Flags, - } - } - - // level objects - g.Level.Objects = nil - for i := range st.Objects { - o := st.Objects[i] - g.Level.Objects = append(g.Level.Objects, &o) - } - - // the player +// applyPlayer restores the player, resolving equipment pack indices +// (the player half of applySnapshot). +func (g *RogueGame) applyPlayer(st *SaveState) { + p := &g.Player sp := &st.Player p.Pos = sp.Body.Pos p.Turn = sp.Body.Turn @@ -412,11 +441,6 @@ func (g *RogueGame) applySnapshot(st *SaveState) { p.NoFood = sp.NoFood p.MaxStats = sp.MaxStats p.VfHit = sp.VfHit - - g.applyMonsters(st) - g.applyDests(st) - - g.scr.Std.SetContents(st.Screen) } // applyMonsters rebuilds the monster list and its map index from a @@ -507,7 +531,8 @@ prompt: g.FileName = buf - if err := g.saveFile(g.FileName); err != nil { + err := g.saveFile(g.FileName) + if err != nil { g.msg("%s", err.Error()) continue