A faithful recreation of the classic 1983 RPG "Ultima III: Exodus" using .NET 9 and Avalonia UI for cross-platform compatibility.
| Main Menu | Overworld | Town |
|---|---|---|
![]() |
![]() |
![]() |
| Combat | Dungeon | Character Creation |
|---|---|---|
![]() |
![]() |
![]() |
Lonnie Watson
UltimaIII.sln
├── src/
│ ├── UltimaIII.Core/ # Game logic, models, and engine (platform-agnostic)
│ │ ├── Enums/ # Game enumerations (Race, Class, TileType, etc.)
│ │ ├── Models/ # Core models (Character, Party, Item, Spell, Monster, Map)
│ │ └── Engine/ # Game engine, combat system, map generator
│ │
│ ├── UltimaIII.Avalonia/ # Avalonia UI project for rendering and input
│ │ ├── Controls/ # Custom controls (TileMapControl, CombatMapControl)
│ │ ├── Services/Audio/ # Procedural chiptune audio system
│ │ ├── ViewModels/ # MVVM ViewModels
│ │ └── Views/ # AXAML views
│ │
│ └── UltimaIII.Data/ # Game data (maps, monsters, items, spells)
- Races: Human, Elf, Dwarf, Bobbit, Fuzzy (each with stat modifiers)
- Classes: Each class has unique combat bonuses and special abilities:
| Class | Combat Role | Attack | Defense | Damage | Special |
|---|---|---|---|---|---|
| Fighter | Pure warrior | +2, +1/4 lvls | +1 | +2, +1/5 lvls | Best consistent melee |
| Cleric | Healer | — | +1, +1/5 lvls | — | +2 atk/dmg vs Undead |
| Wizard | Offensive caster | -2 | — | -1 | Relies on spells |
| Thief | Agile rogue | +3, +1/3 lvls | +2 | — | Critical hits (15+Level %) |
| Paladin | Holy knight | +1, +1/5 lvls | +2 | +1 | +3 atk/dmg vs Undead/Demon |
| Barbarian | Brute | +1 | — | +3, +1/4 lvls | Rage: +1 dmg per 25% HP missing |
| Lark | Thief-mage | +1, +1/5 lvls | +1 | — | Critical hits (10+Level/2 %) |
| Illusionist | Wizard-thief | -1 | +1 | -1 | Spell-focused |
| Druid | Nature priest | — | +1 | — | +2 atk/dmg vs Demon |
| Alchemist | Scholar | -1 | — | — | Jack-of-all-trades caster |
| Ranger | Wilderness warrior | +1, +1/5 lvls | +1 | +1 | +1 weapon range |
- Stats: Strength, Dexterity, Intelligence, Wisdom (range: 3-25)
- Party System: Create up to 4 characters
- Tile-Based World: Procedurally generated overworld, towns, and dungeons
- Movement: 4-directional movement with collision detection
- Terrain Types: Grass, Forest, Mountain, Water, Swamp, Lava, etc.
- Time System: Day/night cycle, moon phases
- Fog of War: Exploration reveals the map
- Safe Zones: Towns have no random encounters
- Save/Load: Persistent game saves with full party, inventory, and quest state
- Screenshots: Press Ctrl+Shift+S on any screen (main menu, gameplay, combat, shops, etc.) to capture a PNG screenshot with a custom name (defaults to current screen + date)
- Turn-Based Tactical Combat: 11x11 grid
- Initiative: Based on Dexterity/Speed
- Player Movement: Move characters tactically during combat
- Actions: Move, Attack, Cast Spell, Pass, Flee
- Target Selection: Keyboard (WASD) or mouse (click to select, double-click to confirm)
- Monster AI: Simple pathfinding and attack behavior
- 20+ Monster Types: Orcs, Skeletons, Dragons, Demons, etc.
- Loot Drops: Defeated monsters can drop weapons, armor, shields, consumables, and gems based on per-monster loot tables
- Gem Combat Effects: Socketed gems provide passive bonuses during combat -- bonus damage, lifesteal, damage reflection, status resistance, and more
- Wizard Spells: 19 spells (offensive, utility, teleportation)
- Includes AOE: Vas Flam (fireball), Grav Por (ice storm), Noxum (poison cloud), Dag Mentar (confusion), Xen Ang (chain lightning)
- Cleric Spells: 19 spells (healing, protection, cure, resurrection, holy offense)
- Includes AOE: Vas Sanct (holy nova), An Corp (divine judgment), Sominae (sleep)
- Status Cures: Sanctu cures poison; Lib Rec removes all ailments (poison, confusion, sleep, paralysis)
- Combat Casting: CuresStatus spells work in combat to heal afflicted party members
- Field Casting: Press C outside of combat to cast support spells — heal injured allies, cure poison or paralysis, resurrect fallen party members, and more without needing a Healer shop
- Class Restrictions: Each class has access to different spell levels
- 7 Shop Types: Weapon Shop, Armor Shop, Tavern, Healer, Guild, Inn, Temple
- Unique Shop Names: Each town has procedurally named shops (e.g. "The Rusty Blade", "The Silver Stag")
- Buy/Sell/Equip Tabs: Purchase equipment, sell items, and equip gear
- Party Inventory Selling: Press Q on the Sell tab to toggle between selling from character inventory or party inventory
- Services: Healing, cure, resurrection (Healer); rest to restore HP/MP (Inn); food (Tavern)
- Temple: Socket gems into equipment (see Gem Socketing System below)
- Class Restrictions: Equipment restricted by character class
- Shared Inventory: Party-wide item storage fed by monster loot drops
- Inventory Browser: Press I to open the inventory screen from anywhere (overworld, town, dungeon)
- 5 Filter Tabs: All, Weapons, Armor, Shields, Items
- Equip from Party: Select a character and equip items directly from party inventory
- Equipment Swap: Currently equipped items return to party inventory when replaced
- Stackable Items: Consumables stack with quantity display (e.g. "Healing Potion x3")
- Persistent: Party inventory saves and loads with the game
- Procedurally Generated Towns: 32x32 maps with walls, buildings, and a central fountain square
- Cobblestone Paths: Connecting main avenue, east-west roads, and the town square
- Shop Signs: Readable signs next to each shop door displaying the shop name
- Decorations: Flower beds, lampposts along roads, and scattered trees
- Door Clearance: Automatic validation ensures decorations never block shop entrances
- 18 Quests: Spanning all 8 towns with early, mid, and late game progression
- 3 Quest Types:
- Kill Quests: Slay a target number of specific monsters (e.g. 5 Giant Rats, 12 Undead)
- Fetch Quests: Recover quest items dropped by specific monsters in combat (e.g. Lich Phylactery from Liches)
- Explore Quests: Visit a specific dungeon level to scout and report back
- Quest NPCs: Green-robed NPCs with "!" markers placed in each town — they greet you as you approach
- Tavern Quests: Some quests are offered by tavern barkeeps (accessible via the Tavern shop)
- Quest Chains: Late-game quests require completing prerequisites (e.g. "Destroy the Lich" unlocks after "Vampire Hunt")
- Quest Log: Press J to view active quests with progress tracking (kill counts, exploration status)
- Talk to NPCs: Press T when adjacent to a quest NPC to view available quests, accept new ones, or turn in completed quests
- Quest Item Drops: Fetch quest items drop from specific monsters at high rates (50-80%) when the quest is active
- Rewards: Gold and experience for each completed quest
- Persistent: Quest progress saves and loads with the game
- Overworld: 64x64 procedurally generated world with 8 towns and 4 dungeons
- Towns: 32x32 with shops, paths, signs, and decorative features
Each of the 4 dungeons (Doom, Fire, Time, Snake) has 8 procedurally generated levels with increasing difficulty.
- 32x32 maps with 9-16 rooms per level (more rooms on deeper levels)
- Room size variety: Tight closets (2-3 tiles), standard rooms (4-6 tiles), and large chambers (7-9 tiles)
- MST corridors: Prim's minimum spanning tree guarantees all rooms are reachable, with extra random connections creating loops and alternate paths
- Wide corridors: On levels 5+, some corridors are 2 tiles wide (25% chance)
- Doors: Automatically placed at corridor chokepoints; more frequent on deeper levels (20% on L1, 55% on L8)
- Stairs up: Always in the first room (entrance from previous level or surface)
- Stairs down: Always present on levels 1-7, placed in the last room
- Exit portals: Shimmering portals on levels 5-8 for quick return to the surface
Every room can contain multiple features, with more in larger rooms:
| Feature | Chance | Notes |
|---|---|---|
| Chest | 20% | Contains gold scaled by level, plus a 35% chance of item drops (consumables, gems, or equipment) -- 20% chance of being trapped |
| Fountain | 15% | Interactable water source |
| Trap | 5% + 2% per level | More dangerous on deeper levels |
| Secret Door | 10% | Hidden in room walls (all 4 sides); appears as a grey wall tile until revealed by Searching (Space) |
| Lava Cluster | 3% per level | 1-3 tile clusters; only on deeper levels |
Searching a chest (Space) awards gold and may drop an item:
| Drop | Chance | Details |
|---|---|---|
| Gold | Always | 10-100 base x (dungeon level + 1) |
| Consumable | 10% | Healing Potion or Rations |
| Gem | 10% | Tier scaled by dungeon level (same rates as monster gem drops) |
| Equipment | 15% | Random weapon, armor, or shield; better gear available on deeper levels |
Random encounters occur with each step: 5 + dungeon level% chance (6% on L1, 13% on L8). Larger maps mean more exploration between fights.
- Recruitable NPCs: Each town's tavern has a randomly generated companion available
- Recruit Tab: Press 3 in the tavern to browse the available NPC's stats, race, and class
- Direct Recruit: If the party has an open slot (fewer than 4 members), the NPC joins immediately
- Swap System: If the party is full, choose which member to leave behind at the tavern
- Parked Characters: Left-behind characters remain at the tavern and can be recruited later
- Persistent: Tavern NPCs and parked characters save and load with the game
Gems are rare drops from defeated monsters that can be permanently socketed into equipment at Temples found in every town. Each gem grants a specific combat bonus depending on its type and which equipment slot it occupies. Gems cannot be purchased — they can only be found through combat or earned as quest rewards.
| Gem | Tier | Slot | Effect |
|---|---|---|---|
| Ruby | Chipped / Flawed / Perfect | Weapon | +1 / +2 / +4 bonus damage on every attack |
| Sapphire | Chipped / Flawed / Perfect | Weapon | +1 / +2 / +3 attack hit bonus |
| Emerald | Chipped / Flawed / Perfect | Armor, Shield | +3 / +6 / +10 max HP |
| Diamond | Chipped / Flawed / Perfect | Weapon | +3% / +5% / +8% critical hit chance |
| Diamond | Chipped / Flawed / Perfect | Armor | +1 / +2 / +3 defense |
| Topaz | Chipped / Flawed / Perfect | Weapon | +2 / +3 / +5 bonus damage vs Undead |
| Topaz | Chipped / Flawed / Perfect | Armor | +1 / +2 / +3 magic defense (reduces spell damage) |
| Amethyst | Chipped / Flawed / Perfect | Armor, Shield | 10% / 20% / 35% status effect resistance |
| Onyx | Chipped / Flawed / Perfect | Weapon | 5% / 10% / 15% lifesteal (heal % of damage dealt) |
| Opal | Chipped / Flawed / Perfect | Shield | Reflect 1 / 2 / 4 damage back to melee attackers |
Monster Drops: Every defeated monster has a chance to drop a gem based on its dungeon level. Higher dungeon levels yield rarer tiers:
| Monster Level | Chipped | Flawed | Perfect |
|---|---|---|---|
| 1 (Rats, Goblins) | 8% | -- | -- |
| 2 (Ghouls, Trolls) | 12% | 4% | -- |
| 3 (Wraiths, Imps) | 10% | 8% | -- |
| 4 (Vampires) | 5% | 12% | 3% |
| 5 (Liches) | -- | 15% | 5% |
| 6 (Daemons) | -- | 12% | 8% |
| 7 (Balrons) | -- | 10% | 12% |
| 8 (Dragons) | -- | 8% | 15% |
Quest Rewards: Four quests grant guaranteed gem rewards:
- Troll Bridge (Fawn) -- Flawed Ruby
- Undead Purge (Moon) -- Flawed Topaz
- Daemon Bane (Devil Guard) -- Perfect Onyx
- The Time Shard (Moon) -- Perfect Diamond
Not all equipment has sockets. Higher-tier gear has more:
| Sockets | Weapons | Armor | Shields |
|---|---|---|---|
| 0 | Dagger, Sling, Mace | Cloth | Small Shield |
| 1 | Short Sword, Axe, Bow, Long Sword, Staff, Crossbow | Leather, Chain Mail | Large Shield, Tower Shield |
| 2 | Halberd, Great Sword, 2H Axe, Wand | Plate Mail | -- |
- Enter a town and walk into the Temple building (bottom-right area of town)
- Press B at the counter to enter the Temple
- Select a character (A/D to cycle)
- Select the equipment to socket
- Select the socket slot (empty or occupied)
- Select the gem from your inventory
- Confirm the socketing and pay the gold cost
Socketing Costs scale by gem tier and equipment value:
| Gem Tier | Equipment value up to 100g | 101-300g | Over 300g |
|---|---|---|---|
| Chipped | 50g | 100g | 150g |
| Flawed | 150g | 300g | 450g |
| Perfect | 400g | 800g | 1,200g |
Important: Replacing a socketed gem destroys the old gem. There is no way to remove a gem without replacing it.
- OGG Music Support: Place
.oggfiles inAssets/Music/to replace any synthesized track (e.g.,Overworld.ogg,Combat.ogg,Town.ogg) - Automatic Fallback: Tracks without a matching OGG file use procedural chiptune synthesis
- Smart Track Matching: Dungeon-specific combat tracks (e.g.,
CombatDoom) fall back toCombat.oggif no specific file exists; same for dungeon exploration tracks - Procedural Chiptune Audio: Built-in synthesized music and sound effects as default
- Waveform Synthesis: Square, triangle, sawtooth waves, and white noise
- Cross-Platform: Uses Silk.NET.OpenAL for Windows (x64/ARM64), macOS (Intel/Apple Silicon), and Linux support
- Music Tracks:
- Main Menu - Epic/mysterious arpeggios
- Overworld - Adventurous march (day/night variations)
- Town - Peaceful medieval melody
- Dungeon - Tense, foreboding atmosphere
- Combat - Fast, urgent battle music
- Victory/Defeat - Triumphant fanfare or somber dirge
- Sound Effects: Footsteps, sword swings, hits, misses, spell casting, monster deaths, UI feedback, and more
- .NET 9 SDK
dotnet builddotnet run --project src/UltimaIII.Avalonia| Key | Action |
|---|---|
| W / Up Arrow | Move North |
| S / Down Arrow | Move South |
| A / Left Arrow | Move West |
| D / Right Arrow | Move East |
| Space | Search |
| R | Rest |
| B | Enter Shop (when adjacent to counter) |
| T | Talk to quest NPC (when adjacent) |
| C | Cast spell (field magic — heal, cure, resurrect) |
| I | Open Party Inventory |
| J | Open Quest Log |
| X | Exit current location |
| Ctrl+Shift+S | Take screenshot |
| F5 | Save game |
| F12 | Quit game |
| Key | Action |
|---|---|
| W / Up Arrow | Move character north |
| S / Down Arrow | Move character south |
| A / Left Arrow | Move character west |
| D / Right Arrow | Move character east |
| T | Attack (select target) |
| C | Cast spell |
| U | Use item (consumables) |
| P | Pass turn |
| F | Flee from combat |
| Input | Action |
|---|---|
| WASD / Arrows | Move target cursor |
| Enter / Space | Confirm target |
| Escape | Cancel |
| Mouse Click | Select target tile |
| Mouse Double-Click | Select and confirm target |
| Key | Action |
|---|---|
| W/S / Up/Down | Browse items |
| A/D / Left/Right | Switch character |
| Enter / Space | Equip selected item |
| 1-5 | Switch tab (All/Weapons/Armor/Shields/Items) |
| Tab | Cycle tabs |
| Esc / I | Close inventory |
| Key | Action |
|---|---|
| W/S / Up/Down | Browse items |
| A/D / Left/Right | Switch character |
| Enter / Space | Confirm purchase/sale/equip/recruit |
| 1-4 | Switch tab (Buy/Sell/Recruit/Equip/Services) |
| Tab | Cycle tabs |
| Q | Toggle sell source (Character/Party inventory) |
| Esc | Leave shop |
| Key | Action |
|---|---|
| W/S / Up/Down | Browse casters, spells, or targets |
| Enter / Space | Select caster / cast spell / confirm target |
| Esc / C | Go back / close |
| Key | Action |
|---|---|
| W/S / Up/Down | Browse quests |
| Esc / J | Close quest log |
| Key | Action |
|---|---|
| W/S / Up/Down | Browse equipment, sockets, or gems |
| A/D / Left/Right | Switch character |
| Enter / Space | Select / confirm |
| Esc | Go back / close temple |
| Key | Action |
|---|---|
| W/S / Up/Down | Browse quests |
| Enter / Space | View details / accept / turn in |
| Esc | Go back / close |
The game supports PNG sprite overrides for any tile type. Place a 32x32 PNG in src/UltimaIII.Avalonia/Assets/sprites/ named after the tile type (lowercased). Any tile without a matching sprite falls back to code-drawn rendering.
Overworld / Town Terrain:
-
grass.png -
forest.png -
mountain.png -
water.png -
deepwater.png -
swamp.png -
desert.png -
lava.png -
bridge.png -
path.png -
flowers.png -
lamppost.png -
town.png -
dungeonentrance.png
Structures:
-
wall.png -
floor.png -
door.png -
lockeddoor.png -
secretdoor.png -
castlewall.png -
castlefloor.png -
counter.png -
sign.png
Dungeon Features:
-
stairsup.png -
stairsdown.png -
ladder.png -
pit.png -
ceilinghole.png -
trap.png -
exitportal.png -
void.png
Special:
-
altar.png -
fountain.png -
chest.png -
portal.png -
party.png
Combat sprites also go in Assets/sprites/. Player characters use their class name, monsters use their definition ID. Combat terrain checks for combat_<terrain>.png first, then falls back to the shared terrain sprite above.
Player Classes (by class):
-
fighter.png -
cleric.png -
wizard.png -
thief.png -
paladin.png -
barbarian.png -
lark.png -
illusionist.png -
druid.png -
alchemist.png -
ranger.png
Monsters (by ID):
-
orc.png -
goblin.png -
skeleton.png -
zombie.png -
ghoul.png -
giant_rat.png -
giant_spider.png -
gelatinous_cube.png -
troll.png -
ogre.png -
wraith.png -
vampire.png -
lich.png -
imp.png -
daemon.png -
balron.png -
dragon.png -
pirate.png -
sea_serpent.png -
guard.png
Combat Terrain (optional overrides):
-
combat_grass.png -
combat_forest.png -
combat_mountain.png -
combat_floor.png
- Framework: .NET 9
- UI: Avalonia UI 11.2
- Pattern: MVVM with CommunityToolkit.Mvvm
- Graphics: Custom tile rendering with retro CGA/EGA color palette
- Audio: Silk.NET.OpenAL for cross-platform audio, NVorbis for OGG Vorbis decoding
This project is licensed under the MIT License - see the LICENSE file for details.
A recreation of Ultima III: Exodus, originally created by Richard Garriott (Lord British) and published by Origin Systems in 1983.





