A savegame editor for Ultima IV: Quest of the Avatar that runs in your terminal, and
speaks both save formats: the original DOS PARTY.SAV and ScummVM's slots.
No Windows. No Wine. No hex editor. Point it at a save, fix your party, keep playing, and move a game between DOSBox and ScummVM in both directions.
- Two formats, autodetected. Give it a DOS game directory (or
PARTY.SAV) or a ScummVM slot file (~/.local/share/scummvm/saves/ultima4_enh.000) and it figures out the rest. Pointing it at the ScummVM saves directory lists the slots with their names. - Export to the other format. Started in ScummVM and want to finish in DOSBox, or carry
your Avatar on to Ultima V?
Ctrl+Ewrites a classicPARTY.SAV+MONSTERS.SAV. Coming from DOS? The same key creates a ScummVM slot, with a name and thumbnail so it shows up in ScummVM's load menu. - Every save is a version. The same bzip2 version history as u3edit: readable change logs, one-key restore, and your game's own saves are captured as well.
- Plays nice while you play. If ScummVM or the game saved while the editor was open, u4ed
merges your edits on top of the new state field by field instead of throwing away your progress.
Ctrl+Rreloads while you play. - Byte-exact. Only the fields you touch change. In ScummVM slots, the monster tables, metadata and thumbnail are carried over untouched. A no-op save leaves the file bit-for-bit identical.
- Every save adds a version. Each one is a small bzip2 tarball in
.u4ed-history/next to the save. ScummVM slots get one folder per slot. - Your originals are always version 1.
- Game saves are captured. If the game wrote the files since the last version, that state is recorded as "Changed outside u4ed" before anything is overwritten. Above: ScummVM autosaved after the party walked two steps, and u4ed kept both that save and the user's edits.
- Readable change logs. For example
Jaana: status Poisoned → Good, hit points 143 → 400,gold 1337 → 9999or+rune of Valor. - Restore any version with
F5→r. The restore is itself a new version, so it can be undone too. - No lock-in.
tar -xjfgets your files back without u4ed.
| Inventory | Magic |
|---|---|
![]() |
![]() |
| Virtues | World |
![]() |
![]() |
- Characters (all 8): name, sex, class, status (Good / Poisoned / Sleeping / Dead), HP, max HP, XP, Str, Dex, Int, MP, equipped weapon and armour, derived level
- Inventory: food, gold, torches, gems, keys, sextants, all armour and weapon stocks
- Magic: all 8 reagents and all 26 spell mixtures
- Virtues: karma for all eight virtues (0 = elevated, i.e. partial Avatarhood), the eight runes, the eight stones, and the quest items (Bell, Book, Candle, the three-part key, Silver Horn, Wheel, Skull)
- World: moves, position, party size, transport, both moon phases, ship hull
F3heal: status Good and full HP.F4: revert one character.- Export dialog with a suggested free ScummVM slot:
Requires Python ≥ 3.10 and uv.
cd u4ed
uv run u4ed ~/.local/share/scummvm/saves/ultima4_enh.000 # a ScummVM slot
uv run u4ed ~/dos/ultima4 # a DOS game diruv tool install . puts u4ed on your PATH.
u4ed PATH # open the TUI (format autodetected)
u4ed PATH --dump # print party, inventory, virtues
u4ed ~/.local/share/scummvm/saves # lists the ScummVM slots to choose from
u4ed SLOT --export ~/dos/ultima4-copy/ # ScummVM -> PARTY.SAV + MONSTERS.SAV
u4ed ~/dos/ultima4 --export ~/.local/share/scummvm/saves/ultima4_enh.007 --name "From DOS"--export refuses to overwrite existing files unless you add --force.
| Key | Action |
|---|---|
↑ / ↓ |
select a character (★ = in the party) |
Ctrl+S / F2 |
save (adds a history version) |
F3 |
heal the selected character |
F4 |
revert the selected character |
F5 |
version history |
Ctrl+R / F6 |
reload from disk |
Ctrl+E |
export to the other format |
Ctrl+P |
command palette |
Ctrl+Q |
quit |
The conversion works for saves made on the surface of Britannia. Inside a town or a dungeon,
the DOS game keeps extra state in OUTMONST.SAV/DNGMAP.SAV that ScummVM doesn't store, so
u4ed refuses: walk outside, save, and export that save. Editing works everywhere.
Original PARTY.SAV (502 bytes, little-endian): u32 unknown, u32 moves, 8 × 39-byte
player records (hp, hpMax, xp, str, dex, int, mp, unknown, weapon, armour as u16; name[16];
sex 0x0B/0x0C, class 0-7, status G P S D), food (u32, hundredths), gold, karma[8],
torches, gems, keys, sextants, armour[8], weapons[16], reagents[8], mixtures[26], items
(bitmask), x, y, stones, runes, members, transport, balloon, Trammel, Felucca, hull, lbIntro,
lastCamp, lastReagent, lastMeditation, lastVirtue, dngx, dngy, orientation, dnglevel, location.
ScummVM slot (gzip): bytes 0x000-0x1D1 are identical to PARTY.SAV. Then come a location
chain (u8 count + x/y/z/map per level, world first), orientation, items, stones, runes, the
same 11 u16 fields, then one "MONS" + 256-byte monster table per map (the MONSTERS.SAV
layout), then ScummVM's extended header (SVMCR, slot name, date, play time, THMB thumbnail).
The offset of that header is stored in the last 4 bytes.
Sources: ScummVM engines/ultima/ultima4/filesys/savegame.{h,cpp}, engines/metaengine.cpp and
graphics/thumbnail.cpp, plus xu4's savegame.cpp. Verified against real DOS and ScummVM saves
(tests/fixtures).
uv run pytest # model, formats, export round trips, headless TUI tests
uv run python scripts/make_demo.py # rebuild the demo saves (both formats)
uv run python scripts/screenshots.py # re-render docs/screenshots (needs inkscape)The screenshots show the demo party from tests/fixtures/demo: the Avatar, Werdna (yes, that
one), adventuring with Iolo, Shamino, Dupre, Mariah, Geoffrey, Jaana and Katrina.
MIT © 2026 Mathias Menzel-Nielsen






