whscullin / apple2js

An Apple II emulator originally written in Javascript, now being converted to TypeScript
http://www.scullinsteel.com/apple2/
MIT License
438 stars 57 forks source link

Ultima V from the san inc pack does not work properly #128

Closed iflan closed 2 years ago

iflan commented 2 years ago

When everyone in the party dies, there is usually a "fade to black" sequence before Lord British resurrects the party. That does not happen with the emulator. Instead, the hard drive light stays on and nothing happens.

Repro steps:

  1. Load https://www.scullinsteel.com/apple2//e#https://mirrors.apple2.org.za/ftp.apple.asimov.net/images/games/collections/san_inc_prodos/ultima5%20PRODOS%20%28san%20inc%20pack%29.po
  2. Hit space a couple times when the title sequence starts.
  3. Create a new character. The fastest way is to do this is to just type garbage for the name and hit A until the whole sequence is done.
  4. Journey Onward. As soon as this happens, the emulator automatically goes into accelerated mode. I don't know why.
  5. Die. There are two ways that I've found effective: get poisoned or find some ents. Both work well.

Expected result: The fade to black sequence happens and then Lord British resurrects the party.

Actual result: Nothing happens.

Could this be related to the game activating the accelerated mode? Possibly. But since it's a ProDOS block device, I wouldn't think that timing would be that important.

I've tested this image on Virtual ][ and it works as expected. It also works correctly on real hardware.

whscullin commented 2 years ago

Cool, I didn't know they had their CORS headers set up so that was possible. IFAICT it's asking for acceleration via the Transwarp softswitch emulation, probably intentionally. From a quick investigation it's stuck in a read/write disk loop. (With the Preact UI you can actually see disk activity, woot!) I wonder if there's a bug in the Smartport code code around writing, it's probably not something that been exercised a whole lot.

iflan commented 2 years ago

I tried doing a bit of debugging:

  1. I tried going to Yew and getting killed by the guards. That, however, did not trigger the bug. :-(
  2. Dying outside afterwards caused the bug.
  3. I tried disassembling the loop that it seemed to be caught in, but it was very frustrating and I didn't get that far.
  4. Using some of the disassembled code, I found a link to qkumba's (@peterferrie) explanation of how he ported it to ProDOS. (Note that this link is not readable without playing with the site's CSS. Sigh.) In particular, there is a mention of $D363 which is one of the bits I partially disassembled, but didn't really understand. Apparently it's the start of the read block routine, which explains why the drive light stays on.

Also, this was the original discussion that prompted me to try this ProDOS-enabled crack. So much better than swapping disks all the time.

I'll poke around at it more this week.

peterferrie commented 2 years ago

$D363 is the lowest level of disk access. It sets the parameters and then calls through the SmartPort interface. If there's an error, then the caller that's five(!) levels up will retry infinitely without interaction. Assuming that's what's happening, why is the SmartPort call failing? Perhaps it thinks that the disk is somehow write-protected?

whscullin commented 2 years ago

Ugh, stupid bug. state.s &= flags.C; is not how you clear the carry flag. I guess for most cases it was coming in already clear so that just mangled all the other flags (how did this every work) but this case carry was coming in set.

whscullin commented 2 years ago

Fixed by https://github.com/whscullin/apple2js/commit/cc025447dc01cfdb684af813d66bc7ad845c4daa

iflan commented 2 years ago

Thanks @peterferrie and @whscullin!