Improvements and optimizations

Major points (see also notes on 4d92ed3b4a7a2a411f301353ffa58a845de4c954):

1. Incremental redrawing for games that don't scroll (old-style redrawing for games that scroll), via a `dirty` object which tracks which tiles need to be redrawn, or `dirty.all=true` if the whole screen needs a redraw.
2. Makegif works properly with random and wait, reseeding the RNG with its initial seed. Undo and redo still give different results under randomness, but I think this is to spec.
3. Support for automatically dumping play traces with user-defined handlers.
4. Refactored `if(canDump) { inputHistory.push() }` stuff into a function `pushInput` which is a no-op for release mode and does something useful in debug mode.

I do have one issue, though: this works on Mac Chrome & Firefox, works when played by hand in Safari, but some tests fail when run via `testingFramework.js`, UNLESS the debugger is open or breakpoints are set in which case all tests pass. Urgh. The two main issues are (1) just wrong level outputs and (2) throwing exceptions in `engine.js:880` or so because `delta` is null because the direction mask is "5", which doesn't map to a proper direction. Again, when this is run in debug mode (to figure out how the direction mask could possibly be 5) the error doesn't occur.