diff --git a/assets/games/liminal/test.xml b/assets/games/liminal/test.xml
new file mode 100644
index 00000000..910d4cd0
--- /dev/null
+++ b/assets/games/liminal/test.xml
@@ -0,0 +1,9 @@
+
+
+
+ Hi, I'm Craig.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/dawn/games/vn/components/VNManager.cpp b/src/dawn/games/vn/components/VNManager.cpp
index 9f6a655f..169cd0f5 100644
--- a/src/dawn/games/vn/components/VNManager.cpp
+++ b/src/dawn/games/vn/components/VNManager.cpp
@@ -23,6 +23,15 @@ void VNManager::setEvent(VNEvent *event) {
this->currentEvent = event;
}
+void VNManager::setFlag(std::string key, std::string value) {
+ this->flags[key] = value;
+}
+
+std::string VNManager::getFlag(std::string key) {
+ if(this->flags.find(key) == this->flags.end()) return "";
+ return this->flags[key];
+}
+
void VNManager::nextEvent() {
if(this->currentEvent == nullptr) return;
auto old = this->currentEvent;
diff --git a/src/dawn/games/vn/components/VNManager.hpp b/src/dawn/games/vn/components/VNManager.hpp
index 5f6d5842..0485fea8 100644
--- a/src/dawn/games/vn/components/VNManager.hpp
+++ b/src/dawn/games/vn/components/VNManager.hpp
@@ -13,6 +13,7 @@ namespace Dawn {
protected:
std::vector events;
VNEvent *currentEvent = nullptr;
+ std::map flags;
public:
/**
@@ -46,6 +47,22 @@ namespace Dawn {
*/
void nextEvent();
+ /**
+ * Sets a flag for the visual novel.
+ *
+ * @param key Key of the flag.
+ * @param value Value of the flag.
+ */
+ void setFlag(std::string key, std::string value);
+
+ /**
+ * Gets a flag for the visual novel.
+ *
+ * @param key Key of the flag.
+ * @return Value of the flag, or an empty string if it doesn't exist.
+ */
+ std::string getFlag(std::string key);
+
void onStart() override;
void onDispose() override;
diff --git a/src/dawn/games/vn/events/VNChoiceEvent.hpp b/src/dawn/games/vn/events/VNChoiceEvent.hpp
new file mode 100644
index 00000000..cc7a3899
--- /dev/null
+++ b/src/dawn/games/vn/events/VNChoiceEvent.hpp
@@ -0,0 +1,45 @@
+// Copyright (c) 2023 Dominic Masters
+//
+// This software is released under the MIT License.
+// https://opensource.org/licenses/MIT
+
+#pragma once
+#include "VNEvent.hpp"
+
+namespace Dawn {
+ class VNChoiceEvent : public VNEvent {
+ public:
+ std::string text;
+ std::string key;
+ std::map choices;
+ int32_t choice = 0;
+
+ protected:
+ void onStart() override {
+ choice = 0;
+
+ std::cout << "CHOICE: " << text << std::endl;
+ for(auto& choice : choices) {
+ std::cout << " " << choice.first << ": " << choice.second << std::endl;
+ }
+
+ useEvent([&](float_t delta) {
+ auto im = &getScene()->game->inputManager;
+ if(im->isPressed(INPUT_BIND_ACCEPT)) {
+ auto it = choices.begin();
+ std::advance(it, choice);
+ std::string choiceMade = it->first;
+ std::cout << "Choice made " << choiceMade << std::endl;
+ this->manager->setFlag(this->key, choiceMade);
+ this->next();
+ } else if(im->isPressed(INPUT_BIND_NEGATIVE_Y)) {
+ choice = mathClamp((choice - 1), 0, choices.size() - 1);
+ std::cout << "Current choice: state" << choice << std::endl;
+ } else if(im->isPressed(INPUT_BIND_POSITIVE_Y)) {
+ choice = mathClamp((choice + 1), 0, choices.size() - 1);
+ std::cout << "Current choice: state" << choice << std::endl;
+ }
+ }, getScene()->eventSceneUpdate);
+ }
+ };
+}
\ No newline at end of file
diff --git a/src/dawn/games/vn/events/VNChoiceSetEvent.hpp b/src/dawn/games/vn/events/VNChoiceSetEvent.hpp
new file mode 100644
index 00000000..e7c488ea
--- /dev/null
+++ b/src/dawn/games/vn/events/VNChoiceSetEvent.hpp
@@ -0,0 +1,21 @@
+// Copyright (c) 2023 Dominic Masters
+//
+// This software is released under the MIT License.
+// https://opensource.org/licenses/MIT
+
+#pragma once
+#include "VNEvent.hpp"
+
+namespace Dawn {
+ class VNChoiceSetEvent : public VNEvent {
+ public:
+ std::string key;
+ std::string value;
+
+ protected:
+ void onStart() override {
+ this->manager->setFlag(this->key, this->value);
+ this->next();
+ }
+ };
+}
\ No newline at end of file
diff --git a/src/dawn/games/vn/events/VNDummyEvent.hpp b/src/dawn/games/vn/events/VNDummyEvent.hpp
index 9a525be1..ba2702df 100644
--- a/src/dawn/games/vn/events/VNDummyEvent.hpp
+++ b/src/dawn/games/vn/events/VNDummyEvent.hpp
@@ -10,7 +10,7 @@ namespace Dawn {
class VNDummyEvent : public VNEvent {
protected:
void onStart() override {
- std::cout << "Test" << std::endl;
+ std::cout << "Dummy VN Event" << std::endl;
this->next();
}
};
diff --git a/src/dawn/games/vn/events/VNIfEvent.hpp b/src/dawn/games/vn/events/VNIfEvent.hpp
new file mode 100644
index 00000000..62aed8e7
--- /dev/null
+++ b/src/dawn/games/vn/events/VNIfEvent.hpp
@@ -0,0 +1,28 @@
+// Copyright (c) 2023 Dominic Masters
+//
+// This software is released under the MIT License.
+// https://opensource.org/licenses/MIT
+
+#pragma once
+#include "VNEvent.hpp"
+
+namespace Dawn {
+ class VNIfEvent : public VNEvent {
+ public:
+ std::string key;
+ std::string value;
+ VNEvent *ifTrue = nullptr;
+
+ VNEvent * getNextEvent() override {
+ if(this->manager.getFlag(key) == value) {
+ return ifTrue;
+ }
+ return VNEvent::getNextEvent();
+ }
+
+ protected:
+ void onStart() override {
+ this->next();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/dawn/games/vn/events/VNTextEvent.hpp b/src/dawn/games/vn/events/VNTextEvent.hpp
index 9171986c..00021a60 100644
--- a/src/dawn/games/vn/events/VNTextEvent.hpp
+++ b/src/dawn/games/vn/events/VNTextEvent.hpp
@@ -14,7 +14,13 @@ namespace Dawn {
protected:
void onStart() override {
std::cout << "TEXT: " << text << std::endl;
- this->next();
+
+ useEvent([&](float_t delta) {
+ if(getScene()->game->inputManager.isPressed(INPUT_BIND_ACCEPT)) {
+ std::cout << "Text Advance" << std::endl;
+ this->next();
+ }
+ }, getScene()->eventSceneUpdate);
}
};
}
\ No newline at end of file
diff --git a/src/dawnliminal/CMakeLists.txt b/src/dawnliminal/CMakeLists.txt
index 8de667f3..b78b1e1c 100644
--- a/src/dawnliminal/CMakeLists.txt
+++ b/src/dawnliminal/CMakeLists.txt
@@ -14,4 +14,8 @@ target_include_directories(${DAWN_TARGET_NAME}
# Subdirs
add_subdirectory(game)
-add_subdirectory(save)
\ No newline at end of file
+add_subdirectory(save)
+
+# Assets
+set(LIMINAL_ASSETS_DIR ${DAWN_ASSETS_DIR}/games/liminal)
+tool_vnscene(${LIMINAL_ASSETS_DIR}/test.xml)
\ No newline at end of file
diff --git a/src/dawnliminal/game/LiminalGame.cpp b/src/dawnliminal/game/LiminalGame.cpp
index 105be5d3..7bec3cab 100644
--- a/src/dawnliminal/game/LiminalGame.cpp
+++ b/src/dawnliminal/game/LiminalGame.cpp
@@ -5,9 +5,11 @@
#include "game/DawnGame.hpp"
#include "scenes/HelloWorldScene.hpp"
+#include "vnscenes/TestScene.hpp"
using namespace Dawn;
Scene * Dawn::dawnGameGetInitialScene(DawnGame *game) {
- return new HelloWorldScene(game);
+ // return new HelloWorldScene(game);
+ return new TestScene(game);
}
\ No newline at end of file
diff --git a/src/dawnliminal/scenes/HelloWorldScene.hpp b/src/dawnliminal/scenes/HelloWorldScene.hpp
index 56000366..14359484 100644
--- a/src/dawnliminal/scenes/HelloWorldScene.hpp
+++ b/src/dawnliminal/scenes/HelloWorldScene.hpp
@@ -12,6 +12,7 @@
#include "games/vn/events/VNTextEvent.hpp"
#include "games/vn/events/VNPositionEvent.hpp"
#include "games/vn/events/VNSetEvent.hpp"
+#include "games/vn/events/VNChoiceEvent.hpp"
namespace Dawn {
class HelloWorldScene : public Scene {
@@ -47,10 +48,19 @@ namespace Dawn {
setPropertyEvent->modifies = &test;
setPropertyEvent->to = 10;
+ auto choiceEvent = vnManager->createEvent();
+ choiceEvent->text = "Choice?";
+ choiceEvent->choices["state0"] = "State 0";
+ choiceEvent->choices["state1"] = "State 1";
+ choiceEvent->choices["state2"] = "State 2";
+ choiceEvent->choices["state3"] = "State 3";
+
+
eventTest
->then(positionEvent)
->then(vnTextEvent)
->then(setPropertyEvent)
+ ->then(choiceEvent)
;
vnManager->setEvent(eventTest);
}
diff --git a/src/dawntools/CMakeLists.txt b/src/dawntools/CMakeLists.txt
index e915ff6b..7f4bff00 100644
--- a/src/dawntools/CMakeLists.txt
+++ b/src/dawntools/CMakeLists.txt
@@ -21,4 +21,4 @@ include(util/CMakeLists.txt)
# Tools
add_subdirectory(prefabtool)
add_subdirectory(texturetool)
-# add_subdirectory(vnscenetool)
\ No newline at end of file
+add_subdirectory(vnscenetool)
\ No newline at end of file
diff --git a/src/dawntools/vnscenetool/CMakeLists.txt b/src/dawntools/vnscenetool/CMakeLists.txt
index 83b8fefd..ff3749d2 100644
--- a/src/dawntools/vnscenetool/CMakeLists.txt
+++ b/src/dawntools/vnscenetool/CMakeLists.txt
@@ -18,6 +18,7 @@ target_sources(vnscenetool
VNSceneTool.cpp
VNSceneParser.cpp
VNSceneEventsParser.cpp
+ VNSceneGen.cpp
)
# Includes
@@ -49,15 +50,15 @@ function(tool_vnscene in)
set(DEPS vnscenetool)
endif()
- STRING(REGEX REPLACE "[\.|\\|\/]" "-" prefab_name ${in})
- add_custom_target(prefab_${prefab_name}
- COMMAND vnscenetool --input="${DAWN_ASSETS_SOURCE_DIR}/${in}"
+ STRING(REGEX REPLACE "[\.|\\|\/]" "-" scene_name ${in})
+ add_custom_target(scene_${scene_name}
+ COMMAND vnscenetool --input="${DAWN_ASSETS_SOURCE_DIR}/${in}" --output="${DAWN_GENERATED_DIR}/generatedscenes"
COMMENT "Generating prefab from ${in}"
DEPENDS ${DEPS}
)
target_include_directories(${DAWN_TARGET_NAME}
PUBLIC
- ${DAWN_GENERATED_DIR}/generatedprefabs
+ ${DAWN_GENERATED_DIR}/generatedscenes
)
- add_dependencies(${DAWN_TARGET_NAME} prefab_${prefab_name})
+ add_dependencies(${DAWN_TARGET_NAME} scene_${scene_name})
endfunction()
\ No newline at end of file
diff --git a/src/dawntools/vnscenetool/VNSceneEventsParser.cpp b/src/dawntools/vnscenetool/VNSceneEventsParser.cpp
index 281a0a6e..154860b4 100644
--- a/src/dawntools/vnscenetool/VNSceneEventsParser.cpp
+++ b/src/dawntools/vnscenetool/VNSceneEventsParser.cpp
@@ -18,7 +18,7 @@ std::map VNSceneEventsParser::getOptionalAttributes()
int32_t VNSceneEventsParser::onParse(
Xml *node,
std::map values,
- struct VNSceneEvent *out,
+ struct VNSceneEventList *out,
std::string *error
) {
int32_t ret;
@@ -26,15 +26,28 @@ int32_t VNSceneEventsParser::onParse(
auto itChildren = node->children.begin();
while(itChildren != node->children.end()) {
Xml *child = *itChildren;
+ struct VNSceneEvent event;
// Parse event(s)
- if(child->node == "position") {
- struct VNPosition position;
- ret = (VNPositionParser()).parse(child, &position, error);
+ if(child->node == "text") {
+ VNTextEventParser parser;
+ event.type = VN_SCENE_EVENT_TYPE_TEXT;
+ ret = (VNTextEventParser()).parse(child, &event.text, error);
if(ret != 0) return ret;
- out->position = position;
+
+ } else if(child->node == "position") {
+ VNPositionEventParser parser;
+ event.type = VN_SCENE_EVENT_TYPE_POSITION;
+ ret = (VNPositionEventParser()).parse(child, &event.position, error);
+ if(ret != 0) return ret;
+
+ } else {
+ *error = "Unknown child node '" + child->node + "'";
+ return -1;
}
+ if(ret != 0) return ret;
+ out->events.push_back(event);
itChildren++;
}
diff --git a/src/dawntools/vnscenetool/VNSceneEventsParser.hpp b/src/dawntools/vnscenetool/VNSceneEventsParser.hpp
index 7c35cc6c..a004c298 100644
--- a/src/dawntools/vnscenetool/VNSceneEventsParser.hpp
+++ b/src/dawntools/vnscenetool/VNSceneEventsParser.hpp
@@ -4,22 +4,34 @@
// https://opensource.org/licenses/MIT
#pragma once
-#include "util/XmlParser.hpp"
-#include "events/VNPositionParser.hpp"
+#include "events/VNTextEventParser.hpp"
+#include "events/VNPositionEventParser.hpp"
namespace Dawn {
- struct VNSceneEvent {
- int32_t bruh;
+ enum VNSceneEventType {
+ VN_SCENE_EVENT_TYPE_TEXT,
+ VN_SCENE_EVENT_TYPE_POSITION
};
- class VNSceneEventsParser : public XmlParser {
+ struct VNSceneEvent {
+ enum VNSceneEventType type;
+
+ struct VNTextEvent text;
+ struct VNPositionEvent position;
+ };
+
+ struct VNSceneEventList {
+ std::vector events;
+ };
+
+ class VNSceneEventsParser : public XmlParser {
protected:
std::vector getRequiredAttributes() override;
std::map getOptionalAttributes() override;
int32_t onParse(
Xml *node,
std::map values,
- struct VNSceneEvent *out,
+ struct VNSceneEventList *out,
std::string *error
) override;
};
diff --git a/src/dawntools/vnscenetool/VNSceneGen.cpp b/src/dawntools/vnscenetool/VNSceneGen.cpp
new file mode 100644
index 00000000..183bf5f6
--- /dev/null
+++ b/src/dawntools/vnscenetool/VNSceneGen.cpp
@@ -0,0 +1,106 @@
+// Copyright (c) 2023 Dominic Masters
+//
+// This software is released under the MIT License.
+// https://opensource.org/licenses/MIT
+
+#include "VNSceneGen.hpp"
+
+using namespace Dawn;
+
+void VNSceneGen::generate(
+ std::vector *out,
+ struct VNScene *scene,
+ std::string tabs
+) {
+ struct ClassGenInfo classInfo;
+ classInfo.clazz = "TestScene";
+ classInfo.extend = "Scene";
+ classInfo.constructorArgs = "DawnGame *game";
+ classInfo.extendArgs = "game";
+
+ classInfo.includes.push_back("scene/Scene.hpp");
+
+ struct MethodGenInfo methodAssets;
+ methodAssets.name = "getRequiredAssets";
+ methodAssets.isOverride = true;
+ methodAssets.type = "std::vector";
+ line(&methodAssets.body, "auto assMan = &this->game->assetManager;", "");
+ line(&methodAssets.body, "std::vector assets;", "");
+ line(&methodAssets.body, "return assets;", "");
+
+ struct MethodGenInfo methodStage;
+ methodStage.name = "stage";
+ methodStage.isOverride = "true";
+ line(&methodStage.body, "// test", "");
+
+ // TEST
+ line(&methodStage.body, "auto canvas = UICanvas::create(this);", "");
+ line(&methodStage.body, "", "");
+
+ classInfo.includes.push_back("scene/components/display/Camera.hpp");
+ line(&methodStage.body, "auto camera = Camera::create(this);", "");
+ line(&methodStage.body, "camera->fov = 0.436332f;", "");
+ line(&methodStage.body, "camera->transform->lookAt(glm::vec3(10, 10, 10), glm::vec3(0, 0, 0));", "");
+ line(&methodStage.body, "", "");
+
+ classInfo.includes.push_back("prefabs/SimpleSpinningCubePrefab.hpp");
+ line(&methodStage.body, "auto cube = SimpleSpinningCubePrefab::create(this);", "");
+ line(&methodStage.body, "", "");
+
+ // Events
+ classInfo.includes.push_back("games/vn/components/VNManager.hpp");
+ line(&methodStage.body, "auto vnItem = this->createSceneItem();", "");
+ line(&methodStage.body, "auto vnManager = vnItem->addComponent();", "");
+ line(&methodStage.body, "VNEvent *previous = vnManager->createEvent();", "");
+ line(&methodStage.body, "auto eventStart = previous;", "");
+
+ int32_t eventIndex = 0;
+ auto itEvents = scene->events.events.begin();
+ while(itEvents != scene->events.events.end()) {
+ std::string eventName = "event" + std::to_string(eventIndex);
+ std::string initType = "";
+ std::string initArgs = "";
+ std::string prev = "previous";
+ std::vector afterLines;
+
+ switch(itEvents->type) {
+ case VN_SCENE_EVENT_TYPE_TEXT:
+ initType = "VNTextEvent";
+ line(&afterLines, eventName + "->" + "text = \"" + itEvents->text.texts.begin()->text + "\";", "");
+ break;
+
+ case VN_SCENE_EVENT_TYPE_POSITION:
+ initType = "VNPositionEvent";
+ line(&afterLines, eventName + "->item = " + itEvents->position.item + ";", "");
+ if(itEvents->position.x != "") line(&afterLines, eventName + "->" + "to.x = " + itEvents->position.x + ";", "");
+ if(itEvents->position.y != "") line(&afterLines, eventName + "->" + "to.y = " + itEvents->position.y + ";", "");
+ if(itEvents->position.z != "") line(&afterLines, eventName + "->" + "to.z = " + itEvents->position.z + ";", "");
+ break;
+
+ default:
+ assertUnreachable();
+ }
+
+ line(&methodStage.body, "", "");
+ line(
+ &methodStage.body,
+ "auto " + eventName + " = " + prev + "->then(vnManager->createEvent<" + initType + ">(" + initArgs + "));",
+ ""
+ );
+ line(&methodStage.body, "previous = " + eventName + ";", "");
+ lines(&methodStage.body, afterLines, "");
+
+ eventIndex++;
+ ++itEvents;
+ }
+
+ line(&methodStage.body, "", "");
+ line(&methodStage.body, "vnManager->setEvent(eventStart);", "");
+
+ // Add in methods
+ CodeGen::methodGen(&classInfo.protectedCode, methodAssets);
+ line(&classInfo.protectedCode, "", "");
+ CodeGen::methodGen(&classInfo.protectedCode, methodStage);
+
+ CodeGen::classGen(out, classInfo);
+}
\ No newline at end of file
diff --git a/src/dawntools/vnscenetool/VNSceneGen.hpp b/src/dawntools/vnscenetool/VNSceneGen.hpp
new file mode 100644
index 00000000..8a704b89
--- /dev/null
+++ b/src/dawntools/vnscenetool/VNSceneGen.hpp
@@ -0,0 +1,19 @@
+// Copyright (c) 2023 Dominic Masters
+//
+// This software is released under the MIT License.
+// https://opensource.org/licenses/MIT
+
+#pragma once
+#include "VNSceneParser.hpp"
+#include "util/CodeGen.hpp"
+
+namespace Dawn {
+ class VNSceneGen : public CodeGen {
+ public:
+ static void generate(
+ std::vector *out,
+ struct VNScene *scene,
+ std::string tabs
+ );
+ };
+}
\ No newline at end of file
diff --git a/src/dawntools/vnscenetool/VNSceneParser.cpp b/src/dawntools/vnscenetool/VNSceneParser.cpp
index 16c901ca..dd77240d 100644
--- a/src/dawntools/vnscenetool/VNSceneParser.cpp
+++ b/src/dawntools/vnscenetool/VNSceneParser.cpp
@@ -30,13 +30,9 @@ int32_t VNSceneParser::onParse(
// Parse event(s)
if(child->node == "events") {
- struct VNSceneEvent scene;
- ret = (VNSceneEventsParser()).parse(child, &scene, error);
+ ret = (VNSceneEventsParser()).parse(child, &out->events, error);
if(ret != 0) return ret;
- out->events.push_back(scene);
}
-
-
itChildren++;
}
diff --git a/src/dawntools/vnscenetool/VNSceneParser.hpp b/src/dawntools/vnscenetool/VNSceneParser.hpp
index e4140ac3..49bd3c5c 100644
--- a/src/dawntools/vnscenetool/VNSceneParser.hpp
+++ b/src/dawntools/vnscenetool/VNSceneParser.hpp
@@ -8,7 +8,7 @@
namespace Dawn {
struct VNScene {
- std::vector events;
+ struct VNSceneEventList events;
};
class VNSceneParser : public XmlParser {
diff --git a/src/dawntools/vnscenetool/VNSceneTool.cpp b/src/dawntools/vnscenetool/VNSceneTool.cpp
index 79f9a69b..0f287b9c 100644
--- a/src/dawntools/vnscenetool/VNSceneTool.cpp
+++ b/src/dawntools/vnscenetool/VNSceneTool.cpp
@@ -8,7 +8,7 @@
using namespace Dawn;
std::vector VNSceneTool::getRequiredFlags() {
- return { "input" };
+ return { "input", "output" };
}
std::map VNSceneTool::getOptionalFlags() {
@@ -38,6 +38,28 @@ int32_t VNSceneTool::start() {
}
// Generate output
+ std::vector outputData;
+ VNSceneGen::generate(&outputData, &scene, "");
+
+ // Load output file from name and type
+ File outputFile = File(flags["output"] + "/vnscenes/TestScene.hpp");
+ if(!outputFile.mkdirp()) {
+ std::cout << "Failed to create output directory!" << std::endl;
+ return 1;
+ }
+
+ // Combine vector into single string
+ std::string outputDataStr = "";
+ auto it = outputData.begin();
+ while(it != outputData.end()) {
+ outputDataStr += *it + "\n";
+ ++it;
+ }
+
+ if(!outputFile.writeString(outputDataStr)) {
+ std::cout << "Failed to write output file!" << std::endl;
+ return 1;
+ }
return 0;
}
\ No newline at end of file
diff --git a/src/dawntools/vnscenetool/VNSceneTool.hpp b/src/dawntools/vnscenetool/VNSceneTool.hpp
index b6da5ec1..5b7d12f4 100644
--- a/src/dawntools/vnscenetool/VNSceneTool.hpp
+++ b/src/dawntools/vnscenetool/VNSceneTool.hpp
@@ -6,6 +6,7 @@
#pragma once
#include "util/DawnTool.hpp"
#include "VNSceneParser.hpp"
+#include "VNSceneGen.hpp"
#include "util/File.hpp"
namespace Dawn {
diff --git a/src/dawntools/vnscenetool/events/CMakeLists.txt b/src/dawntools/vnscenetool/events/CMakeLists.txt
index 825fa31d..aa7a159b 100644
--- a/src/dawntools/vnscenetool/events/CMakeLists.txt
+++ b/src/dawntools/vnscenetool/events/CMakeLists.txt
@@ -6,5 +6,6 @@
# Sources
target_sources(vnscenetool
PRIVATE
- VNPositionParser.cpp
+ VNPositionEventParser.cpp
+ VNTextEventParser.cpp
)
\ No newline at end of file
diff --git a/src/dawntools/vnscenetool/events/VNPositionEventParser.cpp b/src/dawntools/vnscenetool/events/VNPositionEventParser.cpp
new file mode 100644
index 00000000..e43eaafb
--- /dev/null
+++ b/src/dawntools/vnscenetool/events/VNPositionEventParser.cpp
@@ -0,0 +1,33 @@
+// Copyright (c) 2023 Dominic Masters
+//
+// This software is released under the MIT License.
+// https://opensource.org/licenses/MIT
+
+#include "VNPositionEventParser.hpp"
+
+using namespace Dawn;
+
+std::vector VNPositionEventParser::getRequiredAttributes() {
+ return { "item" };
+}
+
+std::map VNPositionEventParser::getOptionalAttributes() {
+ return {
+ { "x", "" },
+ { "y", "" },
+ { "z", "" }
+ };
+}
+
+int32_t VNPositionEventParser::onParse(
+ Xml *node,
+ std::map values,
+ struct VNPositionEvent *out,
+ std::string *error
+) {
+ out->x = values["x"];
+ out->y = values["y"];
+ out->z = values["z"];
+ out->item = values["item"];
+ return 0;
+}
\ No newline at end of file
diff --git a/src/dawntools/vnscenetool/events/VNPositionEventParser.hpp b/src/dawntools/vnscenetool/events/VNPositionEventParser.hpp
new file mode 100644
index 00000000..a670ed0c
--- /dev/null
+++ b/src/dawntools/vnscenetool/events/VNPositionEventParser.hpp
@@ -0,0 +1,28 @@
+// Copyright (c) 2023 Dominic Masters
+//
+// This software is released under the MIT License.
+// https://opensource.org/licenses/MIT
+
+#pragma once
+#include "util/XmlParser.hpp"
+
+namespace Dawn {
+ struct VNPositionEvent {
+ std::string x = "";
+ std::string y = "";
+ std::string z = "";
+ std::string item = "";
+ };
+
+ class VNPositionEventParser : public XmlParser {
+ protected:
+ std::vector getRequiredAttributes() override;
+ std::map getOptionalAttributes() override;
+ int32_t onParse(
+ Xml *node,
+ std::map values,
+ struct VNPositionEvent *out,
+ std::string *error
+ ) override;
+ };
+}
\ No newline at end of file
diff --git a/src/dawntools/vnscenetool/events/VNPositionParser.cpp b/src/dawntools/vnscenetool/events/VNPositionParser.cpp
deleted file mode 100644
index 380abc39..00000000
--- a/src/dawntools/vnscenetool/events/VNPositionParser.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2023 Dominic Masters
-//
-// This software is released under the MIT License.
-// https://opensource.org/licenses/MIT
-
-#include "VNPositionParser.hpp"
-
-using namespace Dawn;
-
-std::vector VNPositionParser::getRequiredAttributes() {
- return { };
-}
-
-std::map VNPositionParser::getOptionalAttributes() {
- return { };
-}
-
-int32_t VNPositionParser::onParse(
- Xml *node,
- std::map values,
- struct VNPosition *out,
- std::string *error
-) {
- return 0;
-}
\ No newline at end of file
diff --git a/src/dawntools/vnscenetool/events/VNPositionParser.hpp b/src/dawntools/vnscenetool/events/VNPositionParser.hpp
deleted file mode 100644
index 55bff476..00000000
--- a/src/dawntools/vnscenetool/events/VNPositionParser.hpp
+++ /dev/null
@@ -1,6 +0,0 @@
-// Copyright (c) 2023 Dominic Masters
-//
-// This software is released under the MIT License.
-// https://opensource.org/licenses/MIT
-
-#pragma once
diff --git a/src/dawntools/vnscenetool/events/VNTextEventParser.cpp b/src/dawntools/vnscenetool/events/VNTextEventParser.cpp
new file mode 100644
index 00000000..65d79ad3
--- /dev/null
+++ b/src/dawntools/vnscenetool/events/VNTextEventParser.cpp
@@ -0,0 +1,43 @@
+// Copyright (c) 2023 Dominic Masters
+//
+// This software is released under the MIT License.
+// https://opensource.org/licenses/MIT
+
+#include "VNTextEventParser.hpp"
+
+using namespace Dawn;
+
+std::vector VNTextEventParser::getRequiredAttributes() {
+ return { };
+}
+
+std::map VNTextEventParser::getOptionalAttributes() {
+ return { };
+}
+
+int32_t VNTextEventParser::onParse(
+ Xml *node,
+ std::map values,
+ struct VNTextEvent *out,
+ std::string *error
+) {
+ auto itChildren = node->children.begin();
+ while(itChildren != node->children.end()) {
+ Xml *child = *itChildren;
+
+ // Parse strings
+ if(child->node == "string") {
+ VNText text;
+ text.language = child->attributes["lang"];
+ text.text = child->value;
+ out->texts.push_back(text);
+ } else {
+ *error = "Unknown child node '" + child->node + "'";
+ return -1;
+ }
+
+ itChildren++;
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/src/dawntools/vnscenetool/events/VNTextEventParser.hpp b/src/dawntools/vnscenetool/events/VNTextEventParser.hpp
new file mode 100644
index 00000000..d351896b
--- /dev/null
+++ b/src/dawntools/vnscenetool/events/VNTextEventParser.hpp
@@ -0,0 +1,30 @@
+// Copyright (c) 2023 Dominic Masters
+//
+// This software is released under the MIT License.
+// https://opensource.org/licenses/MIT
+
+#pragma once
+#include "util/XmlParser.hpp"
+
+namespace Dawn {
+ struct VNText {
+ std::string language;
+ std::string text;
+ };
+
+ struct VNTextEvent {
+ std::vector texts;
+ };
+
+ class VNTextEventParser : public XmlParser {
+ protected:
+ std::vector getRequiredAttributes() override;
+ std::map getOptionalAttributes() override;
+ int32_t onParse(
+ Xml *node,
+ std::map values,
+ struct VNTextEvent *out,
+ std::string *error
+ ) override;
+ };
+}
\ No newline at end of file