Example sign with conversation.
This commit is contained in:
@ -21,7 +21,11 @@
|
|||||||
"maps": {
|
"maps": {
|
||||||
"testmap": {
|
"testmap": {
|
||||||
"bob": "Hello, I am Bob.",
|
"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."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -42,6 +42,15 @@
|
|||||||
"y": 8,
|
"y": 8,
|
||||||
"text": "maps.testmap.sign"
|
"text": "maps.testmap.sign"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": 3,
|
||||||
|
"x": 2,
|
||||||
|
"y": 2,
|
||||||
|
"texts": [
|
||||||
|
"maps.testmap.sign2.1",
|
||||||
|
"maps.testmap.sign2.2"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": 4,
|
"type": 4,
|
||||||
"x": 6,
|
"x": 6,
|
||||||
|
@ -48,12 +48,32 @@ void assetMapLoadEntity(
|
|||||||
|
|
||||||
case ENTITY_TYPE_SIGN:
|
case ENTITY_TYPE_SIGN:
|
||||||
val = assetJsonGetObjectValue(jEnt, "text");
|
val = assetJsonGetObjectValue(jEnt, "text");
|
||||||
if(val != NULL) {
|
if(val != NULL) {
|
||||||
assertTrue(
|
assertTrue(
|
||||||
val->type == ASSET_JSON_DATA_TYPE_STRING,
|
val->type == ASSET_JSON_DATA_TYPE_STRING,
|
||||||
"assetMapLoad: Sign text is not a 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;
|
break;
|
||||||
|
|
||||||
|
@ -46,7 +46,6 @@ void gameInit() {
|
|||||||
gameupdateresult_t gameUpdate(const float_t delta) {
|
gameupdateresult_t gameUpdate(const float_t delta) {
|
||||||
timeUpdate(delta);
|
timeUpdate(delta);
|
||||||
inputUpdate();
|
inputUpdate();
|
||||||
conversationUpdate();
|
|
||||||
|
|
||||||
switch(GAME.state) {
|
switch(GAME.state) {
|
||||||
case GAME_STATE_INITIAL:
|
case GAME_STATE_INITIAL:
|
||||||
|
@ -10,10 +10,13 @@
|
|||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "ui/textbox.h"
|
#include "ui/textbox.h"
|
||||||
#include "ui/testmenu.h"
|
#include "ui/testmenu.h"
|
||||||
|
#include "rpg/conversation/conversation.h"
|
||||||
|
|
||||||
void gameStateOverworldUpdate() {
|
void gameStateOverworldUpdate() {
|
||||||
textboxUpdate();
|
textboxUpdate();
|
||||||
testMenuUpdate();
|
testMenuUpdate();
|
||||||
|
conversationUpdate();
|
||||||
|
|
||||||
if(GAME.currentMap) mapUpdate(GAME.currentMap);
|
if(GAME.currentMap) mapUpdate(GAME.currentMap);
|
||||||
if(inputWasPressed(INPUT_BIND_PAUSE)) GAME.state = GAME_STATE_PAUSED;
|
if(inputWasPressed(INPUT_BIND_PAUSE)) GAME.state = GAME_STATE_PAUSED;
|
||||||
}
|
}
|
@ -30,49 +30,56 @@ void conversationUpdate() {
|
|||||||
if(CONVERSATION.init == NULL || CONVERSATION.update == NULL) return;
|
if(CONVERSATION.init == NULL || CONVERSATION.update == NULL) return;
|
||||||
|
|
||||||
uint16_t ret;
|
uint16_t ret;
|
||||||
|
bool_t recheck = true;
|
||||||
|
|
||||||
// Init or update.
|
// Init or update.
|
||||||
switch(CONVERSATION.index) {
|
while(recheck) {
|
||||||
case CONVERSATION_NOT_INITIALIZED:
|
switch(CONVERSATION.index) {
|
||||||
CONVERSATION.index = 0;
|
case CONVERSATION_NOT_INITIALIZED:
|
||||||
ret = CONVERSATION.init(
|
CONVERSATION.index = 0;
|
||||||
&CONVERSATION, CONVERSATION.index
|
ret = CONVERSATION.init(
|
||||||
);
|
&CONVERSATION, CONVERSATION.index
|
||||||
break;
|
);
|
||||||
|
break;
|
||||||
default:
|
|
||||||
ret = CONVERSATION.update(&CONVERSATION, CONVERSATION.index);
|
default:
|
||||||
break;
|
ret = CONVERSATION.update(&CONVERSATION, CONVERSATION.index);
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Check ret value and update conversation.
|
|
||||||
switch(ret) {
|
|
||||||
case CONVERSATION_NEXT:
|
|
||||||
CONVERSATION.index++;
|
|
||||||
CONVERSATION.index = CONVERSATION.init(
|
|
||||||
&CONVERSATION, CONVERSATION.index
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CONVERSATION_CONTINUE:
|
|
||||||
return;
|
|
||||||
|
|
||||||
case CONVERSATION_RESTART:
|
|
||||||
CONVERSATION.index = 0;
|
|
||||||
CONVERSATION.init(&CONVERSATION, CONVERSATION.index);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CONVERSATION_INVALID:
|
|
||||||
assertUnreachable("Invalid converstaion retval");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CONVERSATION_DONE:
|
// Check ret value and update conversation.
|
||||||
CONVERSATION.init = NULL;
|
switch(ret) {
|
||||||
CONVERSATION.update = NULL;
|
case CONVERSATION_NEXT:
|
||||||
break;
|
CONVERSATION.index++;
|
||||||
|
CONVERSATION.index = CONVERSATION.init(
|
||||||
default:
|
&CONVERSATION, CONVERSATION.index
|
||||||
CONVERSATION.index = ret;
|
);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CONVERSATION_CONTINUE:
|
||||||
|
recheck = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONVERSATION_RESTART:
|
||||||
|
CONVERSATION.index = 0;
|
||||||
|
CONVERSATION.init(&CONVERSATION, CONVERSATION.index);
|
||||||
|
break;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -21,12 +21,12 @@ uint16_t conversationInteractEntityInit(
|
|||||||
entity_t *e = (entity_t*)convo->data.entityInteract.entity;
|
entity_t *e = (entity_t*)convo->data.entityInteract.entity;
|
||||||
switch(e->type) {
|
switch(e->type) {
|
||||||
case ENTITY_TYPE_SIGN:
|
case ENTITY_TYPE_SIGN:
|
||||||
textboxSetText("entities.sign.name", e->sign.text);
|
textboxSetText("entities.sign.name", e->sign.texts[i]);
|
||||||
return 0;
|
return i;
|
||||||
|
|
||||||
case ENTITY_TYPE_NPC:
|
case ENTITY_TYPE_NPC:
|
||||||
textboxSetText(e->npc.name, e->npc.text);
|
textboxSetText(e->npc.text.name, e->npc.text.text);
|
||||||
return 0;
|
return i;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assertUnreachable("Invalid entity type for conversation.");
|
assertUnreachable("Invalid entity type for conversation.");
|
||||||
@ -38,11 +38,24 @@ uint16_t conversationInteractEntityUpdate(
|
|||||||
conversation_t *convo,
|
conversation_t *convo,
|
||||||
const uint16_t i
|
const uint16_t i
|
||||||
) {
|
) {
|
||||||
switch(i) {
|
assertNotNull(convo, "Conversation is NULL!");
|
||||||
case 0:
|
assertNotNull(convo->data.entityInteract.entity, "Conversation user is NULL!");
|
||||||
return textboxIsOpen() ? CONVERSATION_CONTINUE : CONVERSATION_DONE;
|
|
||||||
|
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:
|
default:
|
||||||
return CONVERSATION_INVALID;
|
switch(i) {
|
||||||
|
case 0:
|
||||||
|
return textboxIsOpen() ? CONVERSATION_CONTINUE : CONVERSATION_DONE;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return CONVERSATION_INVALID;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -33,6 +33,7 @@ void entityInteractEntity(
|
|||||||
conversationInteractEntityUpdate,
|
conversationInteractEntityUpdate,
|
||||||
(conversationdata_t){ .entityInteract = { .entity = target } }
|
(conversationdata_t){ .entityInteract = { .entity = target } }
|
||||||
);
|
);
|
||||||
|
source->state = ENTITY_STATE_TALKING;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case ENTITY_TYPE_SIGN:
|
case ENTITY_TYPE_SIGN:
|
||||||
@ -41,6 +42,7 @@ void entityInteractEntity(
|
|||||||
conversationInteractEntityUpdate,
|
conversationInteractEntityUpdate,
|
||||||
(conversationdata_t){ .entityInteract = { .entity = target } }
|
(conversationdata_t){ .entityInteract = { .entity = target } }
|
||||||
);
|
);
|
||||||
|
source->state = ENTITY_STATE_TALKING;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case ENTITY_TYPE_DOOR:
|
case ENTITY_TYPE_DOOR:
|
||||||
|
@ -10,18 +10,16 @@
|
|||||||
|
|
||||||
void npcInit(npc_t *npc) {
|
void npcInit(npc_t *npc) {
|
||||||
assertNotNull(npc, "npcInit: NPC is NULL!");
|
assertNotNull(npc, "npcInit: NPC is NULL!");
|
||||||
npc->name[0] = '\0';
|
|
||||||
npc->text[0] = '\0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void npcNameSet(npc_t *npc, const char_t *name) {
|
void npcNameSet(npc_t *npc, const char_t *name) {
|
||||||
assertNotNull(npc, "npcNameSet: NPC is NULL!");
|
assertNotNull(npc, "npcNameSet: NPC is NULL!");
|
||||||
assertNotNull(name, "npcNameSet: Name 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) {
|
void npcTextSet(npc_t *npc, const char_t *text) {
|
||||||
assertNotNull(npc, "npcTextSet: NPC is NULL!");
|
assertNotNull(npc, "npcTextSet: NPC is NULL!");
|
||||||
assertNotNull(text, "npcTextSet: Text 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);
|
||||||
}
|
}
|
@ -11,6 +11,15 @@
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
char_t name[LANGUAGE_STRING_KEY_LENGTH_MAX+1];
|
char_t name[LANGUAGE_STRING_KEY_LENGTH_MAX+1];
|
||||||
char_t text[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;
|
} npc_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -7,14 +7,24 @@
|
|||||||
|
|
||||||
#include "sign.h"
|
#include "sign.h"
|
||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
|
#include "util/memory.h"
|
||||||
|
|
||||||
void signInit(sign_t *sign) {
|
void signInit(sign_t *sign) {
|
||||||
assertNotNull(sign, "signInit: Sign is NULL!");
|
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) {
|
void signTextAppend(sign_t *sign, const char_t *text) {
|
||||||
assertNotNull(sign, "signTextSet: Sign is NULL!");
|
assertNotNull(sign, "signConversationAppend: Sign is NULL!");
|
||||||
assertNotNull(text, "signTextSet: Text is NULL!");
|
assertNotNull(text, "signConversationAppend: Text is NULL!");
|
||||||
strncpy(sign->text, text, LANGUAGE_STRING_KEY_LENGTH_MAX);
|
|
||||||
|
// 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!");
|
||||||
}
|
}
|
@ -8,8 +8,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "locale/language.h"
|
#include "locale/language.h"
|
||||||
|
|
||||||
|
#define SIGN_TEXT_COUNT_MAX 32
|
||||||
|
|
||||||
typedef struct {
|
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;
|
} sign_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -20,9 +22,9 @@ typedef struct {
|
|||||||
void signInit(sign_t *sign);
|
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 sign Sign to append conversation to.
|
||||||
* @param text Text to set.
|
* @param text Text to append.
|
||||||
*/
|
*/
|
||||||
void signTextSet(sign_t *sign, const char_t *text);
|
void signTextAppend(sign_t *sign, const char_t *text);
|
Reference in New Issue
Block a user