Merge pull request #325 from kichikuou/parts_input

PartsEngine: Implement pass_cursor flag, MOUSE_ON and MOUSE_MOVE message dispatch
This commit is contained in:
Nunuhara Cabbage
2026-04-19 07:01:05 -07:00
committed by GitHub
6 changed files with 72 additions and 16 deletions
+2
View File
@@ -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
View File
@@ -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),
+4 -3
View File
@@ -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),
+55 -8
View File
@@ -25,6 +25,8 @@
// true between calls to BeginClick and EndClick
bool parts_began_click = false;
// the mouse position at last update
static Point parts_prev_pos = {0};
// true when the left mouse button was down last update
static bool prev_clicking = false;
// the last (fully) clicked parts number
@@ -42,38 +44,67 @@ 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,
int passed_time, 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) {
parts_msg_push(parts->no, parts->delegate_index,
PARTS_MSG_MOUSE_ENTER, "ii", cur_pos.x, cur_pos.y);
parts->hover_time = 0;
}
if (!is_hovered && was_hovered) {
parts_msg_push(parts->no, parts->delegate_index,
PARTS_MSG_MOUSE_LEAVE, "ii", cur_pos.x, cur_pos.y);
}
if (is_hovered) {
// MOUSE_ON message fires every frame while hovering
parts_msg_push(parts->no, parts->delegate_index,
PARTS_MSG_MOUSE_ON, "iii", cur_pos.x, cur_pos.y, parts->hover_time);
parts->hover_time += passed_time;
// MOUSE_MOVE message fires when cursor moves while hovering
if (cur_pos.x != parts_prev_pos.x || cur_pos.y != parts_prev_pos.y) {
parts_msg_push(parts->no, parts->delegate_index,
PARTS_MSG_MOUSE_MOVE, "ii", cur_pos.x, cur_pos.y);
}
}
if (!is_hovered) {
parts_set_state(parts, PARTS_STATE_DEFAULT);
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 +127,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;
@@ -107,15 +139,19 @@ static void parts_update_mouse(struct parts *parts, Point cur_pos, bool cur_clic
}
}
void PE_UpdateInputState(possibly_unused int passed_time)
void PE_UpdateInputState(int passed_time)
{
Point cur_pos;
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, passed_time,
&hover_consumed, &click_consumed);
}
if (prev_clicking && !cur_clicking) {
@@ -126,6 +162,17 @@ void PE_UpdateInputState(possibly_unused int passed_time)
}
prev_clicking = cur_clicking;
parts_prev_pos = cur_pos;
}
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)
+3
View File
@@ -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;
@@ -371,6 +372,7 @@ struct parts {
int linked_to;
int linked_from;
bool is_hovered;
int hover_time;
int draw_filter;
bool message_window;
int alpha_clipper_parts_no;
@@ -379,6 +381,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
View File
@@ -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);