FLAT_LIB_STOP_MOTION represents a sprite animation as a sequence of CG
frames. A stop_motion library specifies a base CG file (e.g. "foo.png");
at load time, parts_flat_load() discovers numbered frame variants
("foo_01.png", "foo_02.png", ...) and builds a frame list.
At render time, the active frame is resolved from the local timeline
clock using three parameters:
- span: number of timeline ticks each frame is displayed
- loop_type: 0 = play once and stop at last frame,
1 = loop forward,
2 = ping-pong (forward then backward)
- local: the timeline's current local time
The multiply and screen blend functions used in render_flat_item
ignored the source alpha, so transparent pixels still modulated the
destination color instead of leaving it untouched.
Add a draw_filter uniform to the parts fragment shader and have it
output an alpha-baked source color, so that the framebuffer result
after the GL blend equation interpolates correctly in alpha:
- multiply: shader outputs src = mix(vec3(1.0), mod_color, alpha)
blend (GL_DST_COLOR, GL_ZERO) gives src*dst,
i.e. mix(dst, mod_color*dst, alpha)
- screen: shader outputs src = mod_color * alpha
blend (GL_ONE, GL_ONE_MINUS_SRC_COLOR) gives src + (1-src)*dst,
i.e. mod_color*alpha + (1 - mod_color*alpha)*dst
In both cases alpha=0 leaves the destination untouched, alpha=1
gives the full multiply/screen result.
Also switch the surface-area mask from multiplication to discard,
so pixels outside the rect leave the destination intact under
multiply blending (where multiplying src by 0 would otherwise
zero out dst).
This adds a key handler facility to input.c so that the InputString
can intercept the Backspace key while the IME is open, and remove the
last character from the result string. Backspace is ignored while the
IME has composing text, so it does not interfere with IME editing.
The newer version (from Boku Dake no Hokenshitsu onwards) of
InputString.GetResultString() does not clear its internal string.
This fixes the issue in Rance 02 where the text always remained empty
when editing save comments.
This fixes heap use-after-free in the music mode in Rance 9.
Hold a reference to the struct page (`this` pointer) for the duration
of a method call. Without this, if the sole external reference to an
object is dropped during one of its method calls (e.g. an event handler
that destroys its own parent), the object and its members are freed
immediately, causing use-after-free when the VM tries to access them
afterward.
This matches the behavior of the original VM, which was introduced in
Rance9.exe and later titles.
The fix is gated on AIN v6.1+ (AIN v6 with a MSG1 section) to match
the original. Applying it unconditionally would change the heap refcount
state visible to resume saves, potentially breaking existing saves for
older games.
line_space was stored but never used during rendering or size
calculation. Apply it as inter-line spacing in both the size calculation
and the render path. Also initialize empty lines with the current text
style height so that newline-only lines occupy the correct space.
Change line_space from unsigned to int because negative values can be
set.
This fixes the rendering of the sample message in the "Message Color"
configuration of Rance 9.
PE_SetPartsFont* and PE_SetText*Space functions only modified the text
style struct without re-rendering existing character textures. Since
character glyphs are baked into textures at append time, subsequent
style changes had no visible effect.
mag_speed is a per-plugin integer (default 1) set by SetMagSpeed on
all existing plugins. use_mag_speed is a per-instance flag (default
true) set by SetInstanceUseMagSpeed. When use_mag_speed is true,
motion delta_frame is multiplied by mag_speed.
POL v4 introduces material groups with texture blending. A material's
sub-material can be a "blend group" containing exactly two leaf
materials, whose textures are blended using per-vertex weights for
smooth terrain transitions.
This implements Parts_SetDrag and drag/drop event handling. When a part
has drag enabled, clicking and moving the mouse will move the part and
emit DRAG_BEGIN/DRAGGING/DRAG_END messages. Drop target detection emits
DROP_ENTER/DROP_ON/DROPPED/DROP_LEAVE messages on parts under the cursor
during drag.
This adds PARTS_LAYOUT_BOX parts type with support for automatic
horizontal/vertical child positioning. Layout calculation runs during
the component update cycle, repositioning children before their global
parameters are combined.
This function has a large number of parameters, which are serialized
fields from CASConstructionProcess. Dispatch on the command number to
the appropriate PE_Add*ToPartsConstructionProcess function.
MOUSE_ON is sent every frame while hovering, with cursor position and
accumulated hover time. MOUSE_MOVE is sent when the cursor position
changes during hover.
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.