mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-09-28 18:08:07 +03:00
PartsEngine: Implement pass_cursor flag
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
This commit is contained in:
@@ -162,6 +162,8 @@ bool PE_SetPartsConstructionSurfaceArea(int parts_no, int x, int y, int w, int h
|
||||
|
||||
// input.c
|
||||
void PE_UpdateInputState(int passed_time);
|
||||
void PE_SetPassCursor(int parts_no, bool pass);
|
||||
bool PE_GetPartsPassCursor(int parts_no);
|
||||
void PE_SetClickable(int parts_no, bool clickable);
|
||||
bool PE_GetPartsClickable(int parts_no);
|
||||
void PE_SetPartsGroupDecideOnCursor(int group_no, bool decide_on_cursor);
|
||||
|
||||
+2
-2
@@ -918,7 +918,7 @@ HLL_LIBRARY(GUIEngine,
|
||||
HLL_EXPORT(Parts_SetShow, PE_SetShow),
|
||||
HLL_EXPORT(Parts_SetAlpha, PE_SetAlpha),
|
||||
HLL_EXPORT(Parts_SetPartsDrawFilter, PE_SetPartsDrawFilter),
|
||||
HLL_TODO_EXPORT(Parts_SetPassCursor, GUIEngine_Parts_SetPassCursor),
|
||||
HLL_EXPORT(Parts_SetPassCursor, PE_SetPassCursor),
|
||||
HLL_EXPORT(Parts_SetClickable, PE_SetClickable),
|
||||
HLL_EXPORT(Parts_SetSpeedupRateByMessageSkip, PE_SetSpeedupRateByMessageSkip),
|
||||
HLL_TODO_EXPORT(Parts_SetResetTimerByChangeInputStatus, GUIEngine_Parts_SetResetTimerByChangeInputStatus),
|
||||
@@ -945,7 +945,7 @@ HLL_LIBRARY(GUIEngine,
|
||||
HLL_EXPORT(Parts_GetPartsShow, PE_GetPartsShow),
|
||||
HLL_EXPORT(Parts_GetPartsAlpha, PE_GetPartsAlpha),
|
||||
HLL_EXPORT(Parts_GetPartsDrawFilter, PE_GetPartsDrawFilter),
|
||||
HLL_TODO_EXPORT(Parts_GetPartsPassCursor, GUIEngine_Parts_GetPartsPassCursor),
|
||||
HLL_EXPORT(Parts_GetPartsPassCursor, PE_GetPartsPassCursor),
|
||||
HLL_EXPORT(Parts_GetPartsClickable, PE_GetPartsClickable),
|
||||
HLL_TODO_EXPORT(Parts_GetPartsSpeedupRateByMessageSkip, GUIEngine_Parts_GetPartsSpeedupRateByMessageSkip),
|
||||
HLL_TODO_EXPORT(Parts_GetResetTimerByChangeInputStatus, GUIEngine_Parts_GetResetTimerByChangeInputStatus),
|
||||
|
||||
@@ -143,7 +143,6 @@ static int PartsEngine_PartsFunc(int func_id, struct page **array_int,
|
||||
}
|
||||
|
||||
HLL_WARN_UNIMPLEMENTED(, void, PartsEngine, StopSoundWithoutSystemSound);
|
||||
HLL_WARN_UNIMPLEMENTED(, void, PartsEngine, Parts_SetPassCursor, int Number, bool Pass);
|
||||
|
||||
static void PartsEngine_PreLink(void);
|
||||
|
||||
@@ -242,6 +241,7 @@ HLL_LIBRARY(PartsEngine,
|
||||
HLL_EXPORT(SetPartsDrawFilter, PE_SetPartsDrawFilter),
|
||||
HLL_EXPORT(SetAddColor, PE_SetAddColor),
|
||||
HLL_EXPORT(SetMultiplyColor, PE_SetMultiplyColor),
|
||||
HLL_EXPORT(SetPassCursor, PE_SetPassCursor),
|
||||
HLL_EXPORT(SetClickable, PE_SetClickable),
|
||||
HLL_EXPORT(SetSpeedupRateByMessageSkip, PE_SetSpeedupRateByMessageSkip),
|
||||
HLL_TODO_EXPORT(SetResetTimerByChangeInputStatus, PartsEngine_SetResetTimerByChangeInputStatus),
|
||||
@@ -252,6 +252,7 @@ HLL_LIBRARY(PartsEngine,
|
||||
HLL_EXPORT(GetPartsAlpha, PE_GetPartsAlpha),
|
||||
HLL_TODO_EXPORT(GetAddColor, PartsEngine_GetAddColor),
|
||||
HLL_TODO_EXPORT(GetMultiplyColor, PartsEngine_GetMultiplyColor),
|
||||
HLL_EXPORT(GetPartsPassCursor, PE_GetPartsPassCursor),
|
||||
HLL_EXPORT(GetPartsClickable, PE_GetPartsClickable),
|
||||
HLL_TODO_EXPORT(GetPartsSpeedupRateByMessageSkip, PartsEngine_GetPartsSpeedupRateByMessageSkip),
|
||||
HLL_TODO_EXPORT(GetResetTimerByChangeInputStatus, PartsEngine_GetResetTimerByChangeInputStatus),
|
||||
@@ -644,7 +645,7 @@ HLL_LIBRARY(PartsEngine,
|
||||
HLL_TODO_EXPORT(Parts_CreateParts3DLayerPluginID, PartsEngine_Parts_CreateParts3DLayerPluginID),
|
||||
HLL_TODO_EXPORT(Parts_GetParts3DLayerPluginID, PartsEngine_Parts_GetParts3DLayerPluginID),
|
||||
HLL_TODO_EXPORT(Parts_ReleaseParts3DLayerPluginID, PartsEngine_Parts_ReleaseParts3DLayerPluginID),
|
||||
HLL_EXPORT(Parts_SetPassCursor, PartsEngine_Parts_SetPassCursor),
|
||||
HLL_EXPORT(Parts_SetPassCursor, PE_SetPassCursor),
|
||||
HLL_EXPORT(Parts_SetClickable, PE_SetClickable),
|
||||
HLL_TODO_EXPORT(Parts_SetResetTimerByChangeInputStatus, PartsEngine_Parts_SetResetTimerByChangeInputStatus),
|
||||
HLL_TODO_EXPORT(Parts_SetDrag, PartsEngine_Parts_SetDrag),
|
||||
@@ -653,7 +654,7 @@ HLL_LIBRARY(PartsEngine,
|
||||
HLL_EXPORT(Parts_SetOnCursorShowLinkPartsNumber, PE_SetOnCursorShowLinkPartsNumber),
|
||||
HLL_TODO_EXPORT(Parts_SetSoundNumber, PartsEngine_Parts_SetSoundNumber),
|
||||
HLL_EXPORT(Parts_SetPartsPixelDecide, PE_SetPartsPixelDecide),
|
||||
HLL_TODO_EXPORT(Parts_GetPartsPassCursor, PartsEngine_Parts_GetPartsPassCursor),
|
||||
HLL_EXPORT(Parts_GetPartsPassCursor, PE_GetPartsPassCursor),
|
||||
HLL_EXPORT(Parts_GetPartsClickable, PE_GetPartsClickable),
|
||||
HLL_TODO_EXPORT(Parts_GetResetTimerByChangeInputStatus, PartsEngine_Parts_GetResetTimerByChangeInputStatus),
|
||||
HLL_TODO_EXPORT(Parts_GetPartsDrag, PartsEngine_Parts_GetPartsDrag),
|
||||
|
||||
+37
-7
@@ -42,19 +42,25 @@ static bool parts_hittest(struct parts *parts, int state, Point pos)
|
||||
return SDL_PointInRect(&pos, &hitbox);
|
||||
}
|
||||
|
||||
static void parts_update_mouse(struct parts *parts, Point cur_pos, bool cur_clicking)
|
||||
static void parts_update_mouse(struct parts *parts, Point cur_pos, bool cur_clicking,
|
||||
bool *hover_consumed, bool *click_consumed)
|
||||
{
|
||||
// Always use DEFAULT state hitbox regardless of the current display state.
|
||||
bool is_hovered = parts_hittest(parts, PARTS_STATE_DEFAULT, cur_pos);
|
||||
bool is_hovered = parts_hittest(parts, PARTS_STATE_DEFAULT, cur_pos)
|
||||
&& !*hover_consumed;
|
||||
|
||||
bool was_hovered = parts->is_hovered;
|
||||
parts->is_hovered = is_hovered;
|
||||
|
||||
// !pass_cursor parts consume the cursor for parts behind them
|
||||
if (is_hovered && !parts->pass_cursor)
|
||||
*hover_consumed = true;
|
||||
|
||||
if (parts->linked_from >= 0 && is_hovered != was_hovered) {
|
||||
parts_dirty(parts_get(parts->linked_from));
|
||||
}
|
||||
|
||||
if (!parts_began_click || !parts->clickable)
|
||||
if (!parts_began_click)
|
||||
return;
|
||||
|
||||
if (is_hovered && !was_hovered) {
|
||||
@@ -71,9 +77,18 @@ static void parts_update_mouse(struct parts *parts, Point cur_pos, bool cur_clic
|
||||
return;
|
||||
}
|
||||
|
||||
// click down: just remember the parts number for later
|
||||
bool click_eligible = parts->clickable || !parts->pass_cursor;
|
||||
if (!click_eligible || *click_consumed) {
|
||||
if (!was_hovered)
|
||||
audio_play_sound(parts->on_cursor_sound);
|
||||
parts_set_state(parts, PARTS_STATE_HOVERED);
|
||||
return;
|
||||
}
|
||||
|
||||
// click down: first eligible part captures the click
|
||||
if (cur_clicking && !prev_clicking) {
|
||||
click_down_parts = parts->no;
|
||||
*click_consumed = true;
|
||||
|
||||
// KEY_TRIGGER message fires on press transition
|
||||
parts_msg_push(parts->no, parts->delegate_index,
|
||||
@@ -96,7 +111,8 @@ static void parts_update_mouse(struct parts *parts, Point cur_pos, bool cur_clic
|
||||
}
|
||||
|
||||
// click event: only if the click down event had same parts number
|
||||
if (prev_clicking && !cur_clicking && click_down_parts == parts->no) {
|
||||
if (parts->clickable && prev_clicking && !cur_clicking
|
||||
&& click_down_parts == parts->no) {
|
||||
audio_play_sound(parts->on_click_sound);
|
||||
clicked_parts = parts->no;
|
||||
|
||||
@@ -113,9 +129,13 @@ void PE_UpdateInputState(possibly_unused int passed_time)
|
||||
bool cur_clicking = key_is_down(VK_LBUTTON);
|
||||
mouse_get_pos(&cur_pos.x, &cur_pos.y);
|
||||
|
||||
bool hover_consumed = false;
|
||||
bool click_consumed = false;
|
||||
struct parts *parts;
|
||||
PARTS_LIST_FOREACH(parts) {
|
||||
parts_update_mouse(parts, cur_pos, cur_clicking);
|
||||
// Iterate front-to-back (highest z first) for proper cursor consumption
|
||||
PARTS_LIST_FOREACH_REVERSE(parts) {
|
||||
parts_update_mouse(parts, cur_pos, cur_clicking,
|
||||
&hover_consumed, &click_consumed);
|
||||
}
|
||||
|
||||
if (prev_clicking && !cur_clicking) {
|
||||
@@ -128,6 +148,16 @@ void PE_UpdateInputState(possibly_unused int passed_time)
|
||||
prev_clicking = cur_clicking;
|
||||
}
|
||||
|
||||
void PE_SetPassCursor(int parts_no, bool pass)
|
||||
{
|
||||
parts_get(parts_no)->pass_cursor = !!pass;
|
||||
}
|
||||
|
||||
bool PE_GetPartsPassCursor(int parts_no)
|
||||
{
|
||||
return parts_get(parts_no)->pass_cursor;
|
||||
}
|
||||
|
||||
void PE_SetClickable(int parts_no, bool clickable)
|
||||
{
|
||||
parts_get(parts_no)->clickable = !!clickable;
|
||||
|
||||
@@ -364,6 +364,7 @@ struct parts {
|
||||
int delegate_index;
|
||||
int sprite_deform;
|
||||
bool clickable;
|
||||
bool pass_cursor;
|
||||
int on_cursor_sound;
|
||||
int on_click_sound;
|
||||
int origin_mode;
|
||||
@@ -379,6 +380,7 @@ struct parts {
|
||||
};
|
||||
|
||||
#define PARTS_LIST_FOREACH(iter) TAILQ_FOREACH(iter, &parts_list, parts_list_entry)
|
||||
#define PARTS_LIST_FOREACH_REVERSE(iter) TAILQ_FOREACH_REVERSE(iter, &parts_list, parts_list, parts_list_entry)
|
||||
#define PARTS_FOREACH_CHILD(iter, parent) TAILQ_FOREACH(iter, &parent->children, child_list_entry)
|
||||
|
||||
// parts.c
|
||||
|
||||
+6
-3
@@ -532,8 +532,10 @@ static void save_parts(struct iarray_writer *w, struct parts *parts)
|
||||
iarray_write(w, parts->alpha_clipper_parts_no);
|
||||
// TODO: once the Rance 9 save format stabilizes, bump save version
|
||||
// and save unconditionally
|
||||
if (parts_multi_controller)
|
||||
if (parts_multi_controller) {
|
||||
iarray_write(w, parts->controller_no);
|
||||
iarray_write(w, parts->pass_cursor);
|
||||
}
|
||||
|
||||
unsigned motion_count_pos = iarray_writer_pos(w);
|
||||
iarray_write(w, 0); // size of motion list
|
||||
@@ -575,9 +577,10 @@ static void load_parts(struct iarray_reader *r, int version)
|
||||
parts->alpha_clipper_parts_no = iarray_read(r);
|
||||
// TODO: once the Rance 9 save format stabilizes, bump save version
|
||||
// and load based on version check
|
||||
if (parts_multi_controller)
|
||||
if (parts_multi_controller) {
|
||||
parts->controller_no = iarray_read(r);
|
||||
|
||||
parts->pass_cursor = iarray_read(r);
|
||||
}
|
||||
int motion_count = iarray_read(r);
|
||||
for (int i = 0; i < motion_count; i++) {
|
||||
struct parts_motion *motion = load_parts_motion(r);
|
||||
|
||||
Reference in New Issue
Block a user