Example sign with conversation.

This commit is contained in:
2024-10-20 15:31:04 -07:00
parent a74f285cb2
commit b2a3ca4411
12 changed files with 143 additions and 67 deletions

View File

@ -21,7 +21,11 @@
"maps": {
"testmap": {
"bob": "Hello, I am Bob.",
"sign": "This is a sign."
"sign": "This is a sign.",
"sign2": {
"1": "This is another sign.",
"2": "It has two lines."
}
}
}
}

View File

@ -42,6 +42,15 @@
"y": 8,
"text": "maps.testmap.sign"
},
{
"type": 3,
"x": 2,
"y": 2,
"texts": [
"maps.testmap.sign2.1",
"maps.testmap.sign2.2"
]
},
{
"type": 4,
"x": 6,

View File

@ -53,7 +53,27 @@ void assetMapLoadEntity(
val->type == ASSET_JSON_DATA_TYPE_STRING,
"assetMapLoad: Sign text is not a string!"
);
signTextSet(&ent->sign, val->string);
signTextAppend(&ent->sign, val->string);
}
val = assetJsonGetObjectValue(jEnt, "texts");
if(val != NULL) {
assertTrue(
val->type == ASSET_JSON_DATA_TYPE_ARRAY,
"assetMapLoad: Sign texts is not an array!"
);
assertTrue(
val->array.length <= SIGN_TEXT_COUNT_MAX,
"assetMapLoad: Too many sign texts!"
);
for(int32_t i = 0; i < val->array.length; i++) {
assetjson_t *subVal = val->array.value[i];
assertTrue(
subVal->type == ASSET_JSON_DATA_TYPE_STRING,
"assetMapLoad: Sign text is not a string!"
);
signTextAppend(&ent->sign, subVal->string);
}
}
break;

View File

@ -46,7 +46,6 @@ void gameInit() {
gameupdateresult_t gameUpdate(const float_t delta) {
timeUpdate(delta);
inputUpdate();
conversationUpdate();
switch(GAME.state) {
case GAME_STATE_INITIAL:

View File

@ -10,10 +10,13 @@
#include "input.h"
#include "ui/textbox.h"
#include "ui/testmenu.h"
#include "rpg/conversation/conversation.h"
void gameStateOverworldUpdate() {
textboxUpdate();
testMenuUpdate();
conversationUpdate();
if(GAME.currentMap) mapUpdate(GAME.currentMap);
if(inputWasPressed(INPUT_BIND_PAUSE)) GAME.state = GAME_STATE_PAUSED;
}

View File

@ -30,8 +30,10 @@ void conversationUpdate() {
if(CONVERSATION.init == NULL || CONVERSATION.update == NULL) return;
uint16_t ret;
bool_t recheck = true;
// Init or update.
while(recheck) {
switch(CONVERSATION.index) {
case CONVERSATION_NOT_INITIALIZED:
CONVERSATION.index = 0;
@ -45,6 +47,7 @@ void conversationUpdate() {
break;
}
// Check ret value and update conversation.
switch(ret) {
case CONVERSATION_NEXT:
@ -55,7 +58,8 @@ void conversationUpdate() {
break;
case CONVERSATION_CONTINUE:
return;
recheck = false;
break;
case CONVERSATION_RESTART:
CONVERSATION.index = 0;
@ -64,15 +68,18 @@ void conversationUpdate() {
case CONVERSATION_INVALID:
assertUnreachable("Invalid converstaion retval");
recheck = false;
break;
case CONVERSATION_DONE:
CONVERSATION.init = NULL;
CONVERSATION.update = NULL;
recheck = false;
break;
default:
CONVERSATION.index = ret;
break;
}
}
}

View File

@ -21,12 +21,12 @@ uint16_t conversationInteractEntityInit(
entity_t *e = (entity_t*)convo->data.entityInteract.entity;
switch(e->type) {
case ENTITY_TYPE_SIGN:
textboxSetText("entities.sign.name", e->sign.text);
return 0;
textboxSetText("entities.sign.name", e->sign.texts[i]);
return i;
case ENTITY_TYPE_NPC:
textboxSetText(e->npc.name, e->npc.text);
return 0;
textboxSetText(e->npc.text.name, e->npc.text.text);
return i;
default:
assertUnreachable("Invalid entity type for conversation.");
@ -38,6 +38,18 @@ uint16_t conversationInteractEntityUpdate(
conversation_t *convo,
const uint16_t i
) {
assertNotNull(convo, "Conversation is NULL!");
assertNotNull(convo->data.entityInteract.entity, "Conversation user is NULL!");
entity_t *e = (entity_t*)convo->data.entityInteract.entity;
switch(e->type) {
case ENTITY_TYPE_SIGN:
if(textboxIsOpen()) return CONVERSATION_CONTINUE;
if(i == SIGN_TEXT_COUNT_MAX-1) return CONVERSATION_DONE;
if(e->sign.texts[i+1][0] == '\0') return CONVERSATION_DONE;
return CONVERSATION_NEXT;
default:
switch(i) {
case 0:
return textboxIsOpen() ? CONVERSATION_CONTINUE : CONVERSATION_DONE;
@ -45,4 +57,5 @@ uint16_t conversationInteractEntityUpdate(
default:
return CONVERSATION_INVALID;
}
}
}

View File

@ -33,6 +33,7 @@ void entityInteractEntity(
conversationInteractEntityUpdate,
(conversationdata_t){ .entityInteract = { .entity = target } }
);
source->state = ENTITY_STATE_TALKING;
return;
case ENTITY_TYPE_SIGN:
@ -41,6 +42,7 @@ void entityInteractEntity(
conversationInteractEntityUpdate,
(conversationdata_t){ .entityInteract = { .entity = target } }
);
source->state = ENTITY_STATE_TALKING;
return;
case ENTITY_TYPE_DOOR:

View File

@ -10,18 +10,16 @@
void npcInit(npc_t *npc) {
assertNotNull(npc, "npcInit: NPC is NULL!");
npc->name[0] = '\0';
npc->text[0] = '\0';
}
void npcNameSet(npc_t *npc, const char_t *name) {
assertNotNull(npc, "npcNameSet: NPC is NULL!");
assertNotNull(name, "npcNameSet: Name is NULL!");
strncpy(npc->name, name, LANGUAGE_STRING_KEY_LENGTH_MAX);
strncpy(npc->text.name, name, LANGUAGE_STRING_KEY_LENGTH_MAX);
}
void npcTextSet(npc_t *npc, const char_t *text) {
assertNotNull(npc, "npcTextSet: NPC is NULL!");
assertNotNull(text, "npcTextSet: Text is NULL!");
strncpy(npc->text, text, LANGUAGE_STRING_KEY_LENGTH_MAX);
strncpy(npc->text.text, text, LANGUAGE_STRING_KEY_LENGTH_MAX);
}

View File

@ -11,6 +11,15 @@
typedef struct {
char_t name[LANGUAGE_STRING_KEY_LENGTH_MAX+1];
char_t text[LANGUAGE_STRING_KEY_LENGTH_MAX+1];
} npctext_t;
typedef struct {
uint8_t nothing;
} npcconversation_t;
typedef union {
npctext_t text;
npcconversation_t conversation;
} npc_t;
/**

View File

@ -7,14 +7,24 @@
#include "sign.h"
#include "assert/assert.h"
#include "util/memory.h"
void signInit(sign_t *sign) {
assertNotNull(sign, "signInit: Sign is NULL!");
sign->text[0] = '\0';
memorySet(sign, 0, sizeof(sign_t));
}
void signTextSet(sign_t *sign, const char_t *text) {
assertNotNull(sign, "signTextSet: Sign is NULL!");
assertNotNull(text, "signTextSet: Text is NULL!");
strncpy(sign->text, text, LANGUAGE_STRING_KEY_LENGTH_MAX);
void signTextAppend(sign_t *sign, const char_t *text) {
assertNotNull(sign, "signConversationAppend: Sign is NULL!");
assertNotNull(text, "signConversationAppend: Text is NULL!");
// Find the first empty slot
for(int32_t i = 0; i < SIGN_TEXT_COUNT_MAX; i++) {
if(sign->texts[i][0] == '\0') {
strncpy(sign->texts[i], text, LANGUAGE_STRING_KEY_LENGTH_MAX);
return;
}
}
assertUnreachable("signConversationAppend: No empty slots found!");
}

View File

@ -8,8 +8,10 @@
#pragma once
#include "locale/language.h"
#define SIGN_TEXT_COUNT_MAX 32
typedef struct {
char_t text[LANGUAGE_STRING_KEY_LENGTH_MAX+1];
char_t texts[SIGN_TEXT_COUNT_MAX][LANGUAGE_STRING_KEY_LENGTH_MAX+1];
} sign_t;
/**
@ -20,9 +22,9 @@ typedef struct {
void signInit(sign_t *sign);
/**
* Sets the text of a sign.
* Appends text to the sign's conversation.
*
* @param sign Sign to set text for.
* @param text Text to set.
* @param sign Sign to append conversation to.
* @param text Text to append.
*/
void signTextSet(sign_t *sign, const char_t *text);
void signTextAppend(sign_t *sign, const char_t *text);