The previous output showed the comparisons between items, but was out of sync with the actual comparison method. Updated method only shows relevant data.
If flats can be less than other flats at the same Z coord, then the result would be reliant on with item is this vs other. Making the check flat vs non-flat adds consistency.
As reported in bug #12503, this book does not display the right text. The
correct text is in the usecode, but unreachable in the regular game.
Replace the text for this book at runtime with the originally intended text for
the book. To work this change needs an update to ultima.dat which should be
regenerated before the next release, but it's backwards-compatible with older
dat files and will just not do anything.
Fixes#12093, the avatar keeps standing when casting a spell. This is because
there are breaks between the animations, and the mover kept resetting to
standing. Don't reset if the last animation was a cast.
This is the second part of fixing Crusader elevator speeds after e3ee65. With
this change they move at the same speed as the original (completing their
travel in ~0.6s)
Previously, UC process return would defer termination to the next clock tick,
so waiting processes would be delayed by an extra tick. The elevator platform
speeds in Crusader show that waiters should be executed on the *same* clock
tick as the process returns.
However, if we terminate and schedule waiters immediately then other things
don't work (eg, the door does not open for the first Thermatron).
This suggests that the correct (to original game) behavior is to defer
termination until the end of the current process list, then wake and execute
waiting processes.
Only apply this to Crusader - it *doesn't* get the right speed on U8, where NPC
moves execute too quickly with this change. With just e3ee65, U8 NPC moves are
exactly right.
Previously we implemented implies as the same as waitFor, but that suspends the
current process straight away. All uses of implies in the usecode are
also immediately followed by a suspend. A typical flow is something like:
005A: 0A push byte 05h
005C: 0C push dword 00000000h
0061: 57 spawn 02 00 0A0C:0032 (FREE::ordinal32 (waitNTimerTicks))
0068: 6E add sp -02h
006A: 5E push retval
006B: 54 implies 01 01
006E: 12 pop temp
006F: 53 suspend
So after implies we should actually continue executing the current UC process
until a suspend or return, otherwise we wake up next frame only to suspend
again. For longer-running spawns this probably makes no noticable difference,
but in Crusader the elevators spawn a process which only waits 1 tick. This
should actually run the ELEVAT process again on the very next tick, but instead
it restarts *3* ticks later:
Tick 1:
1a. ELEVAT: spawn 1 tick sleep, execnow
1b. SLEEP: record start tick as tick 1
1c. ELEVAT: implies (waitFor) - process suspends
Tick 2:
2a. SLEEP: current tick is tick 2, (start+1) return, terminateDeferred
Tick 3:
3a. SLEEP: process terminates, notify ELEVAT process
3b. ELEVAT: wake up because of terminated sleep, pop return, suspend again
Tick 4:
4a. ELEVAT: continue again
This fixes it to only sleep for 2 ticks, which is still not totally correct
(terminateDeferred should maybe happen at the end of the frame to match
original?) but it's an improvement and it doesn't seem to break anything in U8.
Waiting for PROC_TERM_DEFERRED processes is fine and needed for compatibility -
they will still notify other processes when they actually terminate. Only
ignore the waitFor on processes which have already notified their waiters.
This fixes the end of the level in Crusader, but likely fixes some subtle
freeze bugs in U8 too.
The implies opcode was already checking for invalid process IDs (which happens
when speaking to children), but not terminated process IDs. There was a window
where a process could start waiting for an already-terminated process and never
get woken up.