This implements SetPassCursor/GetPartsPassCursor HLL functions. The
pass_cursor flag controls whether the cursor "passes through" a
component to reach parts behind it.
Key changes to input processing:
- Iteration order changed from back-to-front to front-to-back for proper
cursor consumption
- MOUSE_ENTER / MOUSE_LEAVE now fire for all parts regardless of
clickable
- Click hit test uses clickable || !pass_cursor pre-filter
- pass_cursor=false parts consume the cursor, preventing hover and
click events from reaching parts behind them
parts_set_state silently ignored transitions to uninitialized states,
causing parts without a HOVERED state to remain in CLICKED after mouse
release. Fall back through CLICKED -> HOVERED -> DEFAULT so the first
initialized state is always selected. DEFAULT is accepted unconditionally
as the terminal fallback, matching the original engine's behavior.
This introduces a per-parts is_hovered flag (replacing the global
parts_prev_pos) and fire MOUSE_ENTER, MOUSE_LEAVE, KEY_TRIGGER,
KEY_DOWN, MOUSE_CLICK, and KEY_UP events on the corresponding mouse
state transitions.
This also fixes the hittest in parts_update_mouse() to account for the
parent's global position, and to use the DEFAULT state hitbox (matching
the original engine's behavior).
PartsEngine in Rance 9 manages multiple "controllers" (called "layers"
in game scripts) that provide part grouping, draw-order control, and
bulk release. This implements the core controller API:
- AddController / RemoveController: push/pop a controller on the
stack. RemoveController releases all parts belonging to the removed
controller and returns their IDs in erase_number_list.
- SetActiveLayer / GetActiveLayer / GetSystemOverlayLayer: control
which controller newly created parts are assigned to. The system
overlay controller is a special controller that always renders on
top and survives ReleaseAllWithoutSystem.
- ReleaseAllWithoutSystem: releases all parts except those in the
system overlay controller and re-initializes the controller stack.
Controllers are identified by their position in the stack (0 = bottom).
Draw ordering uses the scene's two-level sprite sorting: sp.z is set to
the controller's stack index and sp.z2 to the part's Z value, so parts
in higher controllers always render above lower ones regardless of
individual Z values. When the parts_multi_controller flag (see below) is
false, the original Z ordering is preserved (allowing Z-interleaving
with non-parts scene sprites -- see #180) for compatibility with games
that do not use controllers.
Save/load of the controller stack and per-part controller_no is gated on
a parts_multi_controller flag (set at PreLink time when the game's HLL
exports AddController) rather than a save version bump. This keeps the
save format stable for games that do not use controllers, while allowing
the save format to evolve freely during development.
This adds PARTS_MOVIE type which creates a SACT sprite as a render
target for DrawMovie.
The GL texture is shared between the SACT sprite and parts_common, so
movie frames rendered to the sprite are directly visible through the
parts engine's rendering path.
In Rance 9 (and Blade Briders), KiwiSoundEngine looks up BGM and sound
files in archives by name formatted as "%05d" rather than by archive
index. Since the Sound_Seek function only exists in these games' HLL
definitions, its presence is used to switch Music_IsExist, Music_Prepare,
Sound_IsExist and Sound_Prepare to name-based lookups at PreLink time.
PartsEngine.UpdateComponent() is a three-argument function that
corresponds to the older PartsEngine's Update() function.
PE_UpdateComponent is a one-argument function for
GUIEngine.UpdateComponent().
As noted in notes/parts-engine.md, many functions have been renamed.
They link to existing PE_ functions.
Some functions have had their arguments or return values changed from
int to float. For now, they just use the existing int functions.
Class members are destroyed in the reverse order of their declaration
(like C++). The previous code destroyed members in declaration order,
which caused a use-after-free in Rance 9's T_Map class.
Added a test to verify the reverse destruction order.
When a delegate finishes calling all registered functions,
variable_fini() was called on the original stack arguments. For ref
types, this results in an unbalanced heap_unref() because the caller
pushes raw ref-values without incrementing the reference count. Non-ref
string/struct/array arguments are not affected because their push
instructions allocate new heap slots with ownership.
This fixes use-after-free in T_Loop@checkSelect in Rance 9.
Two changes from Pastel Chime 3 (likely to make the executables
incompatible):
- SystemService.XXX function
- PartsEngine.Update() has two dummy string parameters
The system.ExistsFile() system call returns 1 if a file or directory
exists, but returns 0 when the provided path ends with a directory
separator, regardless of whether a directory exists at that location.
This subtle difference in behavior caused problems in Pastel Chime 3.
The meaning of the method parameter is the same as that of
StoatSpriteEngine.SP_SetDrawMethod.
This fixes a visual issue in Pastel Chime 3's battle scene.