In case of simultaneous hyperfruit and non-hyperfruit - which happen to
occur on some aspire maps - the desired behaviour is to hyperdash. This
did not previously occur, due to annoying details in how
`HitObjectContainer` is structured.
`HitObjectContainer`'s drawable comparer determines the order of
updating the objects. One could say that forcing the hyperfruit to be
updated last, after normal fruit, could help; unfortunately this is
complicated by the existence of juice streams and the fact that while a
juice stream can be terminated by a normal fruit that is coincidental
with a hyperfruit, the two are not comparable directly using the
comparer in any feasible way.
Therefore, apply a `Catcher`-level workaround that intends to handle
this locally; in short, if a hyperdash was toggled in a given frame, it
cannot be toggled off again in the same frame. This yields the desired
behaviour.
Previously, some judgement results were not reverted
when the source DHO is not alive (e.g. frames skipped in editor).
Now, all results are reverted in the exact reverse order.
Because the is "end glow" is when a hyper-dash is *started*, the name was confusing.
The "after-image" was already used in the code as a synonym of "end glow" inconsistently.
It resolves mutual dependency of `Catcher` and `CatcherTrailDisplay`.
Trail generation logic is moved to `Catcher`.
The generation logic no longer uses delayed scheduling because the hidden state is hard to manage.
Instead, the last time a trail is generated is calculated and used.
The new logic has a different behavior when the dash key is pressed in succession under 50ms, but it is not noticeable for normal plays.