Ultima 9 in Widescreen Resolutions

u9_16x9

Ultima 9 comes from a fairly early era in 3D gaming, and from an era where 4:3 was by far the dominant screen dimension ratio. These days, of course, widescreen is prevalent, and while Ultima 9’s setup utility presents widescreen resolutions as selectable options, it only uses the vertical resolution value, and renders the game at the standard 4:3 ratio:

u9_regular_4x3

Fortunately, the good folks at the Wide Screen Gaming Forum (WSGF) have come up with a solution. Of course, it’s rather manual in nature:

Go to the installation folder and edit u9.exe with a hex editor. Search for the following hexadecimal values…

28 02 85 00 68 00 00 70 42 8B 88 BC 00 00 00 E8

00 70 42 represent the game’s default field of view (FOV) of 60. Change to the FOV you want by calculating the FOV (see below) or use these example values: 29 5C 96 42 equals an FOV of 75.18, 29 DC 8A 42 equals an FOV of 69.43. These give a Hor+ equivalent of the default FOV of 60.

For other FOV settings, calculate the horizontal FOV you want using FOV Calc or your own personal preference.
Next you need to convert your horizontal FOV into the four pair hexadecimal format.

Paste your horizontal FOV into IEEE-754 Analysis.
Make a note of the Binary32 value.
Reverse the pairs (so e.g. if Binary32 is 42 96 5C 29 change it to 29 5C 96 42).

If you already have existing saved games you will need to modify them as well. Go into the savegame folder where the game is installed and hex-edit the *.sav files. Search for 00 00 70 42 and change it to your custom FOV.

As the screenshot at the top shows, it’s quite possible to get the game looking more or less correct at 16:9 resolution. It looks a bit more skewed when stretched across three monitors using Eyefinity:

u9_eyefinity_3x1

At any rate, this isn’t something that can easily be wrapped up in a patch; you’ll have to follow the instructions at WSGF instead. Sadly, there doesn’t seem to be anything to be done (for now) about the UI scaling.

51 Responses

  1. Sanctimonia says:

    “Go to the installation folder and edit u9.exe with a hex editor. Search for the following hexadecimal values…”

    The last time I heard a line like that I ended up cracking the copy protection in Ultima V and waking up alone in a seedy hotel room. It wasn’t my finest moment. But seriously, that could be added to an existing graphical tool for Ultima IX. I’m guessing the “Binary32” part is referencing a 32-bit variable, which is either of type single or integer (both four bytes). Having to reverse the values probably means the variable is being converted to/from little/big endian. A hell of an improvement to Ultima IX…hopefully someone will make it more user friendly.

  2. Sergorn says:

    I Wonder if this could possibly be wrapped in a patch actually : I mean “all” you’d need is a small executable where you’d put the FOV/ratio you want and would edit the .exe accordingly. I’d have to assume this is doable somehow (doesn’t Beautiful Britannia creates its own .exe when you install it ?) since redistributing the modified .exe would be a big no no.

    That said I did try this fix and it works very well – having a Hor+ widescreen resolution or Hor- is a wecolme change.

    Sadly this doesn’t fix the UI issue. 🙁

  3. Kirinn says:

    Huh, that sounds easy enough. Unless someone beats me to it, I guess I’ll throw together a little GUI tool to apply a new FOV, later this week.

  4. Kirinn says:

    Well, I’ve got a tool that follows the given instructions, but it doesn’t work entirely as expected. The single 32-bit floating point value edited in u9.exe is not sufficient by itself; you can edit existing save games to make them show up in a new fov but as soon as you make a new save, the new save will use the unmodified fov again. I’m not sure how and if the original hack instructions worked to cause a permanent change for anyone…

    With that said, on a whim I replaced every occurrence of 00 00 70 42 in u9.exe with 00 00 F4 42 (60.0 to 122.0 I think). Starting a new game then not only applied the wider fov persistently, but also drew the journal graphics in the new fov. 😕 I’ll poke at it a bit more to identify exactly which memory address needs to be tweaked to just get the general persistent fov change.

    • Iceblade says:

      You are definitely going to want to be careful replacing too many bytes with this. The executable includes dialogue structures and object usecode amongst other more commonly hardcoded parts.

    • Sergorn says:

      What do you mean by drawing tghe journal graphics in the new fov ?

      This also makes me wonder – could there be some eidting like this that could allow fixing of the Journal in widescreen ? Just wondering.

      As for the fix, the info aout it said using an old save would not keep the new FOV, but starting a game from scratch should, but perhaps it is mistaken.

      • Kirinn says:

        The journal basically looks a lot smaller all of a sudden, scaled down by a similar multiplier as the fov went up. If there was a similar effect on the quick-item belt, that would be useful, but I didn’t observe such happening.

      • WtF Dragon says:

        That might actually be useful. Any chance you could post a screenshot?

      • Kirinn says:

        Of course, here’s a temporary link:
        http://mooncore.eu/gfx/u9mini.png
        (It’s 0.8Mb at a 1280×720 resolution, that is 16:9 ratio)

        I’m not entirely sure what is going on, but reverting to the unedited exe shows the journal as the size of nearly the entire screen. There doesn’t appear to be any significant horizontal stretching in either case.

      • WtF Dragon says:

        I hope I’m not alone in thinking this, but that looks great. Definitely worth keeping in play. And if you can get the rest of the UI to do the same…

      • Sergorn says:

        Whoa that looks small but… I gotta wonder if there might be a way to use what you found to modify the scale of the journal/books only so that they look slighty smaller. If that is somehow doable, this could solve that infamous UI scaling issue in widescreen mode.

      • Iceblade says:

        Looks like you have accidentally edited one of the GUMP values largely because it happened to have the same value as FOV. Be useful to know where in the executable you made changes. This could give us (Team FW) the opportunity to pinpoint where the GUMP code is in the executable.

      • WtF Dragon says:

        Well, this conversation just got at least five times more awesome.

      • Iceblade says:

        Well there is nothing left to do then to trial and error edit those 00 00 70 42’s until I find one that does something interesting. I’ll report back on what I see for each of these 21 instances.

      • Iceblade says:

        Well that was fast. I changed 70 to F4 at memory address 138554 (address in decimal). When I started the game, I forgot I had the gamestart.ini set. When I opened the journal, there was apparent size difference. When I loaded a savegame (one have one at the moment, which is on earth), I opened the journal and it was tiny.

      • Kirinn says:

        Ah, there you go then. 🙂 If that helps to reverse-engineer the gump structures, you should be able to fix the whole interface just by writing the right numbers at the right addresses. Of course, for best effect the right numbers need to be derived from the user’s game resolution or desired hFov…

      • Iceblade says:

        Change the 0x70 at address 207,969 to 0xF4 and tell me if you see any differences.

      • Iceblade says:

        8o Okay, that was weird. So weird I have difficulty describing it. Some how the camera is on top of the Avatar, and he appears smaller yet it doesn’t appear to take long at all for him to move from the TV to the door. In fact, it feels like the room has skunk in the lateral while being taller in vertical. Change at the 138545 from 8B to 9B.

      • Kirinn says:

        Poking 207969 with F4 didn’t do anything that I could notice at least in a freshly started game.

      • Iceblade says:

        That’s why I wanted you to check. I wasn’t sure if I was thinking a change happened when it actually hadn’t.

      • Kirinn says:

        Heh, that weird thing is like a sniper scope. 😀

      • Iceblade says:

        Change 42 to 52 at address: 138555

        So cute. :p

      • Iceblade says:

        I doubt I’m going to find non-journal code for GUMPs right near the journal area of the executable. Really no telling how far about bit-wise the GUMP code is.

    • Sergorn says:

      Also I’ve not checked on the save fils in a hex editor, but it definitlys looks as the new saves I did with the modified .exe keep the new FOV, so I don’t know

  5. Iceblade says:

    I wonder if changing the camera’s focal length would be important here.

    It is in the options.ini as CameraZoom

    • Kirinn says:

      It’s worth a try. In a more modern game, that would be the direct fov setting, but I was assuming in U9 it might just be the distance from camera to player rather than a wider render. Let’s see if there’s any fish-eye effect if that’s tweaked upward…

      • Kirinn says:

        For the record, I can’t get the CameraZoom to make any difference. The separate CameraDistance setting works as expected, and in case of higher hFov’s it may be a good idea to reduce the camera distance to compensate for the illusion of our Avatar being further away.

  6. Kirinn says:

    I couldn’t recognise any useful values either in the immediate vicinity of 0x21D38 after a cursory examination. But I did figure out what the value in that spot does exactly. It’s a yFov for the projection matrix of the graphic in question. In practice, the cotangent of half of yFov is a direct size multiplier.

    So… assuming the significant part of journal must take 75% of the game’s vertical resolution, and is natively 443.405px tall:
    desired height = Yres * 0.75
    multiplier to get desired height = Yres * 0.75 / 443.405
    value to write into exe at 0x21D38 = ArcCot(Yres * 0.75 / 443.405) * 2

    There’s a bit of rounding error, since I don’t know the exact pixel size of the journal. But here’s an example for a game resolution of 1280×768:
    desired height = 768 * 0.75 = 576
    multiplier = 576 / 443.405 = 1.2990381…
    value to write = ArcCot(1.2990381…) * 2 = 75.17818 = 3A 5B 96 42

    And sure enough, if you write those four bytes in, the left side of this picture turns into the right side:
    http://mooncore.eu/gfx/u9journ.png

    I might as well throw this easy functionality in as a bonus in the tool, but it’s a bit frustrating not knowing where the rest of the gumps are. Also, to avoid unnecessary tool proliferation, I think FW should eventually come with its own patcher?

    • Iceblade says:

      Need yes. Though I’ve run into one hell of a headache trying to figure out how to determine the address for various values within the executable. Going to have to hold off until I can get some serious how-to for this level of reverse-engineering.

      Anyway, I know why the savegames retain the old perspective. After the processes.dat file within the savegame are snapshots of a host of various game processes (not to be confused with the processes database file) including clocks, movement controllers, and the game camera amongst many others. What is pretty sweet is that each of the processes appears to begin with the title of the process making it very easy for a human to parse out each process.

      • Iceblade says:

        Well, the camera isn’t actually labeled, but based on the position of the 00 00 70 42. I’d say it is before the first process title after all those staggered blocks of FF FF FF FF’s.

    • Sergorn says:

      Okay just whoa : does it affect only the Journal but also the Spellbook and the other books in the game ?

      This actually fixes one of the biggest issue in the game in widescreen resolution. Because you see, this prevented from dragging any spells to the toolbar.

      The other Gumps are less of an issue I think – they’re a tad stretched in widescreen, but they work fine and are at their places.

    • Iceblade says:

      Excellent stuff. You have any experience with reverse engineering?

      • Kirinn says:

        Just got lucky, in this case. :p I do have a long-term on-going reverse-engineered project, but it’s way simpler than what you guys are doing.

  7. Kirinn says:

    OK, I’ve been poking at this a bit more, and the hack instructions as they’re originally given just don’t work for me. Here’s what I do:
    – With a fresh 1.19f U9.exe, find the sequence 28 02 85 00 68 00 00 70 42 8B 88 BC 00 00 00 E8, and change the 00007042 to 0000F442. For me, that dword is at 0x32AD5.
    – Run U9, it automatically loads the latest save. Go in the journal and start a new game, then quit.
    – Run U9 again; this time it won’t just load the latest save but will show the intro FMV and then zoom into our house, giving a fresh start.
    – The FOV remains unchanged.

    On the other hand, if I look for the sequence 89 9E F8 00 00 00 B8 00 00 70 42 89 9E 50 01, then the significant dword is at 0x15D726. Editing this one and following the above steps does result in a persistent fov change; any save games you make now will be loaded with the new fov even if you revert the dword change. (But with a reverted exe, any new saves made will again use the unchanged fov.)

    Could anyone confirm this is also the behavior you see?

    • Kirinn says:

      Ahhh, wait. Looks like there’s another address beside 0x15D726 that also needs to be edited for save games to persist in a new fov. Let me hack it a bit more.

  8. Kirinn says:

    What I thought was the books yfov may be something way more global. Seems that the value at the same address 0x21D38 is also what gets placed as the camera fov in all new savegames. Whereas the address 0x15D726 must be used only to initialise a new game.

    • Kirinn says:

      Ah, another thing was throwing me off. If you press K to switch to first person view, then K again to go back to normal view, the fov gets reset. Must be another dword responsible for that.

    • Kirinn says:

      Also pressing M to switch to temporary first person view resets the fov.
      These are the addresses that need the new fov written in them to fix the K and M issues:
      0x32B9A: camera fov to go to when leaving toggled first person view
      0x35A39: camera fov to go to when leaving temporary first person view

      That leaves two unknown addresses in the early part of the executable – 0x32AD5 and 0x32C5F. Perhaps these control some other fov change somewhere, but until a fov fail is encountered, I’ll leave them untweaked.

      Furthermore, in the save files the fov needs to be entered in two addresses which are apparently always 0x9E0 bytes apart. For all normal saves I’ve checked so far, it’s always at 0x3621C and 0x36BFC, plus the length of the save file name in bytes added to each address. For static\u9game0.sav, the addresses are instead 0x2DFF8 and 0x2E9D8.

      I think this should be enough to make the tool fully functional. We’ll still need to test it then.

    • Sergorn says:

      You’ve lost me at all the adresses and numbers, but I can’t wait for your tool !

      • Kirinn says:

        I think I’ve got everything implemented. Now just need to play up to the cleansing of Compassion to make sure there’s nothing obviously broken.

  9. Derp says:

    This isn’t necessary at all. If you’re using the GoG version, just edit run the nglide configurator and set your resolution to whatever you want. I run U9 beautifully at 2560×1600 this way with zero problems.

    If you’re not using the GoG version, just change your resolution manually in options.ini This was figured out years ago.

    • Sanctimonia says:

      The horror. LOL. Reminds me of when I occasionally realize a ton of code I wrote was in the end unnecessary and I just delete it and write off all the burned hours to fate.

    • WtF Dragon says:

      It’s true that much of this was already known. However, what really was useful that came out of this whole exercise was the fix for the scaling of the in-game books. That was not previously a known thing.

      • Sergorn says:

        In addition, the thing is that just chaning the numbers work but it does so by cropping the picture, so rather than expanding the field of view by showing more picture to the left and right, it shows left. The point of this hack is ti have a proper Hor+ FOV fix.