From 195399635e8644ce3c0738a3241a7538612e1b33 Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Wed, 8 Jul 2026 11:45:10 -0500 Subject: [PATCH] Updating mini textbox --- src/dusk/rpg/cutscene/cutscene.h | 16 +++++++ src/dusk/rpg/cutscene/cutscenesystem.c | 15 +++++++ src/dusk/rpg/cutscene/cutscenesystem.h | 11 +++++ src/dusk/rpg/cutscene/item/cutsceneitem.c | 14 ++++++ src/dusk/rpg/cutscene/item/cutsceneitem.h | 6 +++ src/dusk/rpg/cutscene/item/ui/CMakeLists.txt | 2 + .../rpg/cutscene/item/ui/cutscenetextmini.c | 33 ++++++++++++++ .../rpg/cutscene/item/ui/cutscenetextmini.h | 44 +++++++++++++++++++ .../cutscene/item/ui/cutscenetextminihide.c | 25 +++++++++++ .../cutscene/item/ui/cutscenetextminihide.h | 39 ++++++++++++++++ src/dusk/rpg/cutscene/scene/testcutscene.h | 1 + src/dusk/rpg/rpg.c | 10 ----- src/dusk/ui/rpg/textbox/uitextboxmini.c | 6 ++- src/dusk/ui/rpg/textbox/uitextboxmini.h | 10 ++++- src/dusk/ui/rpg/textbox/uitextboxminilist.c | 9 ++++ src/dusk/ui/rpg/textbox/uitextboxminilist.h | 12 ++++- 16 files changed, 238 insertions(+), 15 deletions(-) create mode 100644 src/dusk/rpg/cutscene/item/ui/cutscenetextmini.c create mode 100644 src/dusk/rpg/cutscene/item/ui/cutscenetextmini.h create mode 100644 src/dusk/rpg/cutscene/item/ui/cutscenetextminihide.c create mode 100644 src/dusk/rpg/cutscene/item/ui/cutscenetextminihide.h diff --git a/src/dusk/rpg/cutscene/cutscene.h b/src/dusk/rpg/cutscene/cutscene.h index 157fc7cf..9fc70116 100644 --- a/src/dusk/rpg/cutscene/cutscene.h +++ b/src/dusk/rpg/cutscene/cutscene.h @@ -34,6 +34,22 @@ typedef struct cutscene_s { #define CUTSCENE_TEXT(TEXT) \ { .type = CUTSCENE_ITEM_TYPE_TEXT, .text = { .text = TEXT } } +#define CUTSCENE_TEXT_MINI(TEXT, X, Y, Z, DURATION) \ + { \ + .type = CUTSCENE_ITEM_TYPE_TEXT_MINI, \ + .textMini = { \ + .text = TEXT, \ + .position = { X, Y, Z }, \ + .duration = DURATION \ + } \ + } + +#define CUTSCENE_TEXT_MINI_HIDE(INDEX) \ + { \ + .type = CUTSCENE_ITEM_TYPE_TEXT_MINI_HIDE, \ + .textMiniHide = { .index = INDEX } \ + } + #define CUTSCENE_WAIT(WAIT) \ { .type = CUTSCENE_ITEM_TYPE_WAIT, .wait = WAIT } diff --git a/src/dusk/rpg/cutscene/cutscenesystem.c b/src/dusk/rpg/cutscene/cutscenesystem.c index cad53612..933dbc0b 100644 --- a/src/dusk/rpg/cutscene/cutscenesystem.c +++ b/src/dusk/rpg/cutscene/cutscenesystem.c @@ -37,6 +37,7 @@ void cutsceneSystemStartCutsceneWith( CUTSCENE_SYSTEM.entityLastCreated = NULL; CUTSCENE_SYSTEM.entityLastRef = NULL; CUTSCENE_SYSTEM.areaLastCreated = CUTSCENE_AREA_LAST_CREATED; + CUTSCENE_SYSTEM.textMiniLastCreated = CUTSCENE_TEXT_MINI_LAST_CREATED; CUTSCENE_SYSTEM.currentItem = 0xFF;// Set to 0xFF so Next wraps to 0. cutsceneSystemNext(); } @@ -65,6 +66,7 @@ void cutsceneSystemNext() { CUTSCENE_SYSTEM.entityLastCreated = NULL; CUTSCENE_SYSTEM.entityLastRef = NULL; CUTSCENE_SYSTEM.areaLastCreated = CUTSCENE_AREA_LAST_CREATED; + CUTSCENE_SYSTEM.textMiniLastCreated = CUTSCENE_TEXT_MINI_LAST_CREATED; return; } @@ -130,6 +132,18 @@ uint8_t cutsceneSystemGetAreaId(const uint8_t areaId) { return areaId; } +uint8_t cutsceneSystemGetTextMiniId(const uint8_t index) { + if(index == CUTSCENE_TEXT_MINI_LAST_CREATED) { + assertTrue( + CUTSCENE_SYSTEM.textMiniLastCreated != CUTSCENE_TEXT_MINI_LAST_CREATED, + "CUTSCENE_TEXT_MINI_LAST_CREATED used but no mini textbox has been " + "shown" + ); + return CUTSCENE_SYSTEM.textMiniLastCreated; + } + return index; +} + void cutsceneSystemDispose() { CUTSCENE_SYSTEM.scene = NULL; CUTSCENE_SYSTEM.currentItem = 0xFF; @@ -139,4 +153,5 @@ void cutsceneSystemDispose() { CUTSCENE_SYSTEM.entityLastCreated = NULL; CUTSCENE_SYSTEM.entityLastRef = NULL; CUTSCENE_SYSTEM.areaLastCreated = CUTSCENE_AREA_LAST_CREATED; + CUTSCENE_SYSTEM.textMiniLastCreated = CUTSCENE_TEXT_MINI_LAST_CREATED; } diff --git a/src/dusk/rpg/cutscene/cutscenesystem.h b/src/dusk/rpg/cutscene/cutscenesystem.h index 4fa901d5..6f95a2a7 100644 --- a/src/dusk/rpg/cutscene/cutscenesystem.h +++ b/src/dusk/rpg/cutscene/cutscenesystem.h @@ -15,6 +15,7 @@ typedef struct entity_s entity_t; #define CUTSCENE_ENTITY_LAST_CREATED ((uint8_t)0xFC) #define CUTSCENE_ENTITY_LAST_REF ((uint8_t)0xFB) #define CUTSCENE_AREA_LAST_CREATED ((uint8_t)0xFF) +#define CUTSCENE_TEXT_MINI_LAST_CREATED ((uint8_t)0xFA) // Maximum number of bytes a running cutscene may request via // cutscene_t.dataSize. @@ -29,6 +30,7 @@ typedef struct { entity_t *entityLastCreated; entity_t *entityLastRef; uint8_t areaLastCreated; + uint8_t textMiniLastCreated; // Data (used by the current item). cutsceneitemdata_t data; @@ -86,6 +88,15 @@ entity_t * cutsceneSystemGetEntity(const uint8_t entityIndex); */ uint8_t cutsceneSystemGetAreaId(const uint8_t areaId); +/** + * Resolves a raw mini textbox slot index (or CUTSCENE_TEXT_MINI_LAST_CREATED + * sentinel) to a concrete UI_TEXTBOX_MINI_LIST slot index. + * + * @param index Raw slot index or sentinel value. + * @returns The resolved slot index. + */ +uint8_t cutsceneSystemGetTextMiniId(const uint8_t index); + /** * Advance to the next item in the cutscene. */ diff --git a/src/dusk/rpg/cutscene/item/cutsceneitem.c b/src/dusk/rpg/cutscene/item/cutsceneitem.c index a733f8c8..bf80836a 100644 --- a/src/dusk/rpg/cutscene/item/cutsceneitem.c +++ b/src/dusk/rpg/cutscene/item/cutsceneitem.c @@ -13,6 +13,14 @@ void cutsceneItemStart(const cutsceneitem_t *item, cutsceneitemdata_t *data) { cutsceneTextStart(item, data); break; + case CUTSCENE_ITEM_TYPE_TEXT_MINI: + cutsceneTextMiniStart(item, data); + break; + + case CUTSCENE_ITEM_TYPE_TEXT_MINI_HIDE: + cutsceneTextMiniHideStart(item, data); + break; + case CUTSCENE_ITEM_TYPE_CALLBACK: cutsceneCallbackStart(item, data); break; @@ -91,6 +99,12 @@ bool_t cutsceneItemUpdate(const cutsceneitem_t *item, cutsceneitemdata_t *data) case CUTSCENE_ITEM_TYPE_TEXT: return cutsceneTextUpdate(item, data); + case CUTSCENE_ITEM_TYPE_TEXT_MINI: + return cutsceneTextMiniUpdate(item, data); + + case CUTSCENE_ITEM_TYPE_TEXT_MINI_HIDE: + return cutsceneTextMiniHideUpdate(item, data); + case CUTSCENE_ITEM_TYPE_CALLBACK: return cutsceneCallbackUpdate(item, data); diff --git a/src/dusk/rpg/cutscene/item/cutsceneitem.h b/src/dusk/rpg/cutscene/item/cutsceneitem.h index 62914438..faffe912 100644 --- a/src/dusk/rpg/cutscene/item/cutsceneitem.h +++ b/src/dusk/rpg/cutscene/item/cutsceneitem.h @@ -17,6 +17,8 @@ #include "entity/cutsceneentityturn.h" #include "entity/cutsceneentitywalktoentity.h" #include "ui/cutscenetext.h" +#include "ui/cutscenetextmini.h" +#include "ui/cutscenetextminihide.h" #include "ui/cutscenefade.h" #include "item/cutsceneitemgive.h" #include "maparea/cutscenemapareaadd.h" @@ -29,6 +31,8 @@ typedef struct cutscene_s cutscene_t; typedef enum { CUTSCENE_ITEM_TYPE_NULL, CUTSCENE_ITEM_TYPE_TEXT, + CUTSCENE_ITEM_TYPE_TEXT_MINI, + CUTSCENE_ITEM_TYPE_TEXT_MINI_HIDE, CUTSCENE_ITEM_TYPE_CALLBACK, CUTSCENE_ITEM_TYPE_WAIT, CUTSCENE_ITEM_TYPE_CUTSCENE, @@ -53,6 +57,8 @@ struct cutsceneitem_s { union { cutscenetext_t text; + cutscenetextmini_t textMini; + cutscenetextminihide_t textMiniHide; cutscenecallback_t callback; cutscenewait_t wait; const cutscene_t *cutscene; diff --git a/src/dusk/rpg/cutscene/item/ui/CMakeLists.txt b/src/dusk/rpg/cutscene/item/ui/CMakeLists.txt index d77f42fd..7649be71 100644 --- a/src/dusk/rpg/cutscene/item/ui/CMakeLists.txt +++ b/src/dusk/rpg/cutscene/item/ui/CMakeLists.txt @@ -6,5 +6,7 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME} PUBLIC cutscenetext.c + cutscenetextmini.c + cutscenetextminihide.c cutscenefade.c ) diff --git a/src/dusk/rpg/cutscene/item/ui/cutscenetextmini.c b/src/dusk/rpg/cutscene/item/ui/cutscenetextmini.c new file mode 100644 index 00000000..f4d7f750 --- /dev/null +++ b/src/dusk/rpg/cutscene/item/ui/cutscenetextmini.c @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "rpg/cutscene/item/cutsceneitem.h" +#include "rpg/cutscene/cutscenesystem.h" +#include "ui/rpg/textbox/uitextboxminilist.h" + +void cutsceneTextMiniStart( + const cutsceneitem_t *item, + cutsceneitemdata_t *data +) { + uint8_t index = uiTextboxMiniListGetNext(); + uiTextboxMiniShow( + &UI_TEXTBOX_MINI_LIST[index], + item->textMini.text, + item->textMini.position, + item->textMini.duration, + NULL, + NULL + ); + CUTSCENE_SYSTEM.textMiniLastCreated = index; +} + +bool_t cutsceneTextMiniUpdate( + const cutsceneitem_t *item, + cutsceneitemdata_t *data +) { + return true; +} diff --git a/src/dusk/rpg/cutscene/item/ui/cutscenetextmini.h b/src/dusk/rpg/cutscene/item/ui/cutscenetextmini.h new file mode 100644 index 00000000..fb2628e7 --- /dev/null +++ b/src/dusk/rpg/cutscene/item/ui/cutscenetextmini.h @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "dusk.h" + +typedef struct cutsceneitem_s cutsceneitem_t; +typedef union cutsceneitemdata_u cutsceneitemdata_t; + +#define CUTSCENE_TEXT_MINI_MAX_CHARS 128 + +typedef struct { + char_t text[CUTSCENE_TEXT_MINI_MAX_CHARS]; + vec3 position; + float_t duration; +} cutscenetextmini_t; + +/** + * Starts a mini text item (shows a mini textbox at the given world + * position for the given duration, then completes immediately). + * + * @param item The cutscene item. + * @param data Runtime data storage. + */ +void cutsceneTextMiniStart( + const cutsceneitem_t *item, + cutsceneitemdata_t *data +); + +/** + * Updates a mini text item (always completes immediately). + * + * @param item The cutscene item. + * @param data Runtime data storage. + * @returns true always. + */ +bool_t cutsceneTextMiniUpdate( + const cutsceneitem_t *item, + cutsceneitemdata_t *data +); diff --git a/src/dusk/rpg/cutscene/item/ui/cutscenetextminihide.c b/src/dusk/rpg/cutscene/item/ui/cutscenetextminihide.c new file mode 100644 index 00000000..c02da2be --- /dev/null +++ b/src/dusk/rpg/cutscene/item/ui/cutscenetextminihide.c @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "rpg/cutscene/item/cutsceneitem.h" +#include "rpg/cutscene/cutscenesystem.h" +#include "ui/rpg/textbox/uitextboxminilist.h" + +void cutsceneTextMiniHideStart( + const cutsceneitem_t *item, + cutsceneitemdata_t *data +) { + uint8_t index = cutsceneSystemGetTextMiniId(item->textMiniHide.index); + uiTextboxMiniClose(&UI_TEXTBOX_MINI_LIST[index]); +} + +bool_t cutsceneTextMiniHideUpdate( + const cutsceneitem_t *item, + cutsceneitemdata_t *data +) { + return true; +} diff --git a/src/dusk/rpg/cutscene/item/ui/cutscenetextminihide.h b/src/dusk/rpg/cutscene/item/ui/cutscenetextminihide.h new file mode 100644 index 00000000..9dbd7f8e --- /dev/null +++ b/src/dusk/rpg/cutscene/item/ui/cutscenetextminihide.h @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "dusk.h" + +typedef struct cutsceneitem_s cutsceneitem_t; +typedef union cutsceneitemdata_u cutsceneitemdata_t; + +typedef struct { + uint8_t index; +} cutscenetextminihide_t; + +/** + * Starts a mini text hide step (closes the mini textbox immediately). + * + * @param item The cutscene item. + * @param data Runtime data storage. + */ +void cutsceneTextMiniHideStart( + const cutsceneitem_t *item, + cutsceneitemdata_t *data +); + +/** + * Updates a mini text hide step (always completes immediately). + * + * @param item The cutscene item. + * @param data Runtime data storage. + * @returns true always. + */ +bool_t cutsceneTextMiniHideUpdate( + const cutsceneitem_t *item, + cutsceneitemdata_t *data +); diff --git a/src/dusk/rpg/cutscene/scene/testcutscene.h b/src/dusk/rpg/cutscene/scene/testcutscene.h index d95a2d71..16ae4703 100755 --- a/src/dusk/rpg/cutscene/scene/testcutscene.h +++ b/src/dusk/rpg/cutscene/scene/testcutscene.h @@ -16,6 +16,7 @@ CUTSCENE(TEST_ONE, 0, DEFAULT, CUTSCENE(TEST_TWO, 0, DEFAULT, CUTSCENE_TEXT("Test Two."), CUTSCENE_ENTITY_ADD(ENTITY_TYPE_NPC, 4, 4, 0), + CUTSCENE_TEXT_MINI("Hello!", 4, 4, 0, 3.0f), CUTSCENE_ENTITY_WALK_TO(CUTSCENE_ENTITY_LAST_CREATED, 8, 2, 0), // CUTSCENE_CONCURRENT( // CUTSCENE_ENTITY_WALK_TO(CUTSCENE_ENTITY_INTERACT, 4, 4, 0), diff --git a/src/dusk/rpg/rpg.c b/src/dusk/rpg/rpg.c index 73f63e1b..6a92cf72 100644 --- a/src/dusk/rpg/rpg.c +++ b/src/dusk/rpg/rpg.c @@ -65,16 +65,6 @@ errorret_t rpgInit(void) { backpackAdd(ITEM_ID_POTATO, 3); backpackAdd(ITEM_ID_APPLE, 8); - // TEST: Show a mini textbox at the world origin. - uiTextboxMiniShow( - &UI_TEXTBOX_MINI_LIST[0], - "Hello, World!", - (vec3){ 0.0f, 0.0f, 0.0f }, - 100.0f, - NULL, - NULL - ); - // TEST: Create a test map area. uint8_t areaIndex = mapAreaAdd( (worldpos_t){ 11, 3, 0 }, diff --git a/src/dusk/ui/rpg/textbox/uitextboxmini.c b/src/dusk/ui/rpg/textbox/uitextboxmini.c index 7e4b43b2..f04515c6 100644 --- a/src/dusk/ui/rpg/textbox/uitextboxmini.c +++ b/src/dusk/ui/rpg/textbox/uitextboxmini.c @@ -69,8 +69,10 @@ errorret_t uiTextboxMiniUpdate(uitextboxmini_t *mini) { errorChain(uiTextboxUpdate(&mini->box)); - mini->timer -= TIME.delta; - if(mini->timer <= 0.0f) uiTextboxMiniClose(mini); + if(mini->timer != UI_TEXTBOX_MINI_DURATION_INFINITE) { + mini->timer -= TIME.delta; + if(mini->timer <= 0.0f) uiTextboxMiniClose(mini); + } errorOk(); } diff --git a/src/dusk/ui/rpg/textbox/uitextboxmini.h b/src/dusk/ui/rpg/textbox/uitextboxmini.h index eb61608d..f173b3c5 100644 --- a/src/dusk/ui/rpg/textbox/uitextboxmini.h +++ b/src/dusk/ui/rpg/textbox/uitextboxmini.h @@ -12,6 +12,10 @@ #define UI_TEXTBOX_MINI_LINES_MAX 2 #define UI_TEXTBOX_MINI_WIDTH_MAX 160.0f +// Magic duration value that keeps a mini textbox visible indefinitely +// instead of counting down and auto-closing. +#define UI_TEXTBOX_MINI_DURATION_INFINITE -1.0f + typedef struct uitextboxmini_s uitextboxmini_t; typedef void (*uitextboxminiclosedcallback_t)(const uitextboxmini_t *mini); @@ -59,7 +63,8 @@ void uiTextboxMiniInit(uitextboxmini_t *mini); * @param mini The mini textbox to show. * @param text Null-terminated source string. * @param position World-space position the box is anchored to on screen. - * @param duration How long the mini textbox stays visible, in seconds. + * @param duration How long the mini textbox stays visible, in seconds, or + * UI_TEXTBOX_MINI_DURATION_INFINITE to never auto-close. * @param closed Called once the timer elapses and the box closes. May be * NULL. * @param user Opaque pointer passed back through the closed callback. @@ -76,7 +81,8 @@ void uiTextboxMiniShow( /** * Advances the typewriter scroll and counts down the visibility timer. * Closes the mini textbox and fires its closed callback once the timer - * elapses. Has no effect if not active. + * elapses. Has no effect if not active or if the duration was set to + * UI_TEXTBOX_MINI_DURATION_INFINITE. * * @param mini The mini textbox to update. * @returns Any error that occurs. diff --git a/src/dusk/ui/rpg/textbox/uitextboxminilist.c b/src/dusk/ui/rpg/textbox/uitextboxminilist.c index 3e066418..070bc817 100644 --- a/src/dusk/ui/rpg/textbox/uitextboxminilist.c +++ b/src/dusk/ui/rpg/textbox/uitextboxminilist.c @@ -8,14 +8,23 @@ #include "uitextboxminilist.h" uitextboxmini_t UI_TEXTBOX_MINI_LIST[UI_TEXTBOX_MINI_LIST_COUNT]; +uint8_t UI_TEXTBOX_MINI_LIST_NEXT; errorret_t uiTextboxMiniListInit(void) { for(uint8_t i = 0; i < UI_TEXTBOX_MINI_LIST_COUNT; i++) { uiTextboxMiniInit(&UI_TEXTBOX_MINI_LIST[i]); } + UI_TEXTBOX_MINI_LIST_NEXT = 0; errorOk(); } +uint8_t uiTextboxMiniListGetNext(void) { + uint8_t index = UI_TEXTBOX_MINI_LIST_NEXT; + UI_TEXTBOX_MINI_LIST_NEXT = + (UI_TEXTBOX_MINI_LIST_NEXT + 1) % UI_TEXTBOX_MINI_LIST_COUNT; + return index; +} + errorret_t uiTextboxMiniListUpdate(void) { for(uint8_t i = 0; i < UI_TEXTBOX_MINI_LIST_COUNT; i++) { errorChain(uiTextboxMiniUpdate(&UI_TEXTBOX_MINI_LIST[i])); diff --git a/src/dusk/ui/rpg/textbox/uitextboxminilist.h b/src/dusk/ui/rpg/textbox/uitextboxminilist.h index 9b4167b2..f3040b2c 100644 --- a/src/dusk/ui/rpg/textbox/uitextboxminilist.h +++ b/src/dusk/ui/rpg/textbox/uitextboxminilist.h @@ -11,14 +11,24 @@ #define UI_TEXTBOX_MINI_LIST_COUNT 4 extern uitextboxmini_t UI_TEXTBOX_MINI_LIST[UI_TEXTBOX_MINI_LIST_COUNT]; +extern uint8_t UI_TEXTBOX_MINI_LIST_NEXT; /** - * Initializes all UI_TEXTBOX_MINI_LIST slots. + * Initializes all UI_TEXTBOX_MINI_LIST slots and resets + * UI_TEXTBOX_MINI_LIST_NEXT. * * @returns Any error that occurs. */ errorret_t uiTextboxMiniListInit(void); +/** + * Returns the index of the next UI_TEXTBOX_MINI_LIST slot to use, cycling + * through all slots in round-robin order via UI_TEXTBOX_MINI_LIST_NEXT. + * + * @returns The next slot index. + */ +uint8_t uiTextboxMiniListGetNext(void); + /** * Updates all UI_TEXTBOX_MINI_LIST slots. *