diff --git a/archive/rpg/rpg.c b/archive/rpg/rpg.c index ead5c870..653b36fe 100644 --- a/archive/rpg/rpg.c +++ b/archive/rpg/rpg.c @@ -41,9 +41,7 @@ errorret_t rpgInit(void) { errorret_t rpgUpdate(void) { #if TIME_FIXED == 0 - if(TIME.dynamicUpdate) { - errorOk(); - } + if(TIME.dynamicUpdate) errorOk(); #endif // TODO: Do not update if the scene is not the map scene? diff --git a/src/dusk/display/screen/screen.c b/src/dusk/display/screen/screen.c index 3f5ee708..9e2e7d10 100644 --- a/src/dusk/display/screen/screen.c +++ b/src/dusk/display/screen/screen.c @@ -53,6 +53,10 @@ errorret_t screenBind() { SCREEN.width = frameBufferGetWidth(FRAMEBUFFER_BOUND); SCREEN.height = frameBufferGetHeight(FRAMEBUFFER_BOUND); SCREEN.aspect = frameBufferGetAspect(FRAMEBUFFER_BOUND); + SCREEN.scanX = 0; + SCREEN.scanY = 0; + SCREEN.scanWidth = SCREEN.width; + SCREEN.scanHeight = SCREEN.height; // No needd for a framebuffer. #ifdef DUSK_DISPLAY_SIZE_DYNAMIC @@ -69,6 +73,10 @@ errorret_t screenBind() { SCREEN.width = SCREEN.fixedSize.width; SCREEN.height = SCREEN.fixedSize.height; SCREEN.aspect = (float_t)SCREEN.width / (float_t)SCREEN.height; + SCREEN.scanX = 0; + SCREEN.scanY = 0; + SCREEN.scanWidth = SCREEN.width; + SCREEN.scanHeight = SCREEN.height; if(SCREEN.framebufferReady) { // Is current framebuffer the correct size? @@ -106,6 +114,10 @@ errorret_t screenBind() { SCREEN.width = fbWidth; SCREEN.height = fbHeight; SCREEN.aspect = (float_t)SCREEN.width / (float_t)SCREEN.height; + SCREEN.scanX = 0; + SCREEN.scanY = 0; + SCREEN.scanWidth = SCREEN.width; + SCREEN.scanHeight = SCREEN.height; if(SCREEN.framebufferReady) { errorChain(frameBufferDispose(&SCREEN.framebuffer)); @@ -136,6 +148,10 @@ errorret_t screenBind() { SCREEN.width = newFbWidth; SCREEN.height = newFbHeight; SCREEN.aspect = curFbAspect; + SCREEN.scanX = 0; + SCREEN.scanY = 0; + SCREEN.scanWidth = SCREEN.width; + SCREEN.scanHeight = SCREEN.height; errorChain(frameBufferBind(&SCREEN.framebuffer)); errorOk(); } @@ -152,6 +168,10 @@ errorret_t screenBind() { SCREEN.width = newFbWidth; SCREEN.height = newFbHeight; SCREEN.aspect = (float_t)SCREEN.width / (float_t)SCREEN.height; + SCREEN.scanX = 0; + SCREEN.scanY = 0; + SCREEN.scanWidth = SCREEN.width; + SCREEN.scanHeight = SCREEN.height; SCREEN.framebufferReady = true; // Bind FB @@ -171,6 +191,10 @@ errorret_t screenBind() { SCREEN.width = newFbWidth; SCREEN.height = newFbHeight; SCREEN.aspect = (float_t)SCREEN.width / (float_t)SCREEN.height; + SCREEN.scanX = 0; + SCREEN.scanY = 0; + SCREEN.scanWidth = SCREEN.width; + SCREEN.scanHeight = SCREEN.height; if(fbWidth == newFbWidth && fbHeight == newFbHeight) { // No need to use framebuffer. @@ -217,6 +241,10 @@ errorret_t screenBind() { SCREEN.width = newFbWidth; SCREEN.height = newFbHeight; SCREEN.aspect = (float_t)SCREEN.width / (float_t)SCREEN.height; + SCREEN.scanX = 0; + SCREEN.scanY = 0; + SCREEN.scanWidth = SCREEN.width; + SCREEN.scanHeight = SCREEN.height; if(fbWidth == newFbWidth && fbHeight == newFbHeight) { // No need to use framebuffer. @@ -258,6 +286,10 @@ errorret_t screenBind() { float_t fbAspect = fbWidth / fbHeight; SCREEN.width = (int32_t)floorf(SCREEN.height * fbAspect); SCREEN.aspect = (float_t)SCREEN.width / (float_t)SCREEN.height; + SCREEN.scanX = 0; + SCREEN.scanY = 0; + SCREEN.scanWidth = SCREEN.width; + SCREEN.scanHeight = SCREEN.height; break; } diff --git a/src/dusk/display/screen/screen.h b/src/dusk/display/screen/screen.h index de69e7af..bf3a26a6 100644 --- a/src/dusk/display/screen/screen.h +++ b/src/dusk/display/screen/screen.h @@ -44,6 +44,14 @@ typedef struct { int32_t width; int32_t height; float_t aspect; + + // Overscan-safe area; defaults to full viewport each frame. + // Platforms with TV overscan set these after screenBind(). + int32_t scanX; + int32_t scanY; + int32_t scanWidth; + int32_t scanHeight; + color_t background; #ifdef DUSK_DISPLAY_SIZE_DYNAMIC diff --git a/src/dusk/rpg/entity/CMakeLists.txt b/src/dusk/rpg/entity/CMakeLists.txt index f6e4cda5..a254c108 100644 --- a/src/dusk/rpg/entity/CMakeLists.txt +++ b/src/dusk/rpg/entity/CMakeLists.txt @@ -8,7 +8,8 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME} PUBLIC entity.c entityanim.c + entitydir.c + entityinteract.c npc.c player.c - entitydir.c ) \ No newline at end of file diff --git a/src/dusk/rpg/entity/entity.c b/src/dusk/rpg/entity/entity.c index 98052149..274ac576 100644 --- a/src/dusk/rpg/entity/entity.c +++ b/src/dusk/rpg/entity/entity.c @@ -49,13 +49,27 @@ void entityUpdate(entity_t *entity) { } } +bool_t entityCanTurn(entity_t *entity) { + return entity->animation == ENTITY_ANIM_IDLE; +} + +bool_t entityCanWalk(entity_t *entity) { + return entity->animation == ENTITY_ANIM_IDLE; +} + +bool_t entityCanRun(entity_t *entity) { + return entity->animation == ENTITY_ANIM_IDLE; +} + void entityTurn(entity_t *entity, const entitydir_t direction) { + if(!entityCanTurn(entity)) return; entity->direction = direction; entity->animation = ENTITY_ANIM_TURN; entity->animTime = ENTITY_ANIM_TURN_DURATION; } void entityWalk(entity_t *entity, const entitydir_t direction) { + if(!entityCanWalk(entity)) return; // TODO: Animation, delay, etc. entity->direction = direction; @@ -172,6 +186,15 @@ void entityWalk(entity_t *entity, const entitydir_t direction) { } } +void entityRun(entity_t *entity, const entitydir_t direction) { + if(!entityCanRun(entity)) return; + entityWalk(entity, direction); + if(entity->animation == ENTITY_ANIM_WALK) { + entity->animation = ENTITY_ANIM_RUN; + entity->animTime = ENTITY_ANIM_RUN_DURATION; + } +} + entity_t * entityGetAt(const worldpos_t position) { entity_t *ent = ENTITIES; do { diff --git a/src/dusk/rpg/entity/entity.h b/src/dusk/rpg/entity/entity.h index e6a93b5c..6d6a566a 100644 --- a/src/dusk/rpg/entity/entity.h +++ b/src/dusk/rpg/entity/entity.h @@ -8,6 +8,7 @@ #pragma once #include "entitydir.h" #include "entityanim.h" +#include "entityinteract.h" #include "entitytype.h" #include "npc.h" @@ -21,11 +22,13 @@ typedef struct entity_s { // Movement entitydir_t direction; worldpos_t position; - tilepos_t subPosition; worldpos_t lastPosition; + vec3 renderPosition; entityanim_t animation; float_t animTime; + + entityinteract_t interact; } entity_t; extern entity_t ENTITIES[ENTITY_COUNT]; @@ -45,9 +48,33 @@ void entityInit(entity_t *entity, const entitytype_t type); */ void entityUpdate(entity_t *entity); +/** + * Returns true if the entity is in a state where it can turn. + * + * @param entity Pointer to the entity to check. + * @returns True if the entity can turn. + */ +bool_t entityCanTurn(entity_t *entity); + +/** + * Returns true if the entity is in a state where it can walk. + * + * @param entity Pointer to the entity to check. + * @returns True if the entity can walk. + */ +bool_t entityCanWalk(entity_t *entity); + +/** + * Returns true if the entity is in a state where it can run. + * + * @param entity Pointer to the entity to check. + * @returns True if the entity can run. + */ +bool_t entityCanRun(entity_t *entity); + /** * Turn an entity to face a new direction. - * + * * @param entity Pointer to the entity to turn. * @param direction The direction to face. */ @@ -55,12 +82,20 @@ void entityTurn(entity_t *entity, const entitydir_t direction); /** * Make an entity walk in a direction. - * + * * @param entity Pointer to the entity to make walk. * @param direction The direction to walk in. */ void entityWalk(entity_t *entity, const entitydir_t direction); +/** + * Make an entity run in a direction. + * + * @param entity Pointer to the entity to make run. + * @param direction The direction to run in. + */ +void entityRun(entity_t *entity, const entitydir_t direction); + /** * Gets the entity at a specific world position. * diff --git a/src/dusk/rpg/entity/entityanim.c b/src/dusk/rpg/entity/entityanim.c index d5024815..8882a222 100644 --- a/src/dusk/rpg/entity/entityanim.c +++ b/src/dusk/rpg/entity/entityanim.c @@ -9,11 +9,33 @@ #include "time/time.h" void entityAnimUpdate(entity_t *entity) { - if(entity->animation == ENTITY_ANIM_IDLE) return; + if(entity->animation != ENTITY_ANIM_IDLE) { + entity->animTime -= TIME.delta; + if(entity->animTime <= 0) { + entity->animation = ENTITY_ANIM_IDLE; + entity->animTime = 0; + } + } - entity->animTime -= TIME.delta; - if(entity->animTime <= 0) { - entity->animation = ENTITY_ANIM_IDLE; - entity->animTime = 0; + if( + entity->animation == ENTITY_ANIM_WALK || + entity->animation == ENTITY_ANIM_RUN + ) { + float_t duration = entity->animation == ENTITY_ANIM_WALK ? + ENTITY_ANIM_WALK_DURATION : ENTITY_ANIM_RUN_DURATION; + float_t t = 1.0f - (entity->animTime / duration); + entity->renderPosition[0] = (float_t)entity->lastPosition.x + t * ( + (float_t)entity->position.x - (float_t)entity->lastPosition.x + ); + entity->renderPosition[1] = (float_t)entity->lastPosition.y + t * ( + (float_t)entity->position.y - (float_t)entity->lastPosition.y + ); + entity->renderPosition[2] = (float_t)entity->lastPosition.z + t * ( + (float_t)entity->position.z - (float_t)entity->lastPosition.z + ); + } else { + entity->renderPosition[0] = (float_t)entity->position.x; + entity->renderPosition[1] = (float_t)entity->position.y; + entity->renderPosition[2] = (float_t)entity->position.z; } } \ No newline at end of file diff --git a/src/dusk/rpg/entity/entityanim.h b/src/dusk/rpg/entity/entityanim.h index 9fb8d9ea..ccd425e6 100644 --- a/src/dusk/rpg/entity/entityanim.h +++ b/src/dusk/rpg/entity/entityanim.h @@ -10,6 +10,7 @@ #define ENTITY_ANIM_TURN_DURATION 0.06f #define ENTITY_ANIM_WALK_DURATION 0.1f +#define ENTITY_ANIM_RUN_DURATION 0.05f typedef struct entity_s entity_t; @@ -17,6 +18,7 @@ typedef enum { ENTITY_ANIM_IDLE, ENTITY_ANIM_TURN, ENTITY_ANIM_WALK, + ENTITY_ANIM_RUN, } entityanim_t; /** diff --git a/src/dusk/rpg/entity/entityinteract.c b/src/dusk/rpg/entity/entityinteract.c new file mode 100644 index 00000000..d3b3ca7f --- /dev/null +++ b/src/dusk/rpg/entity/entityinteract.c @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "entity.h" +#include "assert/assert.h" +#include "console/console.h" +#include "rpg/cutscene/cutscenesystem.h" + +void entityInteractWith(entity_t *player, entity_t *target) { + assertNotNull(player, "Player entity pointer cannot be NULL"); + assertNotNull(target, "Target entity pointer cannot be NULL"); + + switch(target->interact.type) { + case ENTITY_INTERACT_CUTSCENE: + assertNotNull( + target->interact.data.cutscene, + "Interact cutscene pointer cannot be NULL" + ); + cutsceneSystemStartCutscene(target->interact.data.cutscene); + return; + + case ENTITY_INTERACT_PRINT: + consolePrint(target->interact.data.message); + return; + + case ENTITY_INTERACT_NULL: + break; + + default: + assertUnreachable("Unknown entity interact type"); + break; + } + + if(ENTITY_CALLBACKS[target->type].interact == NULL) return; + ENTITY_CALLBACKS[target->type].interact(player, target); +} diff --git a/src/dusk/rpg/entity/entityinteract.h b/src/dusk/rpg/entity/entityinteract.h new file mode 100644 index 00000000..27a1efd6 --- /dev/null +++ b/src/dusk/rpg/entity/entityinteract.h @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "dusk.h" +#include "rpg/cutscene/cutscene.h" + +typedef struct entity_s entity_t; + +/** + * Describes the type of interaction an entity supports. + */ +typedef enum { + ENTITY_INTERACT_NULL = 0, + ENTITY_INTERACT_CUTSCENE, + ENTITY_INTERACT_PRINT, + ENTITY_INTERACT_COUNT +} entityinteracttype_t; + +/** + * Per-type data for an entity's interact component. + */ +typedef union { + const cutscene_t *cutscene; + char_t message[32]; +} entityinteractdata_t; + +/** + * Interact component attached to any entity that can be interacted with. + * Set type to ENTITY_INTERACT_NULL to mark the entity as non-interactable. + */ +typedef struct { + entityinteracttype_t type; + entityinteractdata_t data; +} entityinteract_t; + +/** + * Attempts to interact with the target entity on behalf of the player. + * Dispatches via the interact component; falls back to the entity type + * callback if no component is set. + * + * @param player Pointer to the player entity. + * @param target Pointer to the entity to interact with. + */ +void entityInteractWith(entity_t *player, entity_t *target); diff --git a/src/dusk/rpg/entity/player.c b/src/dusk/rpg/entity/player.c index cf33d562..b8f6bead 100644 --- a/src/dusk/rpg/entity/player.c +++ b/src/dusk/rpg/entity/player.c @@ -26,11 +26,13 @@ void playerInput(entity_t *entity) { return entityTurn(entity, dirMap->direction); } while((++dirMap)->action != 0xFF); - // Walk + // Walk / Run + bool_t running = inputIsDown(INPUT_ACTION_CANCEL); dirMap = PLAYER_INPUT_DIR_MAP; do { if(!inputIsDown(dirMap->action)) continue; if(entity->direction != dirMap->direction) continue; + if(running) return entityRun(entity, dirMap->direction); return entityWalk(entity, dirMap->direction); } while((++dirMap)->action != 0xFF); @@ -45,10 +47,9 @@ void playerInput(entity_t *entity) { z = entity->position.z; } - entity_t *interact = entityGetAt((worldpos_t){ x, y, z }); - if(interact != NULL && ENTITY_CALLBACKS[interact->type].interact != NULL) { - if(ENTITY_CALLBACKS[interact->type].interact(entity, interact)) return; - } + entity_t *target = entityGetAt((worldpos_t){ x, y, z }); + if(target == NULL) return; + entityInteractWith(entity, target); } } \ No newline at end of file diff --git a/src/dusk/rpg/overworld/worldpos.h b/src/dusk/rpg/overworld/worldpos.h index 87559cf1..8dae69f4 100644 --- a/src/dusk/rpg/overworld/worldpos.h +++ b/src/dusk/rpg/overworld/worldpos.h @@ -8,9 +8,6 @@ #pragma once #include "dusk.h" -#define TILE_POS_MIN -128 -#define TILE_POS_MAX 127 - #define CHUNK_WIDTH 16 #define CHUNK_HEIGHT CHUNK_WIDTH #define CHUNK_DEPTH 8 @@ -32,8 +29,6 @@ typedef uint32_t chunktileindex_t; typedef int32_t worldunits_t; typedef int32_t chunkunits_t; -typedef int8_t tileunit_t; - typedef struct worldpos_s { worldunit_t x, y, z; } worldpos_t; @@ -42,10 +37,6 @@ typedef struct chunkpos_t { chunkunit_t x, y, z; } chunkpos_t; -typedef struct tilepos_s { - tileunit_t x, y, z; -} tilepos_t; - /** * Compares two world positions for equality. * diff --git a/src/dusk/rpg/rpg.c b/src/dusk/rpg/rpg.c index 776f07fd..e4f95b00 100644 --- a/src/dusk/rpg/rpg.c +++ b/src/dusk/rpg/rpg.c @@ -13,6 +13,7 @@ #include "rpgcamera.h" #include "rpgtextbox.h" #include "util/memory.h" +#include "util/string.h" #include "assert/assert.h" errorret_t rpgInit(void) { @@ -37,6 +38,13 @@ errorret_t rpgInit(void) { RPG_CAMERA.mode = RPG_CAMERA_MODE_FOLLOW_ENTITY; RPG_CAMERA.followEntity.followEntityId = ent->id; + uint8_t npcIndex = entityGetAvailable(); + entity_t *npc = &ENTITIES[npcIndex]; + entityInit(npc, ENTITY_TYPE_NPC); + npc->position = (worldpos_t){ 3, 3, 0 }; + npc->interact.type = ENTITY_INTERACT_PRINT; + stringCopy(npc->interact.data.message, "hello world", 32); + // All Good! errorOk(); } diff --git a/src/dusk/rpg/rpgcamera.c b/src/dusk/rpg/rpgcamera.c index 0ab0c39e..89058643 100644 --- a/src/dusk/rpg/rpgcamera.c +++ b/src/dusk/rpg/rpgcamera.c @@ -19,17 +19,20 @@ void rpgCameraInit(void) { memoryZero(&RPG_CAMERA, sizeof(rpgcamera_t)); } -worldpos_t rpgCameraGetPosition(void) { +void rpgCameraGetPosition(vec3 out) { switch(RPG_CAMERA.mode) { case RPG_CAMERA_MODE_FREE: - return RPG_CAMERA.free; + glm_vec3_copy(RPG_CAMERA.free, out); + return; case RPG_CAMERA_MODE_FOLLOW_ENTITY: { entity_t *entity = &ENTITIES[RPG_CAMERA.followEntity.followEntityId]; if(entity->type == ENTITY_TYPE_NULL) { - return (worldpos_t){ 0, 0, 0 }; + glm_vec3_zero(out); + return; } - return entity->position; + glm_vec3_copy(entity->renderPosition, out); + return; } default: @@ -39,9 +42,15 @@ worldpos_t rpgCameraGetPosition(void) { errorret_t rpgCameraUpdate(void) { if(!mapIsLoaded()) errorOk(); - + + vec3 pos; + rpgCameraGetPosition(pos); + worldpos_t worldPos = { + (worldunit_t)pos[0], + (worldunit_t)pos[1], + (worldunit_t)pos[2] + }; chunkpos_t chunkPos; - worldpos_t worldPos = rpgCameraGetPosition(); worldPosToChunkPos(&worldPos, &chunkPos); errorChain(mapPositionSet((chunkpos_t){ diff --git a/src/dusk/rpg/rpgcamera.h b/src/dusk/rpg/rpgcamera.h index 824ca8c7..15b234a3 100644 --- a/src/dusk/rpg/rpgcamera.h +++ b/src/dusk/rpg/rpgcamera.h @@ -18,8 +18,8 @@ typedef struct { rpgcameramode_t mode; union { - worldpos_t free; - + vec3 free; + struct { uint8_t followEntityId; } followEntity; @@ -37,10 +37,10 @@ void rpgCameraInit(void); /** * Gets the RPG camera's position. - * - * @return The RPG camera's position. + * + * @param out Output vec3 filled with the camera world position. */ -worldpos_t rpgCameraGetPosition(void); +void rpgCameraGetPosition(vec3 out); /** * Updates the RPG camera. diff --git a/src/dusk/scene/overworld/sceneoverworld.c b/src/dusk/scene/overworld/sceneoverworld.c index 6ec815c9..feca011c 100644 --- a/src/dusk/scene/overworld/sceneoverworld.c +++ b/src/dusk/scene/overworld/sceneoverworld.c @@ -61,14 +61,10 @@ errorret_t sceneOverworldRender(scenedata_t *sceneData) { float_t pixelsPerUnit = 16.0f; float_t worldH = (float)SCREEN.height / pixelsPerUnit; float_t z = (worldH * 0.5f) / tanf(fov * 0.5f); - worldpos_t worldPos = rpgCameraGetPosition(); + vec3 worldPosVec; + rpgCameraGetPosition(worldPosVec); float_t offset = -16.0f; - vec3 worldPosVec = { - worldPos.x, - worldPos.y, - worldPos.z - }; glm_vec3_add(worldPosVec, (vec3){ 0.5f, 0.5f, 0.5f }, worldPosVec); glm_lookat( @@ -119,14 +115,8 @@ errorret_t sceneOverworldRender(scenedata_t *sceneData) { entity_t *ent = &ENTITIES[i]; if(ent->type == ENTITY_TYPE_NULL) continue; - vec3 position = { - ent->position.x + ((float_t)ent->subPosition.x / TILE_POS_MAX), - ent->position.y + ((float_t)ent->subPosition.y / TILE_POS_MAX), - ent->position.z + ((float_t)ent->subPosition.z / TILE_POS_MAX) + 0.01f - }; - - glm_vec3_copy(position, sprites[spriteCount].min); - glm_vec3_copy(position, sprites[spriteCount].max); + glm_vec3_copy(ent->renderPosition, sprites[spriteCount].min); + glm_vec3_copy(ent->renderPosition, sprites[spriteCount].max); glm_vec3_add( sprites[spriteCount].max, (vec3){ 1, 1, 0 }, diff --git a/src/dusk/scene/scene.c b/src/dusk/scene/scene.c index 7e530daa..6d934f09 100644 --- a/src/dusk/scene/scene.c +++ b/src/dusk/scene/scene.c @@ -44,9 +44,7 @@ errorret_t sceneUpdate(void) { } #if DUSK_TIME_DYNAMIC - if(TIME.dynamicUpdate) { - errorOk(); - } + if(TIME.dynamicUpdate) errorOk(); #endif if( diff --git a/src/dusk/ui/uifps.c b/src/dusk/ui/uifps.c index 0edf851c..901e3b09 100644 --- a/src/dusk/ui/uifps.c +++ b/src/dusk/ui/uifps.c @@ -51,7 +51,8 @@ errorret_t uiFPSDraw() { } errorChain(textDraw( - 0, 0, + (float_t)SCREEN.scanX, + (float_t)SCREEN.scanY, fpsText, textColor, &FONT_DEFAULT )); @@ -60,8 +61,8 @@ errorret_t uiFPSDraw() { int32_t versionWidth, versionHeight; textMeasure(ENGINE.version, &FONT_DEFAULT, &versionWidth, &versionHeight); errorChain(textDraw( - (float_t)(SCREEN.width - versionWidth), - (float_t)(SCREEN.height - versionHeight), + (float_t)(SCREEN.scanX + SCREEN.scanWidth - versionWidth), + (float_t)(SCREEN.scanY + SCREEN.scanHeight - versionHeight), ENGINE.version, color(255, 255, 255, 128), &FONT_DEFAULT diff --git a/src/dusk/ui/uiloading.c b/src/dusk/ui/uiloading.c index ecf0b768..89b04309 100644 --- a/src/dusk/ui/uiloading.c +++ b/src/dusk/ui/uiloading.c @@ -52,8 +52,10 @@ errorret_t uiLoadingDraw(void) { int32_t textW, textH; textMeasure(UI_LOADING_TEXT, &FONT_DEFAULT, &textW, &textH); - float_t x = (float_t)SCREEN.width - (float_t)textW - UI_LOADING_MARGIN; - float_t y = (float_t)SCREEN.height - (float_t)textH - UI_LOADING_MARGIN; + float_t x = (float_t)(SCREEN.scanX + SCREEN.scanWidth) - + (float_t)textW - UI_LOADING_MARGIN; + float_t y = (float_t)(SCREEN.scanY + SCREEN.scanHeight) - + (float_t)textH - UI_LOADING_MARGIN; color_t color = COLOR_WHITE; color.a = (uint8_t)(alpha * 255.0f); diff --git a/src/dusk/ui/uitextbox.c b/src/dusk/ui/uitextbox.c index aa032803..487c1e9a 100644 --- a/src/dusk/ui/uitextbox.c +++ b/src/dusk/ui/uitextbox.c @@ -32,9 +32,10 @@ errorret_t uiTextboxInit(void) { (float_t)(UI_TEXTBOX_LINES_PER_PAGE_MAX - 1) * UI_TEXTBOX_LINE_SPACING + 2.0f * fontH ); - UI_TEXTBOX.x = 10.0f; - UI_TEXTBOX.y = (float_t)SCREEN.height - tbHeight - 10.0f; - UI_TEXTBOX.width = (float_t)SCREEN.width - 20.0f; + UI_TEXTBOX.x = (float_t)SCREEN.scanX + 10.0f; + UI_TEXTBOX.y = (float_t)(SCREEN.scanY + SCREEN.scanHeight) - + tbHeight - 10.0f; + UI_TEXTBOX.width = (float_t)SCREEN.scanWidth - 20.0f; UI_TEXTBOX.height = tbHeight; UI_TEXTBOX.frame.tileset.columns = 3;