Emoji support to characters
This commit is contained in:
@@ -144,6 +144,16 @@ typedef struct cutscene_s {
|
||||
#define CUTSCENE_FADE_FROM_WHITE(DURATION) \
|
||||
CUTSCENE_FADE(COLOR_WHITE, COLOR_TRANSPARENT_WHITE, DURATION, EASING_LINEAR)
|
||||
|
||||
#define CUTSCENE_EMOJI(ENTITY_INDEX, EMOJI_TYPE, DURATION) \
|
||||
{ \
|
||||
.type = CUTSCENE_ITEM_TYPE_EMOJI, \
|
||||
.emoji = { \
|
||||
.entityIndex = ENTITY_INDEX, \
|
||||
.emojiType = EMOJI_TYPE, \
|
||||
.duration = DURATION \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CUTSCENE_SET_PAUSE(FLAGS) \
|
||||
{ .type = CUTSCENE_ITEM_TYPE_SET_PAUSE, .setPause = (FLAGS) }
|
||||
|
||||
|
||||
@@ -89,6 +89,10 @@ void cutsceneItemStart(const cutsceneitem_t *item, cutsceneitemdata_t *data) {
|
||||
cutsceneStartBattleStart(item, data);
|
||||
break;
|
||||
|
||||
case CUTSCENE_ITEM_TYPE_EMOJI:
|
||||
cutsceneEmojiStart(item, data);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -153,6 +157,9 @@ bool_t cutsceneItemUpdate(const cutsceneitem_t *item, cutsceneitemdata_t *data)
|
||||
case CUTSCENE_ITEM_TYPE_START_BATTLE:
|
||||
return cutsceneStartBattleUpdate(item, data);
|
||||
|
||||
case CUTSCENE_ITEM_TYPE_EMOJI:
|
||||
return cutsceneEmojiUpdate(item, data);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "ui/cutscenetextmini.h"
|
||||
#include "ui/cutscenetextminihide.h"
|
||||
#include "ui/cutscenefade.h"
|
||||
#include "ui/cutsceneemoji.h"
|
||||
#include "item/cutsceneitemgive.h"
|
||||
#include "maparea/cutscenemapareaadd.h"
|
||||
#include "maparea/cutscenemaparearemove.h"
|
||||
@@ -49,7 +50,8 @@ typedef enum {
|
||||
CUTSCENE_ITEM_TYPE_MAP_AREA_ADD,
|
||||
CUTSCENE_ITEM_TYPE_MAP_AREA_REMOVE,
|
||||
CUTSCENE_ITEM_TYPE_MAP_AREA_WAIT,
|
||||
CUTSCENE_ITEM_TYPE_START_BATTLE
|
||||
CUTSCENE_ITEM_TYPE_START_BATTLE,
|
||||
CUTSCENE_ITEM_TYPE_EMOJI
|
||||
} cutsceneitemtype_t;
|
||||
|
||||
struct cutsceneitem_s {
|
||||
@@ -76,6 +78,7 @@ struct cutsceneitem_s {
|
||||
cutscenemaparearemove_t mapAreaRemove;
|
||||
cutscenemapareawait_t mapAreaWait;
|
||||
cutscenestartbattle_t startBattle;
|
||||
cutsceneemoji_t emoji;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -9,4 +9,5 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
cutscenetextmini.c
|
||||
cutscenetextminihide.c
|
||||
cutscenefade.c
|
||||
cutsceneemoji.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 "rpg/entity/entity.h"
|
||||
|
||||
void cutsceneEmojiStart(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
) {
|
||||
entity_t *entity = cutsceneSystemGetEntity(item->emoji.entityIndex);
|
||||
uiEmojiAdd(entity->id, item->emoji.duration, item->emoji.emojiType);
|
||||
}
|
||||
|
||||
bool_t cutsceneEmojiUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include "ui/rpg/uiemoji.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t entityIndex;
|
||||
float_t duration;
|
||||
uiemojitype_t emojiType;
|
||||
} cutsceneemoji_t;
|
||||
|
||||
/**
|
||||
* Starts an emoji step (shows an emoji above the entity for the given
|
||||
* duration, then completes immediately).
|
||||
*
|
||||
* @param item The cutscene item.
|
||||
* @param data Runtime data storage.
|
||||
*/
|
||||
void cutsceneEmojiStart(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Updates an emoji step (always completes immediately).
|
||||
*
|
||||
* @param item The cutscene item.
|
||||
* @param data Runtime data storage.
|
||||
* @returns true always.
|
||||
*/
|
||||
bool_t cutsceneEmojiUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
@@ -17,6 +17,9 @@ 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_EMOJI(
|
||||
CUTSCENE_ENTITY_LAST_CREATED, UI_EMOJI_EXCLAMATION_MARK, 2.0f
|
||||
),
|
||||
CUTSCENE_ENTITY_WALK_TO(CUTSCENE_ENTITY_LAST_CREATED, 8, 2, 0),
|
||||
// CUTSCENE_CONCURRENT(
|
||||
// CUTSCENE_ENTITY_WALK_TO(CUTSCENE_ENTITY_INTERACT, 4, 4, 0),
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include "assert/assert.h"
|
||||
#include "console/console.h"
|
||||
|
||||
#include "ui/rpg/uiemoji.h"
|
||||
|
||||
void rpgTestAreaCallback(entity_t *entity, const uint8_t trigger) {
|
||||
consolePrint("rpgTestAreaCallback: trigger=%u", trigger);
|
||||
}
|
||||
|
||||
@@ -3,4 +3,10 @@
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
uiemoji.c
|
||||
)
|
||||
|
||||
|
||||
add_subdirectory(textbox)
|
||||
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "uiemoji.h"
|
||||
#include "display/spritebatch/spritebatch.h"
|
||||
#include "time/time.h"
|
||||
#include "util/memory.h"
|
||||
#include "display/shader/shaderunlit.h"
|
||||
#include "rpg/entity/entity.h"
|
||||
#include "rpg/rpgcamera.h"
|
||||
|
||||
uiemoji_t UI_EMOJI;
|
||||
|
||||
errorret_t uiEmojiInit(void) {
|
||||
memoryZero(&UI_EMOJI, sizeof(UI_EMOJI));
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void uiEmojiAdd(
|
||||
const uint8_t entity,
|
||||
const float_t duration,
|
||||
const uiemojitype_t type
|
||||
) {
|
||||
uint8_t slot = 0xFF;
|
||||
// Find an available slot if any
|
||||
for(uint8_t i = 0; i < UI_EMOJI_ACTIVE_COUNT; i++) {
|
||||
if(UI_EMOJI.items[i].time <= 0.0f) {
|
||||
slot = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if(UI_EMOJI.items[i].entity == entity) {
|
||||
slot = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if(UI_EMOJI.items[i].type == UI_EMOJI_NULL) {
|
||||
slot = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(slot == 0xFF) {
|
||||
// Whichever ends soonest
|
||||
float_t minTime = UI_EMOJI.items[0].time;
|
||||
slot = 0;
|
||||
for(uint8_t i = 1; i < UI_EMOJI_ACTIVE_COUNT; i++) {
|
||||
if(UI_EMOJI.items[i].time >= minTime) continue;
|
||||
minTime = UI_EMOJI.items[i].time;
|
||||
slot = i;
|
||||
}
|
||||
}
|
||||
|
||||
uiemojiitem_t *item = &UI_EMOJI.items[slot];
|
||||
item->entity = entity;
|
||||
item->time = duration;
|
||||
item->type = type;
|
||||
}
|
||||
|
||||
errorret_t uiEmojiUpdate(void) {
|
||||
for(uint8_t i = 0; i < UI_EMOJI_ACTIVE_COUNT; i++) {
|
||||
uiemojiitem_t *item = &UI_EMOJI.items[i];
|
||||
if(item->type == UI_EMOJI_NULL) continue;
|
||||
|
||||
item->time -= TIME.delta;
|
||||
|
||||
if(item->time <= 0.0f) {
|
||||
item->type = UI_EMOJI_NULL;
|
||||
item->entity = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t uiEmojiDraw(void) {
|
||||
spritebatchsprite_t sprites[UI_EMOJI_ACTIVE_COUNT];
|
||||
uint8_t count = 0;
|
||||
|
||||
for(uint8_t i = 0; i < UI_EMOJI_ACTIVE_COUNT; i++) {
|
||||
uiemojiitem_t *item = &UI_EMOJI.items[i];
|
||||
if(item->type == UI_EMOJI_NULL) continue;
|
||||
|
||||
vec2 screenPos;
|
||||
rpgCameraToScreen(ENTITIES[item->entity].renderPosition, screenPos);
|
||||
|
||||
spritebatchsprite_t *sprite = &sprites[count++];
|
||||
sprite->min[0] = screenPos[0];
|
||||
sprite->min[1] = screenPos[1] - UI_EMOJI_SIZE;
|
||||
sprite->min[2] = 0.0f;
|
||||
sprite->max[0] = screenPos[0] + UI_EMOJI_SIZE;
|
||||
sprite->max[1] = screenPos[1];
|
||||
sprite->max[2] = 0.0f;
|
||||
sprite->uvMin[0] = 0.0f;
|
||||
sprite->uvMin[1] = 0.0f;
|
||||
sprite->uvMax[0] = 1.0f;
|
||||
sprite->uvMax[1] = 1.0f;
|
||||
}
|
||||
|
||||
if(count == 0) errorOk();
|
||||
|
||||
shadermaterial_t mat = {
|
||||
.unlit = {
|
||||
.color = COLOR_WHITE,
|
||||
.texture = NULL
|
||||
}
|
||||
};
|
||||
errorChain(spriteBatchBuffer(sprites, count, &SHADER_UNLIT, mat));
|
||||
errorChain(spriteBatchFlush());
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t uiEmojiDispose(void) {
|
||||
errorOk();
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "error/error.h"
|
||||
|
||||
#define UI_EMOJI_ACTIVE_COUNT 4
|
||||
#define UI_EMOJI_SIZE 32.0f
|
||||
|
||||
typedef enum {
|
||||
UI_EMOJI_NULL,
|
||||
|
||||
UI_EMOJI_QUESTION_MARK,
|
||||
UI_EMOJI_EXCLAMATION_MARK,
|
||||
|
||||
UI_EMOJI_COUNT,
|
||||
} uiemojitype_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t entity;
|
||||
float_t time;
|
||||
uiemojitype_t type;
|
||||
} uiemojiitem_t;
|
||||
|
||||
typedef struct {
|
||||
uiemojiitem_t items[UI_EMOJI_ACTIVE_COUNT];
|
||||
} uiemoji_t;
|
||||
|
||||
extern uiemoji_t UI_EMOJI;
|
||||
|
||||
/**
|
||||
* Initialize the UI emoji.
|
||||
*/
|
||||
errorret_t uiEmojiInit(void);
|
||||
|
||||
/**
|
||||
* Show a UI emoji for a specific entity.
|
||||
*
|
||||
* @param entity The entity to show the emoji for.
|
||||
* @param duration The duration to display the emoji.
|
||||
* @param type The type of emoji to display.
|
||||
*/
|
||||
void uiEmojiAdd(
|
||||
const uint8_t entity,
|
||||
const float_t duration,
|
||||
const uiemojitype_t type
|
||||
);
|
||||
|
||||
/**
|
||||
* Update the UI emoji.
|
||||
*/
|
||||
errorret_t uiEmojiUpdate(void);
|
||||
|
||||
/**
|
||||
* Draw the UI emoji.
|
||||
*/
|
||||
errorret_t uiEmojiDraw(void);
|
||||
|
||||
/**
|
||||
* Dispose of the UI emoji.
|
||||
*/
|
||||
errorret_t uiEmojiDispose(void);
|
||||
+18
-8
@@ -23,6 +23,7 @@
|
||||
#include "ui/frame/uiconfirm.h"
|
||||
#include "ui/rpg/textbox/uitextboxmain.h"
|
||||
#include "ui/rpg/textbox/uitextboxminilist.h"
|
||||
#include "ui/rpg/uiemoji.h"
|
||||
|
||||
uielement_t UI_ELEMENTS[] = {
|
||||
{
|
||||
@@ -30,7 +31,6 @@ uielement_t UI_ELEMENTS[] = {
|
||||
.dispose = uiFrameDispose
|
||||
},
|
||||
|
||||
|
||||
// Fullbox under: above scene, below system UI.
|
||||
{
|
||||
.init = uiFullboxUnderInit,
|
||||
@@ -38,19 +38,21 @@ uielement_t UI_ELEMENTS[] = {
|
||||
.draw = uiFullboxUnderDraw
|
||||
},
|
||||
|
||||
// in world stuff
|
||||
{
|
||||
.init = uiEmojiInit,
|
||||
.update = uiEmojiUpdate,
|
||||
.draw = uiEmojiDraw,
|
||||
.dispose = uiEmojiDispose
|
||||
},
|
||||
|
||||
// Ingame menus
|
||||
{
|
||||
.init = uiGameMenuInit,
|
||||
.draw = uiGameMenuDraw,
|
||||
.dispose = uiGameMenuDispose
|
||||
},
|
||||
|
||||
{
|
||||
.init = uiSettingsInit,
|
||||
.update = uiSettingsUpdate,
|
||||
.draw = uiSettingsDraw,
|
||||
.dispose = uiSettingsDispose
|
||||
},
|
||||
|
||||
{
|
||||
.init = uiBattleMenuInit,
|
||||
.update = uiBattleMenuUpdate,
|
||||
@@ -63,6 +65,14 @@ uielement_t UI_ELEMENTS[] = {
|
||||
.dispose = uiBackpackDispose
|
||||
},
|
||||
|
||||
{
|
||||
.init = uiSettingsInit,
|
||||
.update = uiSettingsUpdate,
|
||||
.draw = uiSettingsDraw,
|
||||
.dispose = uiSettingsDispose
|
||||
},
|
||||
|
||||
// Text stuffs
|
||||
{
|
||||
.init = uiConfirmInit,
|
||||
.draw = uiConfirmDraw,
|
||||
|
||||
Reference in New Issue
Block a user