diff --git a/assets/testmap.json b/assets/testmap.json index 50cf12fd..ebb8c854 100644 --- a/assets/testmap.json +++ b/assets/testmap.json @@ -26,7 +26,9 @@ { "type": 2, "x": 3, - "y": 3 + "y": 3, + "name": "Bob", + "text": "Hello, I am Bob." }, { "type": 3, diff --git a/src/dawn/asset/assetjson.c b/src/dawn/asset/assetjson.c index 7e949992..e8806c53 100644 --- a/src/dawn/asset/assetjson.c +++ b/src/dawn/asset/assetjson.c @@ -13,7 +13,8 @@ size_t assetJsonParse(const char_t *json, assetjson_t **out) { // We only expect whitespace or EOF here char_t c; - do { + size_t len = strlen(json); + while(offset <= len) { c = json[offset]; if(c == '\0') break; if(c == ' ' || c == '\t' || c == '\n' || c == '\r') { @@ -21,7 +22,9 @@ size_t assetJsonParse(const char_t *json, assetjson_t **out) { continue; } assertUnreachable("Unexpected character found after JSON data."); - } while(true); + } + assertTrue(c == '\0', "Unexpected character found after JSON data."); + assertTrue(offset == len, "Unexpected character found after JSON data."); return offset; } diff --git a/src/dawn/asset/assetmap.c b/src/dawn/asset/assetmap.c index 2be5abfc..0979a6c8 100644 --- a/src/dawn/asset/assetmap.c +++ b/src/dawn/asset/assetmap.c @@ -21,6 +21,7 @@ void assetMapLoad( size_t length = assetGetSize(); char_t *buffer = malloc(sizeof(char_t) * (length + 1)); size_t read = assetRead((uint8_t*)buffer, length); + buffer[length] = '\0'; assertTrue(read == length, "assetMapLoad: Failed to read map data!"); assetClose(); @@ -96,9 +97,30 @@ void assetMapLoad( entityInit(ent, type, map); entityPositionSet(ent, x, y); + assetjson_t *val; switch(type) { + case ENTITY_TYPE_NPC: + val = assetJsonGetObjectValue(jEnt, "name"); + if(val != NULL) { + assertTrue( + val->type == ASSET_JSON_DATA_TYPE_STRING, + "assetMapLoad: NPC name is not a string!" + ); + npcNameSet(&ent->npc, val->string); + } + + val = assetJsonGetObjectValue(jEnt, "text"); + if(val != NULL) { + assertTrue( + val->type == ASSET_JSON_DATA_TYPE_STRING, + "assetMapLoad: NPC text is not a string!" + ); + npcTextSet(&ent->npc, val->string); + } + break; + case ENTITY_TYPE_SIGN: - assetjson_t *val = assetJsonGetObjectValue(jEnt, "text"); + val = assetJsonGetObjectValue(jEnt, "text"); if(val != NULL) { assertTrue( val->type == ASSET_JSON_DATA_TYPE_STRING, diff --git a/src/dawn/rpg/entity/CMakeLists.txt b/src/dawn/rpg/entity/CMakeLists.txt index c93c0864..3b6a59eb 100644 --- a/src/dawn/rpg/entity/CMakeLists.txt +++ b/src/dawn/rpg/entity/CMakeLists.txt @@ -13,4 +13,5 @@ target_sources(${DAWN_TARGET_NAME} player.c sign.c interact.c + npc.c ) \ No newline at end of file diff --git a/src/dawn/rpg/entity/entity.c b/src/dawn/rpg/entity/entity.c index c236630b..82dc48a8 100644 --- a/src/dawn/rpg/entity/entity.c +++ b/src/dawn/rpg/entity/entity.c @@ -29,6 +29,14 @@ void entityInit( assertUnreachable("Should not be initializing a NULL entity."); break; + case ENTITY_TYPE_NPC: + npcInit(&entity->npc); + break; + + case ENTITY_TYPE_SIGN: + signInit(&entity->sign); + break; + case ENTITY_TYPE_PLAYER: playerInit(entity); break; diff --git a/src/dawn/rpg/entity/entity.h b/src/dawn/rpg/entity/entity.h index a10b647c..0d3b7dbe 100644 --- a/src/dawn/rpg/entity/entity.h +++ b/src/dawn/rpg/entity/entity.h @@ -9,6 +9,7 @@ #include "player.h" #include "sign.h" #include "entitydirection.h" +#include "npc.h" typedef struct _map_t map_t; @@ -46,6 +47,7 @@ typedef struct _entity_t { // Type data union { player_t player; + npc_t npc; sign_t sign; }; } entity_t; diff --git a/src/dawn/rpg/entity/interact.c b/src/dawn/rpg/entity/interact.c index b7e0972a..f69bd3cb 100644 --- a/src/dawn/rpg/entity/interact.c +++ b/src/dawn/rpg/entity/interact.c @@ -16,10 +16,20 @@ void entityInteractEntity( assertNotNull(target, "entityInteractEntity: Target is NULL!"); switch(target->type) { + case ENTITY_TYPE_NPC: + source->state = ENTITY_STATE_TALKING; + target->state = ENTITY_STATE_TALKING; + target->direction = entityDirectionLookAt( + target->x, target->y, + source->x, source->y + ); + textboxSetText(target->npc.name, target->npc.text); + return; + case ENTITY_TYPE_SIGN: source->state = ENTITY_STATE_TALKING; target->state = ENTITY_STATE_TALKING; - textboxSetText(NULL, target->sign.text); + textboxSetText("Sign", target->sign.text); return; default: diff --git a/src/dawn/rpg/entity/npc.c b/src/dawn/rpg/entity/npc.c new file mode 100644 index 00000000..b395ba5c --- /dev/null +++ b/src/dawn/rpg/entity/npc.c @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2024 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "npc.h" +#include "assert/assert.h" + +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, TEXTBOX_TITLE_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, TEXTBOX_TEXT_MAX); +} \ No newline at end of file diff --git a/src/dawn/rpg/entity/npc.h b/src/dawn/rpg/entity/npc.h new file mode 100644 index 00000000..5df8bcbc --- /dev/null +++ b/src/dawn/rpg/entity/npc.h @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2024 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "ui/textbox.h" + +typedef struct { + char_t name[TEXTBOX_TITLE_MAX+1]; + char_t text[TEXTBOX_TEXT_MAX+1]; +} npc_t; + +/** + * Initializes an NPC. + * + * @param npc NPC to initialize. + */ +void npcInit(npc_t *npc); + +/** + * Sets the name of an NPC. + * + * @param npc NPC to set name for. + * @param name Name to set. + */ +void npcNameSet(npc_t *npc, const char_t *name); + +/** + * Sets the text of an NPC. + * + * @param npc NPC to set text for. + * @param text Text to set. + */ +void npcTextSet(npc_t *npc, const char_t *text); \ No newline at end of file diff --git a/src/dawn/rpg/entity/sign.c b/src/dawn/rpg/entity/sign.c index de9585ba..6654e110 100644 --- a/src/dawn/rpg/entity/sign.c +++ b/src/dawn/rpg/entity/sign.c @@ -8,6 +8,11 @@ #include "sign.h" #include "assert/assert.h" +void signInit(sign_t *sign) { + assertNotNull(sign, "signInit: Sign is NULL!"); + sign->text[0] = '\0'; +} + void signTextSet(sign_t *sign, const char_t *text) { assertNotNull(sign, "signTextSet: Sign is NULL!"); assertNotNull(text, "signTextSet: Text is NULL!"); diff --git a/src/dawn/rpg/entity/sign.h b/src/dawn/rpg/entity/sign.h index 00cf44bc..0316b5c2 100644 --- a/src/dawn/rpg/entity/sign.h +++ b/src/dawn/rpg/entity/sign.h @@ -12,6 +12,13 @@ typedef struct { char_t text[TEXTBOX_TEXT_MAX + 1]; } sign_t; +/** + * Initializes a sign. + * + * @param sign Sign to initialize. + */ +void signInit(sign_t *sign); + /** * Sets the text of a sign. *