For Save Scummer (http://www.zincland.com/7drl/savescummer) I had good
luck actually just snapshotting each turn. This sounds insanely
wasteful, but with a bit of copy on write you can cut the cost down to
a bearable amount for todays machines. The advantage is that you
don't need to write code to "undo" every action and you can
theoretically remain compatible with future versions by not relying on
a certain sequence of keystrokes to always behave the same.
--
Jeff Lait
(POWDER: http://www.zincland.com/powder)
Yes, I've used recording and replaying games as a testing aid for my game.
In the context of my own requirements it proved easy. The first step was to
pin the RNG so that it produced the same set of random numbers every time.
Some APIs permit this by allowing you to specify a specific seed value to
the RNG. Next was to play the game and record every keystroke that was made
while playing with the RNG pinned.
Then to replay the game I could tweak a configuration parameter so that the
program would know to get keystrokes from the "keystroke source" instead of
from the actual keyboard. The "game" is then defined as simply a sequence of
keystrokes.
In practice I found that my replayed games got stale pretty quick, though.
As soon as I would modify a significant amount of content the game would go
off in the weeds. I had changed the problem domain, so to speak.
Are you integrating recording/playback into the gameplay itself, somehow? If
so I'd enjoy hearing more about that.
Hope that helps. Good luck!
Nathan
http://roguelikefiction.com
I've done something like this for the game I'm working on (not a
roguelike) to implement multiplayer. I save a copy of the game state
every so often and when remote actions are recieved through the
network it reverts to a state from before the action's timestamp,
inserts the action into the queue, then runs forward again to to the
present time taking it into account. Probably not the recommended
method but it works for my purposes and has some advantages: there is
no lag on your own actions, very little information needs to be passed
between players to ensure they have the same state, it's impossible
(well, difficult) to cheat because other players will always be in a
legitimate state - you'll just end up getting out of sync.
Of course all that is really necessary (if it doesn't have to be done
in real-time) is to save the initial state (level, RNG seed, whatever)
and the sequence of actions performed by the players, and the state at
any given time can be recomputed from those.
These are the important parts to make this work as I see it:
- game state is completely encapsulated in one place, and does not
depend on anything else (unless it is guaranteed to be constant).
- RNG state is considered part of the game state.
- the game is completely deterministic. ideally time progresses in
discrete steps.
- all changes to the game state by player actions are carefully
managed and recorded.
If you're planning this from the start it should be very easy to build
it in. If you're a way into the project before adding this it might
get a bit more difficult - the "game state" tends to get scattered
around in a bunch of different variables all over the place, and user
input tends to just directly change values without keeping a record.
I'd recommend using the exact same format for new actions and replayed
actions.
What are you finding difficult?
Sidetrack: One time when I was trying to write a roguelike I had plans
to do something using recorded actions for the final dungeon (which
was to be ridiculously hard). The idea was that you would arrive a
turn or two after your previous character and be able to follow along
behind them and maybe rescue them from whatever killed them (at which
point they would stop following the recorded script and revert to pet
ai) or stupidly get killed by the fireball trap they set off.
Eventually, after several tries, you'd manage to kill the end boss by
climbing over the corpses of your previous characters; then the
challenge would be to try to win with the fewest characters possible.
This would be best on a public server (complete with glorious
opportunities for griefing).
My game shell converts all user actions into keyboard "events" that
happen to contain a system tick count, and a few other bits of info.
The only real reason is that I've used this shell before for non-RL
text based apps that use text "windows" and such, so I can respond to
mouse and keyboard events if needed. These events funnel into a queue
that is then read by the game itself to get keystrokes. I've never
really thought of a reason to record a game, but it would be simple to
save these events to a file, and then have the game play back the
exact events.
-spag
I did a very simple version of this in my in-progress Roguelike, to
enable testers to send me logs of their games. It's kind of like
virtual focus-testing. Very handy! I just save keystrokes to a file
(along with the random number seed and a version number); the
keystrokes are run-length encoded so a typical hour of play takes a
few kilobytes.
Eventually I'd like to turn it into a full undo/redo capability. (I
know, heresy!) This sounds a little more like what you're thinking
of, and would entail quite a bit more work.
The reason I'm so interested in replaying is because the game I'm
designing is all about the social experience of sharing roguelike
stories. One of my favorite things about playing NetHack is talking
with friends about all the crazy stuff that happens in our games (e.g.
YASDs), so I'm trying to build a game around that idea. One of the
essential aspects of this (IMO) is to make every game be automatically
recorded for sharing later (maybe on some kind of community website?
but now we're getting pretty ambitious). (I'm also building the whole
game design in such a way that makes multiplayer feasible, which is my
ultimate goal here.)
Yes! Sharing game highlights via playback is something I want to get
in to my project. I think you're right that it could really help
build a community around your game. I, too, was thinking that the
savegame would contain the entire history, so that every game would be
automatically recorded. Then, eventually, you'd want some sort of
website for posting cool game bits to.
I think undo/redo could work very well in a Roguelike, too. One use
would be to take care of the "What just happened?" moments when you've
banged the keys too fast to catch something. If you allowed someone
to back up and continue play from an earlier turn (true undo) then
that would just tack onto the end of the game history. When you
posted your win file or whatever, it could include stats about how
undo was used/abused. Something like number of abandoned timelines,
or number of abandoned turns of play, or both.
Also, when you load up a game after being away for a while, being able
to watch the last few turns would make a nice recap to get you up to
speed on where you're at.
That's a great idea! (As long as you can easily skip it.) I remember
they did that in some Pokemon games recently and it's really pretty
useful - especially considering how seldom I play Pokemon...