I’ve had several posts about the hotel clerk and stat gain over the past few weeks. In part I think that’s because character advancement is a key quality of role-playing games. But just because I don’t think the issue is quite settled yet, here is another.
In the next release, I’ve added a feature where the player will get the choice of which stat to upgrade. This is a gameplay improvement of course, rather than an audio/visual upgrade, and as such is toggle-able via config.
In a previous post I talked about the issues with stat boost probability and offered solution in v2.0. However, I also mentioned that I didn’t quite see that as the final solution.
Ultima 2 has been notably unique among its brethren in that how your character advances is completely random. By contrast, nearly all other Ultima’s offer the player a choice, whether via signposts, shrines, orbs or trainers. And while randomness does play some role in U4 & U5, it’s by no means the only means of progression.
Ultimately, I feel that the player should get to choose. That should remove the impetus to restore and count your steps every time you don’t get the desired stat.
Now we get technical. The original stat boost code has been completely refactored.
# 3d7e test [08fa],01 ; bit 0 = hotel clerk gameplay fix # 3d83 jz 3d8a ; gameplay fix disabled, jump # 3d85 call 7f6e ; al = prompt user to select stat # 3d88 jmp 3d8d ; continue below... # 3d8a call 7f53 ; al = choose random stat (75%)
Here test the config value to see if the gameplay fix is enabled. Offset 0x08fa contains the “gameplay fixes” byte and bit 0 represents the hotel clerk fix. There’s of course room here to store 7 other gameplay fixes, but they’re not in use at the moment.
If enabled, we call out to prompt the user to select a stat. If not, we call another function that contains the original logic that randomly chooses a stat with a 75% success rate. Note that there’s no “if/else” in assembly language so we have to construct the equivalent with jump instructions.
; if not in range of 0-5; no stat upgrade # 3d8d cmp al,06 ; check if in range of 0-5 # 3d8f jae 3cb6 ; al >= 6, no stat upgrade
Next, we check if the returned value is in the range 0-5 which indicates a valid stat id. The value may be outside that range if the player chooses an option other than 1-6. Or, if the fix was disabled, we likely have hit that 25% failure rate for a random stat.
# 3d93 mov ah,00 # 3d95 mov di,ax ; di = stat id # 3d97 mov al,[di+004b] ; get stat value # 3d9a mov cx,0004 ; loop counter = 4 # 3d9d call 49eb ; increment stat by offer amount # 3da0 loop 3d9d ; repeat
Lastly, we fetch the stat value from memory and call a function that increments the stat. Incrementing a stat is a bit more complicated than just adding the offer amount, as we also have to do an overflow check & cap if a stat rolls beyond 99. We repeat 4 times to achieve the 100 gold to 4 stat points ratio.