aboutsummaryrefslogtreecommitdiff
path: root/frontend
diff options
context:
space:
mode:
Diffstat (limited to 'frontend')
-rw-r--r--frontend/CMakeLists.txt3
-rw-r--r--frontend/Exception.cpp30
-rw-r--r--frontend/Exception.h17
-rw-r--r--frontend/cmd/view.cpp9
-rw-r--r--frontend/generate_dungeon.cpp55
-rw-r--r--frontend/generate_dungeon.h8
-rw-r--r--frontend/load_dungeon.cpp78
-rw-r--r--frontend/load_dungeon.h8
-rw-r--r--frontend/main.cpp32
9 files changed, 229 insertions, 11 deletions
diff --git a/frontend/CMakeLists.txt b/frontend/CMakeLists.txt
index ef64ee2..60b830c 100644
--- a/frontend/CMakeLists.txt
+++ b/frontend/CMakeLists.txt
@@ -4,6 +4,9 @@ target_sources(main PUBLIC
strings.cpp
print.cpp
Player.cpp
+ load_dungeon.cpp
+ generate_dungeon.cpp
+ Exception.cpp
)
add_subdirectory(cmd)
diff --git a/frontend/Exception.cpp b/frontend/Exception.cpp
new file mode 100644
index 0000000..423f4e9
--- /dev/null
+++ b/frontend/Exception.cpp
@@ -0,0 +1,30 @@
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+
+#include "Exception.h"
+
+using namespace std;
+
+const char * Exception::what() {
+ return error.get();
+}
+
+void Exception::va_format(va_list args, const char * fmt) {
+ va_list args_copy;
+ va_copy(args_copy, args);
+ size_t sz = vsnprintf(NULL, 0, fmt, args_copy) + 1;
+ va_end(args_copy);
+
+ this->error = unique_ptr<char>(static_cast<char *>(malloc(sz)));
+
+ vsnprintf(this->error.get(), sz, fmt, args);
+}
+
+Exception::Exception(const char * fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ va_format(args, fmt);
+ va_end(args);
+}
+
diff --git a/frontend/Exception.h b/frontend/Exception.h
new file mode 100644
index 0000000..633cb4f
--- /dev/null
+++ b/frontend/Exception.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include <cstdarg>
+#include <exception>
+#include <memory>
+
+class Exception : public std::exception {
+public:
+ Exception(const char * fmt, ...);
+ const char * what();
+
+protected:
+ Exception() = default;
+ void va_format(va_list args, const char * fmt);
+ std::unique_ptr<char> error = NULL;
+};
+
diff --git a/frontend/cmd/view.cpp b/frontend/cmd/view.cpp
index 8b08a2c..7998a4a 100644
--- a/frontend/cmd/view.cpp
+++ b/frontend/cmd/view.cpp
@@ -7,6 +7,15 @@ FollowupAction Player::cmd_view(Argv argv) {
return FollowupAction::NONE;
}
+ if (argv[0] == "Zelf") {
+ lprtf("Je hebt %d levenspunten.\n", this->health_points);
+ lprtf("Je hebt een aanvalskans van %.0f%%.\n", this->attack_chance * 100);
+ // TODO: weapon
+ // TODO: armor
+ // TODO: gold
+ // TODO: inventory
+ }
+
return FollowupAction::NONE;
}
diff --git a/frontend/generate_dungeon.cpp b/frontend/generate_dungeon.cpp
new file mode 100644
index 0000000..c6ddcbf
--- /dev/null
+++ b/frontend/generate_dungeon.cpp
@@ -0,0 +1,55 @@
+#include <memory>
+#include <functional>
+#include <sqlite3.h>
+
+#include "backend/Dungeon.h"
+
+#include "generate_dungeon.h"
+#include "Exception.h"
+
+using namespace std;
+
+class DB {
+ typedef unique_ptr<sqlite3, function<void(sqlite3*)>> unique_sqlite3;
+ typedef unique_ptr<sqlite3_stmt, function<void(sqlite3_stmt*)>> unique_sqlite3_stmt;
+
+public:
+ DB(const string & path) {
+ sqlite3 * db = NULL;
+ int ret = sqlite3_open_v2(path.c_str(), &db, SQLITE_OPEN_READONLY, NULL);
+ this->db = {
+ db,
+ [] (sqlite3 * db) {
+ sqlite3_close_v2(db);
+ },
+ };
+ if (ret != SQLITE_OK)
+ throw Exception("sqlite3_open_v2");
+ }
+
+ unique_sqlite3_stmt prepare(const string & query) {
+ sqlite3_stmt * stmt = NULL;
+ int ret = sqlite3_prepare_v2(this->db.get(), query.c_str(), query.size(), &stmt, NULL);
+ unique_sqlite3_stmt uniq_stmt = {
+ stmt,
+ [] (sqlite3_stmt * stmt) {
+ sqlite3_finalize(stmt);
+ },
+ };
+ if (ret != SQLITE_OK)
+ throw Exception("sqlite3_prepare_v2");
+ return uniq_stmt;
+ }
+
+private:
+ unique_sqlite3 db = NULL;
+};
+
+unique_ptr<Dungeon> generate_dungeon() {
+ unique_ptr<Dungeon> dungeon = make_unique<Dungeon>();
+
+ DB db { "kerkersendraken.db" };
+
+ return dungeon;
+}
+
diff --git a/frontend/generate_dungeon.h b/frontend/generate_dungeon.h
new file mode 100644
index 0000000..6252c83
--- /dev/null
+++ b/frontend/generate_dungeon.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#include <memory>
+
+class Dungeon;
+
+std::unique_ptr<Dungeon> generate_dungeon();
+
diff --git a/frontend/load_dungeon.cpp b/frontend/load_dungeon.cpp
new file mode 100644
index 0000000..ef8cb54
--- /dev/null
+++ b/frontend/load_dungeon.cpp
@@ -0,0 +1,78 @@
+#include <memory>
+#include <filesystem>
+#include <pugixml.hpp>
+#include <map>
+
+#include "backend/Location.h"
+#include "backend/LocationFactory.h"
+#include "backend/Dungeon.h"
+
+#include "load_dungeon.h"
+#include "Exception.h"
+#include "frontend/strings.h"
+
+using namespace std;
+using namespace pugi;
+
+unique_ptr<Dungeon> load_dungeon(const string & filename) {
+ unique_ptr<Dungeon> dungeon = make_unique<Dungeon>();
+
+ xml_document doc;
+
+ string canonical = filename;
+ if (canonical.starts_with("~/"))
+ canonical = getenv("HOME") + canonical.substr(1);
+ try {
+ canonical = filesystem::canonical(canonical);
+ } catch (...) {
+ throw Exception("Kon bestand niet vinden");
+ }
+
+ xml_parse_result result = doc.load_file(canonical.c_str());
+ if (!result)
+ throw Exception("Kon XML-bestand niet lezen");
+
+ xml_node locations = doc.child("locaties");
+ if (!locations)
+ throw Exception("XML-bestand mist een <locaties> tag");
+
+ LocationFactory factory;
+ struct TempData {
+ Location * location;
+ unsigned edges[4];
+ };
+ map<unsigned, TempData> temp_map;
+ for (xml_node & tag : locations) {
+ const char * name = tag.text().as_string();
+ const char * description = tag.child("beschrijving").text().as_string();
+
+ // vector<string> objects_hidden = split_string(tag.attribute("objectenverborgen").as_string(), ";");
+ // vector<string> objects_visible = split_string(tag.attribute("objectenzichtbaar").as_string(), ";");
+ // vector<string> enemies = split_string(tag.attribute("vijand").as_string(), ";");
+
+ Location * location = factory.create_location(name, description);
+ temp_map[tag.attribute("id").as_uint()] = {
+ .location = location,
+ .edges = {
+ tag.attribute("noord").as_uint(0),
+ tag.attribute("oost").as_uint(0),
+ tag.attribute("zuid").as_uint(0),
+ tag.attribute("west").as_uint(0),
+ },
+ };
+ dungeon->add_location(location);
+ }
+
+ // connect edges after creating all locations
+ for (auto & [here, temp] : temp_map) {
+ for (Direction direction : { NORTH, EAST, SOUTH, WEST }) {
+ unsigned there = temp.edges[direction];
+ if (temp.edges[direction] == 0) continue;
+ if (!temp_map.contains(there)) continue;
+ temp.location->set_exit(direction, temp_map[there].location);
+ }
+ }
+
+ return dungeon;
+}
+
diff --git a/frontend/load_dungeon.h b/frontend/load_dungeon.h
new file mode 100644
index 0000000..4eff4cf
--- /dev/null
+++ b/frontend/load_dungeon.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#include <memory>
+
+class Dungeon;
+
+std::unique_ptr<Dungeon> load_dungeon(const std::string & filename);
+
diff --git a/frontend/main.cpp b/frontend/main.cpp
index b9322ee..c421d9e 100644
--- a/frontend/main.cpp
+++ b/frontend/main.cpp
@@ -3,25 +3,35 @@
#include <memory>
#include "backend/Dungeon.h"
-#include "Player.h"
+#include "Player.h"
+#include "Exception.h"
+#include "frontend/print.h"
+#include "load_dungeon.h"
+#include "generate_dungeon.h"
#include "rl.h"
#include "strings.h"
-#include "print.h"
using namespace std;
-FollowupAction game_main() {
- auto dungeon = make_unique<Dungeon>();
-
- print_string(strings::INTRO);
- string filename = rl();
- if (filename.size() == 0) {
- lprtf("TODO: generate dungeon\n");
- } else {
- lprtf("TODO: load %s\n", filename.c_str());
+static unique_ptr<Dungeon> make_dungeon() noexcept {
+ while (1) {
+ print_string(strings::INTRO);
+ string filename = rl();
+ try {
+ if (filename.size() == 0) {
+ return generate_dungeon();
+ } else {
+ return load_dungeon(filename);
+ }
+ } catch (Exception & e) {
+ lprtf("FOUT: %s\n", e.what());
+ }
}
+}
+FollowupAction game_main() {
+ unique_ptr<Dungeon> dungeon = make_dungeon();
Player player { *dungeon };
while (1) {