U4 Upgrade – Endgame Bug

For those who’ve attempted to play through Ultima IV with the latest U4 Upgrade (v1.2 or v1.3), you may have experienced a bug that prevented you from completing the end game. The problem hits after you answer all the virtue questions and obtain the codex, but the game appears to freeze in the middle of describing the Quest of the Avatar.

While the U4 Upgrade isn’t one of my patches, the purpose of the Exodus Project is to solve these types of problems in older Ultima games.  I did some digging on this a while back when I ran into the same thing, but totally forgot about it until recently. I was reminded of it while watching Kilg0re_Tr0ut’s Twitch stream of U4, who ran into the same problem. Let’s take a look at what’s wrong.

The Problem

The problem stems from an inaccurate file size for file LARGE.XMI. Take a look at this assembly code from ULTIMA.COM:

0189 mov bx,047c        ; number of paragraphs to allocate
018c mov ah,48
018e int 21             ; fcn 48 = allocate memory
0190 cs:
0191 mov [0725],ax      ; save segment address
0194 cs:
0195 mov dx,0742        ; cs:0742 -> "large.xmi"
0198 push ds
0199 push cs
019a pop ds             ; set ds=cs
01eb mov ax,03d00
019e int 21             ; fcn 3d = open file, 00 = readonly

In this section, we’re reserving 1148 paragraphs and loading LARGE.XMI into this space. Since there are 16 bytes/paragraph this equates to 18,368 bytes. However LARGE.XMI is actually 21,208 bytes in size. So we might have a buffer overrun. But, that’s assuming we attempt to load the full file size into that memory space. Let’s keep reading the assembly code to see if that’s what happens:

01a5 mov bx,ax           ; bx = file handle
01a7 cs:
01a8 mov cx,[074c]       ; cx = file size = 0x47c0
01ac cs:
01ad mov ds,[0725]       ; ds = segment address for data
01b1 xor dx,dx           ; dx = 0
01b3 mov ax,3f00
01b6 int 21              ; fcn 3f = read file

Here we’re reading the file into the memory we just reserved above. However note the file size. We’re loading less bytes than the actual size of LARGE.XMI. So now, when the game goes to read the last entry in the file, it crashes. This last entry is of course the end-game tune.

This wasn’t a problem in the U4 Upgrade v1.0 or v1.1 as the XMI files were all separate files and loaded individually.

The Solution

The solution is to increase the size of both values. I used a value of 0x0800 paragraphs for the memory size and 0x8000 for the file size which equates to 32kB. That’s more than enough space to fit the LARGE.XMI file.

I included a fix for this with my U4 Alternate Music package on the Downloads page.  This package was primarily intended as an alternate arrangement of Ultima 4’s music to use more appropriate instruments. So in the u4up-12 folder you will find:

  • ULTIMA.COM – new binary that fixes the endgame crash bug
  • LARGE.XMI – alternate arrangement of U4’s music

The package also includes alternate arrangements for XU4.

2 thoughts on “U4 Upgrade – Endgame Bug

  1. I’m wondering if you thought of looking into the bug that prevents you from moving up or down in the main menu (meaning you can only choose “Journey Onwards”, meaning that you have to create your character before applying the patch (and if you want to create a new character, you have to re-install the game)). I know how to bypass it, but it’s still kinda annoying.

    I’m glad that you’re still supporting these games (including this one). Maybe now, I’ll be motivated to finish these games.

    1. While I haven’t thought of this particular issue, in general I’ve received a lot of requests to improve the U4 Upgrade and I’ve given it quite a bit of thought. Because it wasn’t my product and was built in the pre-github era, the source code used to make it isn’t readily available.

      Having said that, if I do go this route I’ll likely disassemble it from scratch so that it plays nicely with all the other config & patch tools I’m using. But for now I don’t expect to do that before a U5 VGA patch. 😉

Leave a Reply

Your email address will not be published. Required fields are marked *