Chain cutscenes and rendering text.
This commit is contained in:
@@ -6,6 +6,8 @@
|
|||||||
# Sources
|
# Sources
|
||||||
target_sources(microrpg PRIVATE
|
target_sources(microrpg PRIVATE
|
||||||
cutscene.c
|
cutscene.c
|
||||||
cutsceneitem.c
|
|
||||||
cutscenemode.c
|
cutscenemode.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Subdirectories
|
||||||
|
add_subdirectory(item)
|
||||||
@@ -22,9 +22,7 @@ void cutsceneStart(const cutscene_t *cutscene) {
|
|||||||
void cutsceneTick() {
|
void cutsceneTick() {
|
||||||
if(GAME.cutsceneSystem.cutscene == NULL) return;
|
if(GAME.cutsceneSystem.cutscene == NULL) return;
|
||||||
|
|
||||||
const cutsceneitem_t *item = (
|
const cutsceneitem_t *item = cutsceneGetCurrentItem();
|
||||||
&GAME.cutsceneSystem.cutscene->items[GAME.cutsceneSystem.currentItem]
|
|
||||||
);
|
|
||||||
cutsceneItemTick(item, &GAME.cutsceneSystem.data);
|
cutsceneItemTick(item, &GAME.cutsceneSystem.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,16 +32,23 @@ void cutsceneNext() {
|
|||||||
GAME.cutsceneSystem.currentItem++;
|
GAME.cutsceneSystem.currentItem++;
|
||||||
|
|
||||||
// End of the cutscene?
|
// End of the cutscene?
|
||||||
if(GAME.cutsceneSystem.currentItem >= GAME.cutsceneSystem.cutscene->itemCount) {
|
if(
|
||||||
|
GAME.cutsceneSystem.currentItem >= GAME.cutsceneSystem.cutscene->itemCount
|
||||||
|
) {
|
||||||
GAME.cutsceneSystem.cutscene = NULL;
|
GAME.cutsceneSystem.cutscene = NULL;
|
||||||
GAME.cutsceneSystem.currentItem = 0;
|
GAME.cutsceneSystem.currentItem = 0xFF;
|
||||||
GAME.cutsceneSystem.mode = CUTSCENE_MODE_NONE;
|
GAME.cutsceneSystem.mode = CUTSCENE_MODE_NONE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start item.
|
// Start item.
|
||||||
const cutsceneitem_t *item = (
|
const cutsceneitem_t *item = cutsceneGetCurrentItem();
|
||||||
&GAME.cutsceneSystem.cutscene->items[GAME.cutsceneSystem.currentItem]
|
memset(&GAME.cutsceneSystem.data, 0, sizeof(GAME.cutsceneSystem.data));
|
||||||
);
|
|
||||||
cutsceneItemStart(item, &GAME.cutsceneSystem.data);
|
cutsceneItemStart(item, &GAME.cutsceneSystem.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cutsceneitem_t * cutsceneGetCurrentItem() {
|
||||||
|
if(GAME.cutsceneSystem.cutscene == NULL) return NULL;
|
||||||
|
|
||||||
|
return &GAME.cutsceneSystem.cutscene->items[GAME.cutsceneSystem.currentItem];
|
||||||
|
}
|
||||||
@@ -6,10 +6,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "cutsceneitem.h"
|
#include "cutscene/item/cutsceneitem.h"
|
||||||
#include "cutscenemode.h"
|
#include "cutscene/cutscenemode.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct cutscene_s {
|
||||||
const cutsceneitem_t *items;
|
const cutsceneitem_t *items;
|
||||||
uint8_t itemCount;
|
uint8_t itemCount;
|
||||||
} cutscene_t;
|
} cutscene_t;
|
||||||
@@ -44,3 +44,10 @@ void cutsceneNext();
|
|||||||
* Update the cutscene system for one tick.
|
* Update the cutscene system for one tick.
|
||||||
*/
|
*/
|
||||||
void cutsceneTick();
|
void cutsceneTick();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current cutscene item.
|
||||||
|
*
|
||||||
|
* @return Pointer to the current cutscene item.
|
||||||
|
*/
|
||||||
|
const cutsceneitem_t * cutsceneGetCurrentItem();
|
||||||
9
src/cutscene/item/CMakeLists.txt
Executable file
9
src/cutscene/item/CMakeLists.txt
Executable file
@@ -0,0 +1,9 @@
|
|||||||
|
# Copyright (c) 2025 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
# Sources
|
||||||
|
target_sources(microrpg PRIVATE
|
||||||
|
cutsceneitem.c
|
||||||
|
)
|
||||||
@@ -8,4 +8,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "microrpg.h"
|
#include "microrpg.h"
|
||||||
|
|
||||||
typedef const char *cutscenetext_t;
|
typedef struct cutscene_s cutscene_t;
|
||||||
|
|
||||||
|
typedef cutscene_t* cutscenecutscene_t;
|
||||||
@@ -5,13 +5,16 @@
|
|||||||
* https://opensource.org/licenses/MIT
|
* https://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "cutsceneitem.h"
|
#include "cutscene/cutscene.h"
|
||||||
#include "cutscene.h"
|
#include "input.h"
|
||||||
|
|
||||||
void cutsceneItemStart(const cutsceneitem_t *item, cutsceneitemdata_t *data) {
|
void cutsceneItemStart(const cutsceneitem_t *item, cutsceneitemdata_t *data) {
|
||||||
switch(item->type) {
|
switch(item->type) {
|
||||||
case CUTSCENE_ITEM_TEXT:
|
case CUTSCENE_ITEM_TEXT: {
|
||||||
|
strncpy(data->text.buffer, item->text, CUTSCENE_TEXT_BUFFER);
|
||||||
|
data->text.length = strlen(data->text.buffer);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case CUTSCENE_ITEM_WAIT:
|
case CUTSCENE_ITEM_WAIT:
|
||||||
data->wait = item->wait;
|
data->wait = item->wait;
|
||||||
@@ -21,6 +24,10 @@ void cutsceneItemStart(const cutsceneitem_t *item, cutsceneitemdata_t *data) {
|
|||||||
if(item->callback != NULL) item->callback();
|
if(item->callback != NULL) item->callback();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CUTSCENE_ITEM_CUTSCENE:
|
||||||
|
if(item->cutscene != NULL) cutsceneStart(item->cutscene);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -28,8 +35,15 @@ void cutsceneItemStart(const cutsceneitem_t *item, cutsceneitemdata_t *data) {
|
|||||||
|
|
||||||
void cutsceneItemTick(const cutsceneitem_t *item, cutsceneitemdata_t *data) {
|
void cutsceneItemTick(const cutsceneitem_t *item, cutsceneitemdata_t *data) {
|
||||||
switch(item->type) {
|
switch(item->type) {
|
||||||
case CUTSCENE_ITEM_TEXT:
|
// Scroll text, when finished scrolling, wait for A press.
|
||||||
|
case CUTSCENE_ITEM_TEXT: {
|
||||||
|
if(data->text.scroll < data->text.length) {
|
||||||
|
data->text.scroll++;
|
||||||
|
} else if(inputPressed(INPUT_ACTION_A)) {
|
||||||
|
cutsceneNext();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case CUTSCENE_ITEM_CALLBACK:
|
case CUTSCENE_ITEM_CALLBACK:
|
||||||
break;
|
break;
|
||||||
@@ -9,11 +9,13 @@
|
|||||||
#include "cutscenewait.h"
|
#include "cutscenewait.h"
|
||||||
#include "cutscenecallback.h"
|
#include "cutscenecallback.h"
|
||||||
#include "cutscenetext.h"
|
#include "cutscenetext.h"
|
||||||
|
#include "cutscenecutscene.h"
|
||||||
|
|
||||||
#define CUTSCENE_ITEM_NULL 0
|
#define CUTSCENE_ITEM_NULL 0
|
||||||
#define CUTSCENE_ITEM_TEXT 1
|
#define CUTSCENE_ITEM_TEXT 1
|
||||||
#define CUTSCENE_ITEM_CALLBACK 2
|
#define CUTSCENE_ITEM_CALLBACK 2
|
||||||
#define CUTSCENE_ITEM_WAIT 3
|
#define CUTSCENE_ITEM_WAIT 3
|
||||||
|
#define CUTSCENE_ITEM_CUTSCENE 4
|
||||||
|
|
||||||
typedef struct cutsceneitem_s {
|
typedef struct cutsceneitem_s {
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
@@ -23,10 +25,12 @@ typedef struct cutsceneitem_s {
|
|||||||
cutscenetext_t text;
|
cutscenetext_t text;
|
||||||
cutscenecallback_t callback;
|
cutscenecallback_t callback;
|
||||||
cutscenewait_t wait;
|
cutscenewait_t wait;
|
||||||
|
cutscenecutscene_t cutscene;
|
||||||
};
|
};
|
||||||
} cutsceneitem_t;
|
} cutsceneitem_t;
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
|
cutscenetextdata_t text;
|
||||||
cutscenewaitdata_t wait;
|
cutscenewaitdata_t wait;
|
||||||
} cutsceneitemdata_t;
|
} cutsceneitemdata_t;
|
||||||
|
|
||||||
19
src/cutscene/item/cutscenetext.h
Normal file
19
src/cutscene/item/cutscenetext.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "microrpg.h"
|
||||||
|
|
||||||
|
#define CUTSCENE_TEXT_BUFFER 256
|
||||||
|
|
||||||
|
typedef const char_t *cutscenetext_t;
|
||||||
|
|
||||||
|
typedef struct cutscenetextdata_s {
|
||||||
|
char_t buffer[CUTSCENE_TEXT_BUFFER];
|
||||||
|
uint8_t length;
|
||||||
|
uint8_t scroll;
|
||||||
|
} cutscenetextdata_t;
|
||||||
@@ -8,14 +8,23 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "cutscene/cutscene.h"
|
#include "cutscene/cutscene.h"
|
||||||
|
|
||||||
static void testCutsceneTest() {
|
static const cutsceneitem_t TEST_CUTSCENE_ONE_ITEMS[] = {
|
||||||
}
|
{ .type = CUTSCENE_ITEM_TEXT, .text = "This is a test cutscene." },
|
||||||
|
{ .type = CUTSCENE_ITEM_WAIT, .wait = 2 * GAME_TIME_TICKS_PER_SECOND },
|
||||||
|
{ .type = CUTSCENE_ITEM_TEXT, .text = "It has multiple lines of text.\nAnd waits in between." },
|
||||||
|
};
|
||||||
|
|
||||||
static const cutsceneitem_t TEST_CUTSCENE_ITEMS[] = {
|
static const cutscene_t TEST_CUTSCENE_ONE = {
|
||||||
{ .type = CUTSCENE_ITEM_WAIT, .wait = 1 * GAME_TIME_TICKS_PER_SECOND }
|
.items = TEST_CUTSCENE_ONE_ITEMS,
|
||||||
|
.itemCount = sizeof(TEST_CUTSCENE_ONE_ITEMS) / sizeof(cutsceneitem_t)
|
||||||
|
};
|
||||||
|
|
||||||
|
static const cutsceneitem_t TEST_CUTSCENE_TWO_ITEMS[] = {
|
||||||
|
{ .type = CUTSCENE_ITEM_WAIT, .wait = 1 * GAME_TIME_TICKS_PER_SECOND },
|
||||||
|
{ .type = CUTSCENE_ITEM_CUTSCENE, .cutscene = &TEST_CUTSCENE_ONE },
|
||||||
};
|
};
|
||||||
|
|
||||||
static const cutscene_t TEST_CUTSCENE = {
|
static const cutscene_t TEST_CUTSCENE = {
|
||||||
.items = TEST_CUTSCENE_ITEMS,
|
.items = TEST_CUTSCENE_TWO_ITEMS,
|
||||||
.itemCount = sizeof(TEST_CUTSCENE_ITEMS) / sizeof(cutsceneitem_t)
|
.itemCount = sizeof(TEST_CUTSCENE_TWO_ITEMS) / sizeof(cutsceneitem_t)
|
||||||
};
|
};
|
||||||
14
src/game.c
14
src/game.c
@@ -16,18 +16,20 @@ void gameInit() {
|
|||||||
|
|
||||||
cutsceneInit();
|
cutsceneInit();
|
||||||
|
|
||||||
entityInit(&GAME.player, ENTITY_TYPE_PLAYER);
|
entity_t *ent = &GAME.player;
|
||||||
|
entityInit(ent, ENTITY_TYPE_PLAYER);
|
||||||
|
|
||||||
entityInit(&GAME.overworld.map.entities[0], ENTITY_TYPE_SIGN);
|
ent = &GAME.overworld.map.entities[0];
|
||||||
GAME.overworld.map.entities[0].position.x = 5;
|
entityInit(ent, ENTITY_TYPE_SIGN);
|
||||||
GAME.overworld.map.entities[0].position.y = 5;
|
ent->position.x = 5;
|
||||||
GAME.overworld.map.entities[0].sign.cutscene = &TEST_CUTSCENE;
|
ent->position.y = 5;
|
||||||
|
ent->sign.cutscene = &TEST_CUTSCENE;
|
||||||
|
|
||||||
GAME.scene = SCENE_OVERWORLD;
|
GAME.scene = SCENE_OVERWORLD;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gameTick() {
|
void gameTick() {
|
||||||
gameTimeTick(&GAME.time);
|
gameTimeTick(&GAME.time);
|
||||||
cutsceneTick();
|
|
||||||
sceneTick();
|
sceneTick();
|
||||||
|
cutsceneTick();
|
||||||
}
|
}
|
||||||
@@ -3,16 +3,16 @@
|
|||||||
# This software is released under the MIT License.
|
# This software is released under the MIT License.
|
||||||
# https://opensource.org/licenses/MIT
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
if(NOT DEFINED PLATFORM)
|
if(NOT DEFINED RPG_PLATFORM)
|
||||||
set(PLATFORM "raylib" CACHE STRING "Select the platform to build for (options: raylib, term, tty)")
|
set(RPG_PLATFORM "raylib" CACHE STRING "Select the platform to build for")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(PLATFORM STREQUAL "tty")
|
if(RPG_PLATFORM STREQUAL "tty")
|
||||||
add_subdirectory(term)
|
add_subdirectory(term)
|
||||||
add_subdirectory(tty)
|
add_subdirectory(tty)
|
||||||
elseif(PLATFORM STREQUAL "raylib")
|
elseif(RPG_PLATFORM STREQUAL "raylib")
|
||||||
add_subdirectory(raylib)
|
add_subdirectory(raylib)
|
||||||
add_subdirectory(term)
|
add_subdirectory(term)
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "Unknown PLATFORM: ${PLATFORM}.")
|
message(FATAL_ERROR "Unknown RPG_PLATFORM: ${RPG_PLATFORM}.")
|
||||||
endif()
|
endif()
|
||||||
@@ -30,6 +30,9 @@ void termDrawOverworld(
|
|||||||
termDrawEntity(start, chars, colors, w, h);
|
termDrawEntity(start, chars, colors, w, h);
|
||||||
start++;
|
start++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draw UI
|
||||||
|
termDrawUI(chars, colors, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
void termDrawEntity(
|
void termDrawEntity(
|
||||||
@@ -69,3 +72,55 @@ void termDrawEntity(
|
|||||||
colors[index] = TERM_COLOR_YELLOW;
|
colors[index] = TERM_COLOR_YELLOW;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void termDrawUI(
|
||||||
|
char_t *chars,
|
||||||
|
termcolor_t *colors,
|
||||||
|
const int32_t w,
|
||||||
|
const int32_t h
|
||||||
|
) {
|
||||||
|
// Textbox.
|
||||||
|
const cutsceneitem_t *csItem = cutsceneGetCurrentItem();
|
||||||
|
if(csItem != NULL && csItem->type == CUTSCENE_ITEM_TEXT) {
|
||||||
|
// Draw box
|
||||||
|
int32_t boxHeight = 5;
|
||||||
|
for(int32_t y = h - boxHeight; y < h; y++) {
|
||||||
|
for(int32_t x = 0; x < w; x++) {
|
||||||
|
size_t index = y * w + x;
|
||||||
|
if(y == h - boxHeight || y == h - 1) {
|
||||||
|
chars[index] = '-';
|
||||||
|
} else if(x == 0 || x == w - 1) {
|
||||||
|
chars[index] = '|';
|
||||||
|
} else {
|
||||||
|
chars[index] = ' ';
|
||||||
|
}
|
||||||
|
colors[index] = TERM_COLOR_WHITE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw text
|
||||||
|
cutscenetextdata_t *data = &GAME.cutsceneSystem.data.text;
|
||||||
|
int boxRows = boxHeight - 2;
|
||||||
|
int boxCols = w - 2;
|
||||||
|
int row = 0, col = 0;
|
||||||
|
for(uint8_t i = 0; i < data->scroll; i++) {
|
||||||
|
char ch = data->buffer[i];
|
||||||
|
if(ch == '\n') {
|
||||||
|
row++;
|
||||||
|
col = 0;
|
||||||
|
if(row >= boxRows) break;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(col >= boxCols) {
|
||||||
|
row++;
|
||||||
|
col = 0;
|
||||||
|
if(row >= boxRows) break;
|
||||||
|
}
|
||||||
|
size_t boxIndex = (h - boxHeight + 1 + row) * w + 1 + col;
|
||||||
|
if(boxIndex >= (size_t)(h * w)) break;
|
||||||
|
chars[boxIndex] = ch;
|
||||||
|
colors[boxIndex] = TERM_COLOR_WHITE;
|
||||||
|
col++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -40,3 +40,18 @@ void termDrawEntity(
|
|||||||
const int32_t w,
|
const int32_t w,
|
||||||
const int32_t h
|
const int32_t h
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw the UI to the terminal.
|
||||||
|
*
|
||||||
|
* @param chars Buffer of characters to write to.
|
||||||
|
* @param colors Buffer of colors to write to.
|
||||||
|
* @param w Width of the terminal in characters.
|
||||||
|
* @param h Height of the terminal in characters.
|
||||||
|
*/
|
||||||
|
void termDrawUI(
|
||||||
|
char_t *chars,
|
||||||
|
termcolor_t *colors,
|
||||||
|
const int32_t w,
|
||||||
|
const int32_t h
|
||||||
|
);
|
||||||
0
tools/embed-file/CMakeLists.txt
Normal file
0
tools/embed-file/CMakeLists.txt
Normal file
Reference in New Issue
Block a user