Events base.
This commit is contained in:
@ -3,12 +3,11 @@
|
||||
"items": [
|
||||
{
|
||||
"type": "text",
|
||||
"texts": [
|
||||
"This is a bucket",
|
||||
"Dear God",
|
||||
"There's more!",
|
||||
"No!"
|
||||
]
|
||||
"text": "This is a bucket"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"text": "Dear God"
|
||||
}
|
||||
]
|
||||
}
|
@ -37,7 +37,7 @@
|
||||
"overworld.tsx"
|
||||
],
|
||||
"project": "map project.tiled-project",
|
||||
"property.type": "tileSolidType",
|
||||
"property.type": "string",
|
||||
"recentFiles": [
|
||||
"overworld.tsx",
|
||||
"map.tmj",
|
||||
|
@ -425,6 +425,11 @@
|
||||
{
|
||||
"id":13,
|
||||
"properties":[
|
||||
{
|
||||
"name":"interactEvent",
|
||||
"type":"string",
|
||||
"value":"test_event"
|
||||
},
|
||||
{
|
||||
"name":"interactText",
|
||||
"type":"string",
|
||||
@ -434,7 +439,7 @@
|
||||
"name":"interactType",
|
||||
"propertytype":"npcInteractType",
|
||||
"type":"string",
|
||||
"value":"NPC_INTERACT_TYPE_TEXT"
|
||||
"value":"NPC_INTERACT_TYPE_EVENT"
|
||||
}],
|
||||
"template":"templates\/NPC.tx",
|
||||
"x":6539.95833333333,
|
||||
|
@ -25,6 +25,7 @@ target_sources(${DUSK_TARGET_NAME}
|
||||
add_subdirectory(assert)
|
||||
add_subdirectory(display)
|
||||
add_subdirectory(entity)
|
||||
add_subdirectory(event)
|
||||
add_subdirectory(item)
|
||||
add_subdirectory(locale)
|
||||
add_subdirectory(physics)
|
||||
|
@ -37,41 +37,10 @@ void npcInteract(entity_t *player, entity_t *self) {
|
||||
break;
|
||||
|
||||
case NPC_INTERACT_TYPE_EVENT:
|
||||
eventSetActive(self->npc.eventData);
|
||||
break;
|
||||
|
||||
default:
|
||||
assertUnreachable("Unknown NPC interaction type");
|
||||
}
|
||||
|
||||
// uiTextboxSetText(
|
||||
// "Hello World how are you today? Hope things are going well for you! I am "
|
||||
// "having a great day, hope you are too. Did I ever tell you about the tragedy "
|
||||
// "of Darth Plagueis the Wise? He was a dark lord of the Sith, "
|
||||
// "so powerful and so wise he could use the Force to influence the midichlorians"
|
||||
// );
|
||||
// const char_t *name = "Dom";
|
||||
// const char_t *key = "name";
|
||||
// uint16_t len = languageFormat(
|
||||
// "test.npc.text",
|
||||
// NULL,
|
||||
// 0,
|
||||
// (const char_t *[]){ key },
|
||||
// (const char_t *[]){ name },
|
||||
// 1
|
||||
// );
|
||||
|
||||
// char_t *buffer = malloc(sizeof(char_t) + len + 1);
|
||||
// assertNotNull(buffer, "Failed to allocate buffer for NPC text");
|
||||
|
||||
// languageFormat(
|
||||
// "test.npc.text",
|
||||
// buffer,
|
||||
// len + 1,
|
||||
// (const char_t *[]){ key },
|
||||
// (const char_t *[]){ name },
|
||||
// 1
|
||||
// );
|
||||
|
||||
// uiTextboxSetText(buffer);
|
||||
// free(buffer);
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include "event/eventlist.h"
|
||||
|
||||
typedef struct _entity_t entity_t;
|
||||
|
||||
@ -15,7 +15,8 @@ typedef struct {
|
||||
npcinteracttype_t interactType;
|
||||
|
||||
union {
|
||||
char_t* text;
|
||||
const char_t* text;
|
||||
const eventdata_t *eventData;
|
||||
};
|
||||
} npc_t;
|
||||
|
||||
|
11
src/dusk/event/CMakeLists.txt
Normal file
11
src/dusk/event/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DUSK_TARGET_NAME}
|
||||
PRIVATE
|
||||
event.c
|
||||
eventtext.c
|
||||
)
|
@ -5,4 +5,69 @@
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "event.h"
|
||||
#include "event.h"
|
||||
#include "util/memory.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
eventcallback_t EVENT_CALLBACKS[] = {
|
||||
[EVENT_TYPE_NULL] = { NULL, NULL },
|
||||
[EVENT_TYPE_TEXT] = { eventTextStart, eventTextUpdate },
|
||||
};
|
||||
|
||||
event_t EVENT;
|
||||
|
||||
void eventInit() {
|
||||
memoryZero(&EVENT, sizeof(event_t));
|
||||
}
|
||||
|
||||
void eventUpdate() {
|
||||
if(EVENT.active == NULL) {
|
||||
return; // No active event to update
|
||||
}
|
||||
|
||||
const eventitem_t *item = &EVENT.active->items[EVENT.item];
|
||||
assertNotNull(
|
||||
EVENT_CALLBACKS[item->type].update,
|
||||
"Event type does not have an update callback"
|
||||
);
|
||||
|
||||
EVENT_CALLBACKS[item->type].update(item);
|
||||
}
|
||||
|
||||
void eventSetActive(const eventdata_t *event) {
|
||||
assertNotNull(event, "Event data cannot be NULL");
|
||||
assertTrue(
|
||||
event->itemCount <= EVENT_ITEM_COUNT_MAX,
|
||||
"Event count too high"
|
||||
);
|
||||
assertTrue(event->itemCount > 0, "Event must have at least one item");
|
||||
|
||||
EVENT.active = event;
|
||||
EVENT.item = 0;
|
||||
|
||||
const eventitem_t *firstItem = &EVENT.active->items[EVENT.item];
|
||||
|
||||
assertNotNull(
|
||||
EVENT_CALLBACKS[firstItem->type].start,
|
||||
"Event type does not have a start callback"
|
||||
);
|
||||
EVENT_CALLBACKS[firstItem->type].start(firstItem);
|
||||
}
|
||||
|
||||
void eventNext() {
|
||||
assertNotNull(EVENT.active, "No active event to proceed with");
|
||||
assertTrue(EVENT.item < EVENT.active->itemCount, "No more items in the event");
|
||||
|
||||
EVENT.item++;
|
||||
if (EVENT.item >= EVENT.active->itemCount) {
|
||||
EVENT.active = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
const eventitem_t *nextItem = &EVENT.active->items[EVENT.item];
|
||||
assertNotNull(
|
||||
EVENT_CALLBACKS[nextItem->type].start,
|
||||
"Event type does not have a start callback"
|
||||
);
|
||||
EVENT_CALLBACKS[nextItem->type].start(nextItem);
|
||||
}
|
@ -6,24 +6,41 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "eventtext.h"
|
||||
|
||||
typedef enum {
|
||||
EVENT_TYPE_NULL = 0,
|
||||
EVENT_TYPE_TEXT,
|
||||
} eventtype_t;
|
||||
|
||||
typedef struct _eventitem_t {
|
||||
eventtype_t type;
|
||||
|
||||
union {
|
||||
eventtext_t texts;
|
||||
};
|
||||
} eventitem_t;
|
||||
|
||||
#define EVENT_ITEM_COUNT_MAX 32
|
||||
#include "eventdata.h"
|
||||
|
||||
typedef struct {
|
||||
uint8_t itemCount;
|
||||
eventitem_t items[EVENT_ITEM_COUNT_MAX];
|
||||
} event_t;
|
||||
eventdata_t data;
|
||||
const eventdata_t *active;
|
||||
uint8_t item;
|
||||
} event_t;
|
||||
|
||||
typedef struct {
|
||||
void (*start)(const eventitem_t *item);
|
||||
void (*update)(const eventitem_t *item);
|
||||
} eventcallback_t;
|
||||
|
||||
extern eventcallback_t EVENT_CALLBACKS[EVENT_TYPE_COUNT];
|
||||
extern event_t EVENT;
|
||||
|
||||
/**
|
||||
* Initializes the event system.
|
||||
*/
|
||||
void eventInit();
|
||||
|
||||
/**
|
||||
* Updates the active event.
|
||||
*/
|
||||
void eventUpdate();
|
||||
|
||||
/**
|
||||
* Sets the active event.
|
||||
*
|
||||
* @param event The event to set as active.
|
||||
*/
|
||||
void eventSetActive(const eventdata_t *eventData);
|
||||
|
||||
/**
|
||||
* Goes to the next item in the active event. Only meant to be called by
|
||||
* event items.
|
||||
*/
|
||||
void eventNext();
|
14
src/dusk/event/eventdata.h
Normal file
14
src/dusk/event/eventdata.h
Normal file
@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "eventitem.h"
|
||||
|
||||
typedef struct {
|
||||
uint8_t itemCount;
|
||||
eventitem_t items[EVENT_ITEM_COUNT_MAX];
|
||||
} eventdata_t;
|
26
src/dusk/event/eventitem.h
Normal file
26
src/dusk/event/eventitem.h
Normal file
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma ocne
|
||||
#include "eventtext.h"
|
||||
|
||||
typedef enum {
|
||||
EVENT_TYPE_NULL = 0,
|
||||
EVENT_TYPE_TEXT,
|
||||
} eventtype_t;
|
||||
|
||||
#define EVENT_TYPE_COUNT 2
|
||||
|
||||
typedef struct _eventitem_t {
|
||||
eventtype_t type;
|
||||
|
||||
union {
|
||||
eventtext_t text;
|
||||
};
|
||||
} eventitem_t;
|
||||
|
||||
#define EVENT_ITEM_COUNT_MAX 32
|
26
src/dusk/event/eventtext.c
Normal file
26
src/dusk/event/eventtext.c
Normal file
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "event.h"
|
||||
#include "ui/uitextbox.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
void eventTextStart(const eventitem_t *item) {
|
||||
assertNotNull(item, "Event item cannot be NULL");
|
||||
assertTrue(item->type == EVENT_TYPE_TEXT, "Event item must be of type TEXT");
|
||||
assertNotNull(item->text, "Event item must have at least one text");
|
||||
uiTextboxSetText(item->text);
|
||||
}
|
||||
|
||||
void eventTextUpdate(const eventitem_t *item) {
|
||||
assertNotNull(item, "Event item cannot be NULL");
|
||||
assertTrue(item->type == EVENT_TYPE_TEXT, "Event item must be of type TEXT");
|
||||
|
||||
if(!UI_TEXTBOX.visible) {
|
||||
eventNext();
|
||||
}
|
||||
}
|
@ -12,4 +12,25 @@ typedef struct _eventitem_t eventitem_t;
|
||||
|
||||
#define EVENT_TEXT_STRING_COUNT_MAX 8
|
||||
|
||||
typedef const char_t* eventtext_t[EVENT_TEXT_STRING_COUNT_MAX];
|
||||
typedef const char_t* eventtext_t;
|
||||
|
||||
/**
|
||||
* Starts the text event for the given item.
|
||||
*
|
||||
* @param item The event item to start.
|
||||
*/
|
||||
void eventTextStart(const eventitem_t *item);
|
||||
|
||||
/**
|
||||
* Updates the text event for the given item.
|
||||
*
|
||||
* @param item The event item to update.
|
||||
*/
|
||||
void eventTextUpdate(const eventitem_t *item);
|
||||
|
||||
/**
|
||||
* Query whether the text event is done or not.
|
||||
*
|
||||
* @param item The event item to check.
|
||||
*/
|
||||
bool_t eventTextIsDone(const eventitem_t *item);
|
@ -11,13 +11,14 @@
|
||||
#include "display/scene.h"
|
||||
#include "world/overworld.h"
|
||||
#include "input.h"
|
||||
|
||||
#include "event/event.h"
|
||||
#include "ui/uitextbox.h"
|
||||
|
||||
// Press F5 to compile and run the compiled game.gb in the Emulicous Emulator/Debugger
|
||||
void main(void) {
|
||||
renderInit();
|
||||
inputInit();
|
||||
eventInit();
|
||||
uiTextboxInit();
|
||||
|
||||
overworldInit();
|
||||
@ -30,6 +31,7 @@ void main(void) {
|
||||
|
||||
overworldUpdate();
|
||||
uiTextboxUpdate();
|
||||
eventUpdate();
|
||||
|
||||
// Update input for next frame.
|
||||
inputUpdate();
|
||||
|
@ -188,5 +188,4 @@ void uiTextboxSetText(const char_t *text) {
|
||||
|
||||
assertUnreachable("Code should not reach here, all cases handled.");
|
||||
}
|
||||
printf("test");
|
||||
}
|
@ -55,8 +55,8 @@ for jsonFile in jsonFiles:
|
||||
f.write(f"// Generated event header for {jsonFile}\n")
|
||||
f.write(f"// Generated at {now}\n")
|
||||
f.write("#pragma once\n\n")
|
||||
f.write("#include \"event/event.h\"\n\n")
|
||||
f.write(f"static const event_t EVENT_{key.upper()} = {{\n")
|
||||
f.write("#include \"event/eventdata.h\"\n\n")
|
||||
f.write(f"static const eventdata_t EVENT_{key.upper()} = {{\n")
|
||||
f.write(f" .itemCount = {len(data['items'])},\n")
|
||||
f.write(f" .items = {{\n")
|
||||
for i, item in enumerate(data['items']):
|
||||
@ -69,14 +69,11 @@ for jsonFile in jsonFiles:
|
||||
|
||||
# Text(s) Type
|
||||
if itemType == 'text':
|
||||
if 'texts' not in item or not isinstance(item['texts'], list) or len(item['texts']) == 0:
|
||||
print(f"Error: Item {i} in '{jsonFile}' of type 'text' does not contain 'texts' field.")
|
||||
if 'text' not in item:
|
||||
print(f"Error: Item {i} in '{jsonFile}' of type 'text' does not contain 'text' field.")
|
||||
sys.exit(1)
|
||||
f.write(f" .type = EVENT_TYPE_TEXT,\n")
|
||||
f.write(f" .texts = {{\n")
|
||||
for text in item['texts']:
|
||||
f.write(f" \"{text}\",\n")
|
||||
f.write(f" }},\n")
|
||||
f.write(f" .text = \"{item['text']}\",\n")
|
||||
|
||||
|
||||
else:
|
||||
@ -87,4 +84,20 @@ for jsonFile in jsonFiles:
|
||||
f.write(f" }},\n")
|
||||
f.write(f"}};\n\n")
|
||||
|
||||
eventFiles.append(key)
|
||||
eventFiles.append(key)
|
||||
|
||||
# Write the event list header
|
||||
eventListFile = os.path.join(outputDir, "eventlist.h")
|
||||
with open(eventListFile, 'w', encoding='utf-8') as f:
|
||||
f.write(f"// Generated event list header\n")
|
||||
f.write(f"// Generated at {now}\n")
|
||||
f.write("#pragma once\n\n")
|
||||
f.write("#include \"event/event.h\"\n")
|
||||
for event in eventFiles:
|
||||
f.write(f"#include \"event/{event}.h\"\n")
|
||||
f.write("\n")
|
||||
f.write(f"#define EVENT_LIST_COUNT {len(eventFiles)}\n\n")
|
||||
f.write("static const eventdata_t* EVENT_LIST[EVENT_LIST_COUNT] = {\n")
|
||||
for event in eventFiles:
|
||||
f.write(f" &EVENT_{event.upper()},\n")
|
||||
f.write("};\n\n")
|
@ -30,11 +30,35 @@ def parseEntity(obj, chunkData):
|
||||
obj['dir'] = 'ENTITY_DIR_SOUTH'
|
||||
obj['type'] = entType
|
||||
|
||||
def getProperty(propName):
|
||||
for prop in obj['properties']:
|
||||
if prop['name'] == propName:
|
||||
return prop['value']
|
||||
return None
|
||||
|
||||
# Handle per-type properties
|
||||
if entType == 'ENTITY_TYPE_NPC':
|
||||
interactType = getProperty('interactType')
|
||||
if interactType is None:
|
||||
print(f"NPC entity missing 'interactType' property: {obj['id']}")
|
||||
sys.exit(1)
|
||||
|
||||
obj['data'] = {}
|
||||
obj['data']['npc'] = {}
|
||||
obj['data']['npc']['interactType'] = 'NPC_INTERACT_TYPE_TEXT'
|
||||
obj['data']['npc']['text'] = '"test.npc.text"'
|
||||
obj['data']['npc']['interactType'] = interactType
|
||||
|
||||
if interactType == 'NPC_INTERACT_TYPE_TEXT':
|
||||
text = getProperty('interactText')
|
||||
if text is None:
|
||||
print(f"NPC entity missing 'interactText' property: {obj['id']}")
|
||||
sys.exit(1)
|
||||
obj['data']['npc']['text'] = text
|
||||
|
||||
elif interactType == 'NPC_INTERACT_TYPE_EVENT':
|
||||
event = getProperty('interactEvent')
|
||||
if event is None:
|
||||
print(f"NPC entity missing 'interactEvent' property: {obj['id']}")
|
||||
sys.exit(1)
|
||||
obj['data']['npc']['eventData'] = f'&EVENT_{event.upper()}'
|
||||
|
||||
return obj
|
Reference in New Issue
Block a user