Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

133 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Pushover — a from-scratch, reverse-engineered browser port

Pushover's main menu, rendered by this project's browser port

Pushover is a classic 1992 puzzle platformer developed by Red Rat Software, famously created as a major promotional tie-in for Quavers, a popular British potato snack brand manufactured by Walkers. The game features the snack's then-mascot, Colin the Curly Dog, who loses his prized packs of Quavers down a giant ant hill. Players control a helpful soldier ant named G.I. Ant, who must navigate 100 increasingly complex levels to retrieve the fallen snacks. The core gameplay revolves around a domino-toppling mechanic, where players must rearrange various types of dominoes—each with unique properties like exploding, splitting, or floating—so that a single push topples every block and opens the exit within a strict time limit.

The partnership stands out as a highly successful example of "advergaming" from the retro era. Unlike many promotional games of the time that felt rushed or shallow, Pushover received widespread critical acclaim for its ingenious puzzle design, clever mechanics, and high replay value across platforms like the Amiga, Atari ST, and MS-DOS. The game seamlessly integrated the Quavers brand into its visual identity, using the snack's distinctive yellow packaging as the ultimate reward at the end of each stage. By blending addictive puzzle logic with a beloved UK snack mascot, Pushover earned a lasting legacy that outlived the advertising campaign itself.

The original DOS game is still sold today, DRM-free, at gog.com. This project is not a copy of that game and does not include or redistribute any of its data. It is an independent, reverse-engineered simulation of the game's rules, rendered with a browser-native UI — every piece of copyrighted art, level geometry, sound, and music is decoded live, in your browser from your own legally-owned copy of the original files (see Getting the original game data below). Without those files, the pages in this repository won't render anything.

What this repository actually is

Not a fan remake built by eyeballing gameplay footage — a byte-exact reimplementation, derived by statically and dynamically reverse-engineering the original DOS executables with Ghidra and a live DOSBox debugger bridge, then porting the confirmed logic to dependency-free JavaScript. Where a mechanic couldn't be fully pinned down from disassembly alone, it was checked against the running original game — single-stepping real memory, pixel-sampling real captured frames, and diffing this port's own simulation output against recorded ground-truth traces from the real executable (see Conformance testing below). Every non-obvious finding is written up in docs/formats/ and docs/re-notes/, so the "why" behind a piece of code is traceable back to real evidence instead of guesswork.

Getting the original game data

Nothing in this repository can render without the real game's data files (SCREENS/, THEMES/, DATA/, MUSIC/, PUSH.CFG) — they are copyrighted and are never bundled, committed, or fetched from anywhere by this project. You need your own legally-owned copy, for example the DRM-free version from gog.com. Point any page here at it in one of two ways:

  • Drop the game's install folder in as game/ next to this repository (gitignored, never uploaded) and serve the repo root over plain HTTP (see Running it locally) — every page auto-detects it, no prompt shown.
  • Or just open a page without game/ present: a "select your Pushover game folder" picker appears (showDirectoryPicker(), with an <input webkitdirectory> fallback for browsers without it) and remembers your choice for next time.

Every asset — RNC-compressed level files, theme tile/sprite banks, the resident OPL2 music driver blobs — is decompressed and decoded live in the browser, on the fly, from those raw original files. There is no separate build step that converts the game data ahead of time and no pre-extracted asset bundle checked into git.

Play it

Live at vorticoncmdr.github.io/pushover — you'll still need your own copy of the original game data (see above); the page will prompt you to pick your game folder.

Gameplay: G.I. Ant beside a row of dominoes on a conveyor belt, mechanic-themed level

Or run it locally:

git clone <this repo>
cd pushover-rescue
python3 -m http.server 8080
# then open http://localhost:8080/engine/play/

engine/play/ is the actual game: all 100 levels across 10 worlds, real domino/ant physics ported tick-for-tick from the original simulation, the real OPL2 music driver, the CODE/passcode level-select menu, and the P/F1 pause-help overlay — all pixel-rendered from your own copy of the original assets. Progress (current level, collected Quavers) persists across reloads via localStorage, matching the real game's own passcode scope (a passcode never carries token/undo state — see docs/formats/manual.md).

Repository layout

engine/
  src/core/     the ported simulation — plain, dependency-free JS
  play/         the actual playable game (browser UI + audio)
  viewer/       inspector / level editor / theme editor / pose & music explorers
  test/         unit, visual-regression, and conformance test suites
docs/
  formats/      confirmed, written-up file-format and mechanic documentation
  re-notes/     raw reverse-engineering notes and Ghidra findings
tools/
  asset-convert/  RNC decompression + every live asset decoder (theme art, levels, sprites, ANX/DAX/etc.)
  rnc-unpack/     standalone RNC ProPack decompressor (CLI + library)
  lib/            shared runtime glue (asset-source abstraction, Buffer polyfill)

engine/src/core/ — the simulation

The actual game logic, ported with no framework and no runtime dependencies — every file runs directly in Node (node <file>.js) or a <script> tag:

  • dominoSim.js — the domino grid: tick-by-tick physics for every domino type (standard, stopper, splitter, exploder, delay, tumbler, bridger, vanish, trigger, ascender), settledness detection, and win/lose evaluation.
  • antSim.js — G.I. Ant's full movement finite-state machine (~45 states: walking, climbing, pushing, carrying, falling, dying), steering, and rendering-relevant pose selection.
  • menuSim.js — the CODE-entry/level-select screen, the end-of-attempt REPLAY/QUIT/USE TOKEN menu, and the MUSIC/SOUND/QUIET controls.
  • audioSim.js — the resident OPL2 sound-driver simulation (track/instrument selection, register-write sequencing), paired with a vendored OPL2 synthesis core (engine/play/audio/opl2-core.js) for actual audible playback.
  • levelOrder.js — the pure-math level/world table (which SCREENS/*.SCR filename and CODE passcode belong to which of the 100 levels/10 worlds) — see docs/formats/level-order.md.

engine/play/ — the game itself

The playable browser front end (index.html/main.js/style.css) built on top of engine/src/core/: canvas rendering of levels/dominoes/ant/HUD, keyboard input, the pause/help and quit modals (styled to match the original DOS screens, sampled from live captures), and real music/SFX via the vendored OPL2 core. Loads original assets live via tools/lib/assetSource.js — no pre-built asset bundle.

engine/viewer/ — inspection and authoring tools

A suite of browser pages for exploring and authoring the original format, all sharing the same live asset-decoding pipeline as engine/play/:

  • Level viewer (index.html/viewer.js) — read-only inspector for any real SCREENS/*.SCR level, rendered with real theme/domino art.
  • Level editor (editor.html/editor.js) — paints a real level from scratch (background/structure/dominoes, doors, EN/FR/DE hint text), exports uncompressed or real RNC-packed .SCR, and can playtest in an embedded iframe with solution-tape recording. Also exposes a WebMCP tool surface for AI-agent-driven editing.
  • Theme editor (theme-editor.html/theme-editor.js) — paints a full theme (16-color palette, architecture/background tiles, decoration icons) from scratch and exports the real on-disk .PAL/.BCX/.PLX format.
  • Ant pose viewer (ant.html) — frame-accurate scrubber over all 66 real ant sprite poses.
  • Music explorer (music.html) — plays every track in MUSIC/OVER_AD.BIN through the real ported driver, labeled from THEME.KEY's name table.

See engine/viewer/README.md for the full breakdown.

tools/

  • asset-convert/ — every live asset decoder: RNC-decompressed level parsing (scr-to-json.js), theme/sprite recoloring (theme-recolor.js), ant/domino/decoration sprite decoders, and a standalone offline export script (export-viewer-data.js) for eyeballing decoded assets without a browser.
  • rnc-unpack/ — a from-scratch, independently validated implementation of the RNC ProPack decompression algorithm used by nearly every original asset file (see docs/formats/rnc.md), including a from-scratch compressor (rncPack.test.js) that beats the original 1992 tool's output size on every one of the game's 103 real .SCR files (100 playable levels plus the menu-background screens).
  • lib/assetSource.js / assetSourceBoot.js — the shared abstraction that lets every page above load original files from either a local game/ folder or a user-picked directory, decompressing on the fly.

Documentation — docs/formats/

Every confirmed file format and game mechanic, written up with the evidence behind it (static disassembly, live-memory traces, or both):

Document Covers
manual.md Transcription of the original printed instruction manual
level-order.md The LFSR cipher behind level order, SCREENS/*.SCR filenames, and CODE passcodes
password-menu.md The CODE/passcode progress system
main-menu.md The full main menu / level-select flow, including the end-of-attempt and quit menus
screens-scr.md SCREENS/*.SCR — the real gameplay level format
screens-scr-editor.md Authoring a real .SCR file from scratch
domino-memory-layout.md / domino-tick-simulation.md The domino grid's live memory layout and per-tick physics simulation
domino-gameplay-sprites.md / spx.md DOMINOE0/1.SPX — the real domino sprite art format
ant-movement-fsm.md G.I. Ant's ~45-state per-tick movement FSM
ant-steering-mechanics.md Steering/movement claims verified against the FSM
ant-sprites.md DATA/ANT*.ANX + ANT10B29.SPX — the ant's animation art
ant-rendering.md The rendering layer that turns FSM state into on-screen ant poses
fg-visuals.md Platforms, ladders, and the door animation
win-lose-mechanics.md Settledness checks, trigger-last enforcement, the timer, and placement rules
pal.md THEMES/*.PAL — 16-color theme palettes
plx-bcx.md .PLX/.BCX — theme decoration and architecture sprites
theme-dat.md THEME.DAT — an encrypted anti-piracy payload, not theme data
theme-key.md THEME.KEY — world/level counts and the theme/track name table
theme-editor.md Authoring a real theme (.PAL/.BCX/.PLX) from scratch
audio.md MUSIC/*.BIN — the resident OPL2 sound-driver blobs
lang-dax.md DATA/LANG0-3.DAX — the fully decoded UI string table (all 4 languages)
flx.md .FLX — the level archive container
ani-pix-dlx.md DATA/ANI??.PIX/.DLX — per-world background art and EGA delta patches
rnc.md The RNC ProPack compression container used by almost every asset file

Raw, in-progress reverse-engineering notes (Ghidra function renames, live memory dumps, static-unpacker analysis) live in docs/re-notes/ for anyone who wants to see the underlying evidence trail rather than just the conclusions.

Testing

npm test                 # unit tests -- plain Node, no install needed
npm run test:visual      # Tier 2: canvas-pixel visual regression (needs `npm install` once, for Playwright)
npm run test:conformance # Tier 3: diffs dominoSim.js's own tick() against real DOSBox-captured traces

Three tiers, each catching a different class of regression:

  1. Unit tests (engine/test/*.test.js) — 10 suites, ~1,900 assertions, covering the domino/ant simulations, level ordering, menu logic, audio driver, and every asset reader/writer (.SCR, RNC pack/unpack, theme format). Plain Node, zero dependencies, no install step.
  2. Visual regression (engine/test/visual/) — loads real levels in a real headless browser, plays scripted key sequences tick-by-tick, and hashes the exact rendered canvas pixels against committed baselines, so a rendering regression can't slip through even if every simulation unit test still passes. See its own README.
  3. Conformance testing (engine/test/conformance/) — replays recorded ground-truth traces captured from the real DOSBox debugger against this port's own dominoSim.js/antSim.js, cell-by-cell and tick-by-tick, to catch behavioral drift from the real executable that a hand-written unit test wouldn't think to check.

How this was built

This is a from-scratch simulation, not a disassembly-to-JS transpile — but every non-trivial mechanic traces back to real evidence rather than observed-behavior guesswork:

  • Static analysis: Ghidra decompilation of all four original executables, with function/struct renaming as behavior was confirmed (docs/re-notes/function-renames.md).
  • Live dynamic verification: a DOSBox debugger bridge used to single-step the real running game, set breakpoints, read/write real memory and CPU registers, and pixel-sample real captured frames — the deciding source of truth whenever static analysis alone left a mechanic ambiguous.
  • Byte-exact output validation: this port's own RNC compressor, .SCR writer, and theme-format writer are tested by round-tripping through the real original decompressor/parser logic, not just against each other.

Where the project's own documentation later found an earlier conclusion wrong, the docs say so explicitly rather than quietly overwriting the record — see, for example, fg-visuals.md's correction of an earlier claim that platforms had no dedicated art.

About

a from-scratch, reverse-engineered browser port of the classic game Pushover

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages